0% found this document useful (0 votes)
79 views174 pages

Amiga Machine Language Guide

This document provides an introduction to machine language programming on the Amiga computer. It discusses why machine language is used, the components of the Amiga's memory including RAM, ROM, and hardware registers. It also explains basic concepts like bits, bytes, words, and number systems including binary, octal, hexadecimal. The document outlines the components of the Amiga operating system and MC68000 processor that are important for machine language programming.

Uploaded by

Milan Zaninović
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
79 views174 pages

Amiga Machine Language Guide

This document provides an introduction to machine language programming on the Amiga computer. It discusses why machine language is used, the components of the Amiga's memory including RAM, ROM, and hardware registers. It also explains basic concepts like bits, bytes, words, and number systems including binary, octal, hexadecimal. The document outlines the components of the Amiga operating system and MC68000 processor that are important for machine language programming.

Uploaded by

Milan Zaninović
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

AMIGA MACHINE LANGUAGE

Typed by DEE JAY

Table of Contents.
------------------
1. Introduction
1.1 Why machine code?
1.2 A look into the Amiga's memory
1.2.1 RAM,ROM,hardware register
1.2.2 Bits,bytes and words
1.2.3 Number systems
1.3 Inside the Amiga
1.3.1 Components and libraries
1.3.2 Memory
1.3.3 Multi-tasking

2 The MC68000 processor


2.1 Registers
2.2 Addressing memory
2.3 Operating modes
2.3.1 User and supervisor modes
2.3.2 Exceptions
2.3.3 Interrupts
2.3.4 Condition codes
2.4 The 68000 Instructions

3 Working with assemblers


3.1 The development assembler
3.2 AssemPro
3.3 The K-SEKA assembler

4 Our first programs


4.1 Adding tables
4.2 Sorting tables
4.3 Converting number systems
4.3.1 Converting hex to ASCII
4.3.2 Converting decimal to ASCII
4.3.3 Converting ASCII to hex
4.3.4 Converting ASCII to decimal

5 Hardware registers
5.1 Checking for special keys
5.2 Timing
5.3 Reading the mouse or joystick
5.4 Tone production
5.5 Hardware registers overview

6 The Amiga operating system


6.1 Load libraries
6.2 Calling functions
6.3 Program initialization
6.3.1 Reserve memory
6.3.2 Opening a simple window
6.4 Input/output
6.4.1 Screen output
6.4.2 Keyboard input
6.4.3 Printer control
6.4.4 Serial I/O
6.4.5 Speech output
6.5 Disk operations
6.5.1 Open files
6.5.2 Reading and writing data
6.5.3 Erase files
6.5.4 Rename files
6.5.5 CLI directory
6.5.6 Read directory
6.5.7 Direct access to disk

7 Working with Intuition


7.1 Open screen
7.2 Openwindow
7.3 Requesters
7.4 Event handling
7.5 Menu programming
7.6 Text output
7.7 Images
7.8 Borders
7.9 Gadgets
7.9.1 Boolean gadgets
7.9.2 String gadgets
7.9.3 Proportional gadgets
7.10 Example program

8 Advanced programming
8.1 Supervisor mode
8.2 Exception programming

Appendix
Overview of library functions
Overview of the MC68000 Instructions

CHAPTER 1
---------
[Link].
--------------
Before you tackle machine language,you should take a closer
look at several things that are vital to machine language
programming.

[Link] Machine Language.


------------------------
Machine language is actually the only language the MC68000
processor [Link] other languages,such as Basic,Pascal
or C,must first be translated(interpreted or compiled) into
machine [Link] process can take place either when the
program is executed(the BASIC interpreter),or before program
execution(the Pascal and C compilers).
Advantages;
The great advantage of machine language over an interpreted
and compiled program is machine language programs are faster.
With an interpreter like BASIC,each line must first be
interpreted before it is executed,which requires a great deal
of time.A Pascal or C compiler translates the source into
machine [Link] translation procedure does not produce
programs that are as fast as pure machine language programs.
Another advantage machine language has over BASIC is that an
interpreter is not needed for the execution of a machine
language program.
Machine language can access all the capabilities of the
computor since it is the language native to the [Link]
is possible that machine subroutines are required by a higher
level language to access functions that aren't directly
accessible by that language.

1.2.A Look Into The Amiga's Memory.


----------------------------------
Before a machine language program can be written,you must
know exactly what the program is required to [Link] must also
be aware of what resources are needed and available to achieve
those [Link] most important of these resources is the
memory in the Amiga.

[Link],ROM,Hardware Register.
-------------------------------
Random Access Memory,referred to as RAM,allows information to
be placed in it and then withdrawn at a later [Link] memory
consists of electronic componants that retain data only while
the computor is turned on(or until power failure).
So that the computor is able to do something when it is first
turned on,such as promting the Workbench or Kickstart disk,a
program has to remain in memory when the power is off.A memory
type which can retain data in memory without any power being
[Link] second memory type is known as ROM.
ROM;
ROM stands for Read Only Memory,indicating that data can only
be read from this memory,not written to [Link] Amiga contains
a ROM,that loads the Workbench or Kickstart disk into [Link]
first version of the Amiga did not contain the Kickstart in
ROM.
PROM;
One variation of ROM is the PROM,or Programmable Read Only
[Link] special type of ROM can actually be programmed
[Link] it cannot be erased once programmed,it isn't
encountered very [Link] often you will see EPROM's. or
Erasable Programmable ROM'[Link] special chips,which can be
erased with ultraviolet light,have a little window on the
surface of the chip usually covered with tape.
EEROM;
Although not available on the consumer market and much more
expensive than RAM,the EEROM(Electically Erasable ROM) offers
another alternative to programmable [Link] chips function
like RAM,except that information is not lost when the power
is turned off.
WOM;
With the birth of the Amiga,another type of memory,WOM,was
[Link] particular type of memory is Write Once Memory.
The Kickstart disk is read into this memory when the computor
is first [Link] this,no more data can be read into that
[Link] this isn't a completely new component,but
simply RAM that is locked once data has been read into it,
after which the data can only be read from that memory.
Registers;
In addition to RAM and these variations of ROM there is another
type of memory situated between those two [Link] memory
is connected to the processor through a group of peripheral
[Link] it is commonly refered to as the Hardware
Register,since the computor's hardware is managed by this
[Link]'ll go into greater detail on how to use these hardware
registers later in this book.
Lets take a closer look at the structure and use of the memory
most familiar to us,RAM.

[Link],Bytes,and Words.
--------------------------
Kilobyte;
The standard size in which memory is measured is a Kilobyte
(Kbyte).One kilobyte consists of 1024 bytes,not 1000 as you
might [Link] unusual system stems from the computor's
binary mode of operation,where numbers are given as powers of
2,including kilobytes.
To access a memory block of one kilobyte,the processor requires
10 connections which carry either one volt or zero [Link]
2^10=1024 combinations or 1024 bytes of memory,are possible.
Byte;
A byte,in turn,consists of yes/no,on/off information as well.
A byte can be one of 2^8 different values,and thus it can
represent any one of 256 [Link] individual numerical
values that make up a byte,which also are the smallest and
most basic unit encountered in any computor,are called bits
(short for binary coded digit).
A 512 kbyte memory,such as the Amiga's,contains 2^19=524288
bytes and 4194304 [Link] may seem unimaginable,but a memory
of that size has 2^4194300 different combinations.
Word;
Back to the basics...bits and bytes are sufficent to program
an eight bit processor like the 6500,since it can only work
with [Link] program a 16/32 bit processor like the Amiga's
MC68000,you'll need to know two new data forms:words,consisting
of 16 bits(the equivalent of two bytes),and long words,which
are 32 bits(the equivalent of four bytes,or 2 words).
A word can be any number between 0 and 65536,a long word can
0 to [Link] MC68000 processor can process these
gigantic numbers with a single operation.
Once in a while you need to use negative numbers as well as
positive [Link] a bit can only be 1 or 0 and not -1,an
alternative system has been [Link] a word is to have a
specific sign,the highest value digit or 15th bit in the word
(positions are always counted from zero) determines the sign
of the [Link] this method words can carry values from -32768
to +[Link] byte can range from -127 to +[Link] a byte,the
value -1 is given by $FF; in a word it's $FFFF,-2 is $FE(FFFE),
etc.
Lets stick with positive values for the time being,to aid in
the visualization of a bit in relation to its bit pattern.
Machine language does not use the familiar decimal system.
Instead,it commonly employs the binary as well as the octal and
hexadecimal number systems.

[Link] Systems.
--------------------
Lets take a look at the decimal system:its base number is 10.
This means that every digit represents a power of [Link] means
that the 246 represents 2*10^2+4*10^1+6*10^[Link] decimal system
offers a selection of 10 characters,namely 0-9.
Binary;
This procedure is different for the binary [Link] binary
system offers only two different characters:1 and [Link] the
systems base number is [Link] decimal value of 1010 would be:
1*2^3+0*2^2+1*2^1+0*2^0=2^3+2^1=8+2=10 (in decimal system)
Generally binary numbers are identified by having a percentage
symbol as a [Link] if you can determine the decimal value of
this number:110010...
Well did you get 50?.Thats the right [Link] most simple
method to arrive at this result is to simply add up the values
of the digits contained at [Link] values of the first eight digits
are as follows:
digit 8 7 6 5 4 3 2 1
value 128 64 32 16 8 4 2 1
Octal;
The octal system whose base is eight,is [Link] character set
consists of numbers 0 to [Link] decimal equivalent of the octal
number 31 is: 3*8^1+1*8^0=[Link] the octal system isn't
nearly as important as the next one...
The base number of the hexadecimal system is 16,and its character
set ranges from 0 to [Link],A would be equivalent of a decimal 10
and F would be [Link] dollar sign($) indicates a hexadecimal
[Link] binary and hexadecimal systems are the most important
numerical systems for assembly language programming.
Hex;
The hexadecimal representation of a byte ranging from 0 to 256
always has two digits:$00 to $FF.A word ranges from $0000 to $FFFF
and a longword from $00000000 to $FFFFFFFF.
Its quite easy to convert binary numbers into hexadecimal:simply
split up the binary numbers into groups of four [Link] of
these groups of four digits then corresponds to one hexadecimal
[Link] an example:
binary number %110011101111
split up %1100 %1110 %1111
result $C $E $F
thus: %110011101111=$CEF
The opposite operation is just as easy...
hexadecimal $E30D
split up $E $3 $0 $D
result %1110 %0011 %0000 %1101
thus: $E30D = %1110001100001101
This method can also be used to convert binary into octal and vice
versa,except that groups of three digits are used in that case:
octal number 7531
split up 7 5 3 1
result %111 %100 %011 %001
thus: octal 7531=%111101011001
This binary number can the be converted into hexadecimal,as well:
binary number %111101011001
split up %1111 %0101 %1001
result $F $5 $9
thus: octal 7531=$F59
The following calculation can then be used to convert the number
into the familiar decimal system:
hexadecimal $F59
split up $F $5 $9
result 15*16^2+5*16+9
thus: $F59=3929 decimal
Although this conversions are quite simple ,they can get to be
rather [Link] assemblers can ease this task somewhat:they
allow you to enter a value with '?'upon which it returns the
value in decimal and hexadecimal [Link] are even calculators
that perform number base conversions.
Often this conversion as to be performed in a program,for instance
when a number is entered by the user and then processed by the
[Link] this case the number entered,being simply a
combination of graphic symbols,is evaluated and the usually
converted into a binary number,in effect,a word or a longword.
This process is often required in reverse order,as [Link] the
computor is to display a calculated value in a specific number
system,it must first convert that number into a series of
[Link] a later chapter you will develop machine language
routines to solve these [Link] can then use these routines
in your own [Link] you still have to cover some things
that are fundamental to machine language programming on the Amiga.

[Link] the Amiga.


--------------------
In order to program machine language,it is not sufficent to know
only the commands of the particular processor,one must also have
extensive knowledge of the Amiga being [Link] take a
look inside the Amiga.

[Link] and Libraries.


------------------------------
The Amiga is a very capable machine,due to the fact that there
are components that do a large part of the workload,freeing up
the 68000 [Link] are refered to as the"custom"chips,
which perform various tasks independantly of the 68000 processor.
Custom Chips;
This task force is comprised of three chips,whose poetic names
are Agnus,Denice,and [Link] main task of Agnus,alias blitter,
is the shifting of memory blocks,which is helpful for operations
such as quick screen [Link] is responsible for transfering
the computors thoughts on to the [Link]'s tasks consist of
input/output jobs,such as disk operation or sound.
These chips are accessed by the processor through several adresses
starting at $DFF000,which are also known as the hardware registers
(you'll find more detailed information about the registers in the
corresponding chapter).To simplify the otherwise complicated
procedure of utilizing these chips,several programs have been
included in the Kickstart and Workbench [Link] programs
can be called by simple routines and then take over the respective
chips.
If only these library functions are used to program the Amiga,the
parameters are the same,regardless of the language [Link] the
parameter notations differs from language to [Link] is an
exception in this respect,since its interpreter translates the
program calls,which is why you don't need to know how the Amiga
executes these functions in order to use them.
The library functions are written in machine language and are thus
closely related with your own machine language [Link]
you could do without the library programs and write all of the
functions [Link] the incredible workload of this task is
so discouraging,that you'd rather stick with the library functions
[Link].
------------
First lets look at the RAM of the Amiga [Link] standard version
of this computor has over 512 kbytes of RAM,ranging from the
address $00000 to $7FFFF,or 0 to [Link] the memory is expanded
to one megabyte,the first address still starts at $00000,however
the start of anything greater than 512k can go anywhere in the
address space between $200000 to $[Link] the release of
AmigaDOS 1.2,the Amiga figures out where to put the memory
expansion by using a special`Autoconfig`[Link] allows you to
add memory and I/O without worrying about addresses and dip
switches.
Chip RAM;
The chips that support the Amiga`s processor access RAM almost
totally independantly and thus ease the workload of the processor.
However there is a draw back:these chips can only access the first
512k bytes of [Link] graphics and sound data handled by these
chips MUST be stored in this memory [Link] of this,that
memory range is referred to as `Chip RAM`.
Fast RAM;
The counterpart to chip RAM is the remaining RAM which,if the
computor is equipped with it,begins at $[Link] only the
processor itself as access to this part of memory it is known has
`Fast RAM`.
Here`s an overview of the Amiga`s memory:
$000000-$07FFFF chip RAM
$080000-$1FFFFF reserved
$200000-$9FFFFF potential fast RAM
$A00000-$BEFFFF reserved
$BFD000-$BFDF00 PIA B (even addresses)
$BFE001-$BFEF00 PIA C (odd addresses)
$C00000-$DFEFFF reserved for expansion
$DFF000-$DFFFFF custom chip registers
$E00000-$E7FFFF reserved
$E80000-$EFFFFF expansion ports
$F00000-$F7FFFF reserved
$F80000-$FFFFFF system ROM
Since the Amiga is multi-tasking,when a program is loaded into
memory,it is simply loaded into another memory [Link] memory
range thus occupied is added to a list of occupied memory and the
memory range is then considered barred from other [Link] another
program is loaded,which is quite possible with the Amiga,it is
read into another memory location which is then marked on the
occupied [Link] the first program should require additional
memory,to use a text buffer for example,that memory first has to
be [Link] another program could accidently be loaded
into the memory needed for this task.
What`s interesting about this procedure is that when the first
loaded has ended,the memory occupied by it is freed for further
[Link] a result,RAM is then chopped up into occupied and free
parts,which are no longer related to each [Link] Amiga can
still utilize these chunks of memory as if they were one
continuous [Link] all,parts is [Link] example of this is
the dynamic RAM disk which is always available under the name RAM:
This RAM disk is actually quite a phenomenon,since it is always
completely [Link] a program is erased from RAM disk,the memory
allocated to that program,regardless of its location or structure,
is given back to the [Link],if you reserved and filled 100
kbytes of memory,it would be quite posible that the 100kbytes
actually consists of various pieces of memory independant of one
[Link] never notice this since the Amiga automatically
corrects the difference between apparent and actual memory.

[Link]-Tasking.
-------------------
The Amiga is truly an amazing machine,being capable of doing
several things at one time.A red and white ball might be bouncing
around in one window while you`re working on text in another
window and watching a clock tick away in a third.
At least that`s the impression most people get when they recieve
their first Amiga [Link],there is a catch to this:
even the Amiga as only one processor,which can really only do one
thing at a time.
The tricky part is when more than one program is running,each
program is executed part by part,and the Amiga is constantly
switching from one program back to the other [Link] the
example above,the ball would first be moved by one pixel,then
the processor would check for a text entry and if necessary display
it,after which it would move the clock`s second [Link]
procedure would be repeated over and over,as the three programs
are executed [Link] problem is,that the greater the work
load on the processor,the slower the things [Link],programs
run slower during heavy multi-tasking.
Tasks;
Each of these jobs that the Amiga has to execute are commonly
referred to has tasks...thus,[Link] multi-tasking,
each task is assigned a special time segment during which that
particular task is [Link] time segments can be controlled,
so that more time consumming programs can be allotted somewhat
more processing time.
The programmer actually doesn`t need to know how this time slicing
[Link] can write aprogram without paying any attension to
multi-tasking and then run it simultaneously with another program
running in the [Link] only restriction is that you`ll have
to start the program from the CLI with`run`,or from the Workbench.
If you execute the program from the CLI by simply typing its name,
the processor allots all the time it can get from the CLI to that
program,until the execution is [Link] the program with
run free`s the CLI for other uses while the program is being
executed.
There is another restriction regarding multi-tasking that applies
to assembler [Link] from the use of extra memory,which
must first be reserved,the hardware registers should not be
directly [Link] the library functions should be [Link]
reason for this is quite simple:
Should you,for instance,specify the printer port as the input line
and are reading data in,another task might suddenly think its
supposed to be [Link] line would thus be switched to output
and data would be written [Link] this,your program would try to
read more data in,which would not be possible.
This is an oversimplified example,but it points out the problem
[Link] real programming situations the effects of
multiple direct programming of the hardware registers can be much
more [Link] your program still needs to access the
hardware registers directly(which can have some advantages),then
make sure that the program always runs by itself.
Chapter 2.
---------
[Link] MC68000 Processor.
-----------------------
The Amiga`s MC68000 processor is a 16/32 bit processor,which means
that while it can process data of 32 bits,it"only"has a 16 bit
data bus and a 24 bit address [Link],it can access 2^24=16777216
bytes(or 16 Mbytes)of memory directly.
7.1 Megaherz;
The Amiga 68000 processor,running at 7.1 megaherz,is quite fast,
which is required for a computor with a workload as heavy as the
Amiga`[Link] Amiga also processes a number of custom chips that
greatly ease the workload of the [Link] custom chips
manage sound in/output,graphics and animation,thus freeing the
processor for calculations.

[Link].
-------------
In addition to the standard RAM,the processor contains internal
memory called [Link] are eight data registers(D0-D7),
eight address registers(A0-A7),a status register(SR),two stack
pointers,a user stack pointer,a system stack pointer(USP and SSP)
and the program counter(PC).
Register Sizes;
The data registers,the address registers,and the program counter
are all 32 bits,while the status register is 16 [Link]
registers are located dirctly in the processor so they are not
accessed the same way memory would be [Link] are special
instructions for accessing these registers.
Data Registers;
The data registers are used for all kinds of [Link] can handle
operations with bytes(8 bits)words(16 bits)and longwords(32bits).
Address Registers;
The address registers are used for storing and processing
[Link] way they can be used as pointers to tables,in which
case only words and longwords operations are possible.
Stack Pointer;
The address register A7 plays a special role:this register is
utilized as the Stack Pointer(SR)by the processor,and thus is not
recommended for normal use by the [Link] of the two
possible stacks is being pointed to depends on the present mode of
the processor,but more about that later.
The stack,to whose actual position the stack pointer is pointing,
is used to store temporary internal [Link] stack works similar
to a stack of notes on your desk:the note that was added to the
stack last is the first one to come off the [Link] type of
stack is known as LIFO(Last in,First out).There is another type of
stack,the FIFO(First in,First out)which is not used by the
processor itself.
How these registers and the SP can be manipulated,or how to work
with the stack,is presented in the next [Link] continue with
the registers for now.
Status Register;
The status register plays an important role in machine language
[Link] 16-bit quality(word)contains important
information about the processor status in 10 of its [Link] word
is divided into two bytes,the lower byte(the user byte)and the
upper byte(the system byte).The bits that signify that certain
conditions are refered to as [Link] means that when a certain
condition is present,a particular bit is set.
The user byte contains five flags,which have the following meaning

Bit Name Meaning


-----------------------------------------------
0 (C,Carry) Carry bit,modified by math
calculation,and shift instructions.
1 (V,Overflow) Similar to carry,indicates a change
of sign,in other words,a carry from
bit six to bit seven.
2 (Z,Zero) Bit is set when the result of an
operation is zero.
3 (N,Negative) Is set when the result of an
operation is negative.
4 (X,Extended) Like carry,is set for arithmetic
operations.
5-7 Not used.

The system byte contains five significant bits:

Bit Nane Meaning


-----------------------------------------------
8 I0 Interupt [Link] interupt
9 I1 levels 0 to 7,where 0 is the lowest
10 I2 and 7 is the highest priority.
11 not used.
12 not used.
13 (S,Supervisor) This bit indicates the actual
pocessor mode(0=User,1=Supervisor
mode).
14 not used.
15 (T,Trace) If this bit is set,the processor is
in single step mode.

Here's an overview of the status word;

bit : 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
name : T - S - - I2 I1 I0 - - - X N Z V C

Don't let the new terms,like mode and interupt confuse [Link]'ll
talk about these in greater detail in the chapter dealing with the
operating conditions of the processor.

[Link] Memory.
---------------------
In the standard Amiga 500's and 1000's,the processor has over 512k
of RAM [Link] Amiga 2000 has one mega-byte of RAM that can
be accessed by the [Link] does the processor access all
this memory?
If you're programming in BASIC you don't have to worry about
memory [Link] can simply enter MARKER%=1,and the value is
stored in memory by the BASIC interpreter.
In assembler,there are two ways of accomplishing this task:
1) Store the value in one of the data or address registers,or
2)Write it directly into a memory location.
To demonstrate these two methods let's get a little ahead and
introduce a machine language instruction,which is probably the
most common:[Link] its name states,this instruction moves values.
Two parameters are required with the instruction:source and
destination.
Lets see what the example from above would look like if you
utilize the MOVE instruction...
1) MOVE #1,D0
This instruction moves the value 1 into data register [Link] you
can see,the source value is always entered before the destination.
Thus,the instruction MOVE D0,#1 is not possible.
2) MOVE #1,$1000
deposits the value 1 in the memory location at $[Link] address
was arbitrarily [Link] addresses of this form won't be
used at all in assembler programs,since labels that point to a
certain address are used [Link],the more common way of
writing this would be:
...
MOVE #1,MARKER

...
MARKER:DC.W 1

These are actually two pieces of program:the first part executes


the normal MOVE instruction whose destination is `MARKER`.This
label is usually defined at the end of a program and specifies the
address at which the value is stored.
The paraneter DC.W 1 is a pseudo op,apseudo [Link] means
that this isn`t an instruction for the processor,but an
instruction for the [Link] letters DC stand for`DeClare`and
the suffix .W indicates that the data is a [Link] other two
suffix alternatives would be .B for a byte(8 bits)and .L for a
long word(32 bits).
This suffix(.B.W or.L)is used with most machine language
[Link] the suffix is omitted,the assembler uses .W(word)
as the default [Link] you wanted a long word,you`d use an
instruction that looks something like this:MOVE .L #$1234678,D0
where as an instruction like MOVE.B #$12,D0 would be used for a
byte of [Link],with this instruction there`s one thing you
must be aware of...
CAUTION:
If the memory is accessed by words or long words,the address must
be even(end digit must be 0,2,4,6,8,A,C,E)!
Assemblers usually have a pseudo-op,`EVEN`or`ALIGN`,depending on
the assembler,that aligns data to an even [Link] becomes
necessary in situations similar to this:
...
VALUE1: DC.B 1
VALUE2: DC.W 1

If the VALUE1 is located at an even address,VALUE2 is automaticaly


located at an odd [Link] an ALIGN(EVEN)is inserted here,a fill
byte(0)is inserted by the assembler,thus making the second address
even.
...
VALUE1: DC.B 1
ALIGN
VALUE2: DC.W 1

Back to the different ways of [Link] variations listed


above are equivalent to the BASIC instruction MARKER%=1 where the
% symbol indicates an integer value.
Lets go a step further and translate the BASIC instruction MARKER
%=VALUE% into [Link]`ve probably already guessed the answer
right?

MOVE VALUE,MARKER
...
...
MARKER: DC.W 1
VALUE : DC.W 1

In this case,the contents in the address at VALUE are moved into


the address at MARKER.
With the help of these simple examples,you`ve already become
familiar with four different ways of addressing,in other words,
ways that the processor can access [Link] first is
characterized by the number sign(#)and represents a direct value.
Thus,this method is also known as direct addressing,and is legal
only for the source parameter!
A further method in which a direct address(in our case,`MARKER`and
`VALUE`)can be specified is known as absolute [Link]
method is legal for the source parameter as well as for the
destination parameter.
This method can be divided into two different types,between which
the programmer usually does'nt notice a [Link] on
whether the absolute address is smaller or larger than $FFFF,in
other words if it requires a long word,it is called absolute
addressing(for addresses above $FFFF)or otherwise absolute short
[Link] assembler generally makes the distinction between
these two types,and thus,only general knowledge of absolute
addressing is required.
The fourth method of addressing that you've encountered so far is
known as DATA REGISTER [Link] was the first one introduced(MOVE
#1,D0)in conjunction with direct addressing,the only difference
being that this type accesses a data register(such as D0).
These four methods aren't the only ones available to the MC68000
processor,in fact there are a total of [Link] other variation
called ADDRESS REGISTER DIRECT,is almost identical to data
register direct,except that it accesses the address register
instead of the data [Link],you can use MOVE.L #MARKER,A0 to
access the address register A0 directly.
You now know five ways to address memory with which quite a bit
can be [Link],lets tackle something more complicated and
more interesting.
Lets take another example from BASIC:

10 A=1000
20 POKE A,1

In this example the first line assigns the value 1000 to the
variable [Link] can be done in assembler as well:MOVE.L #1000,A0.
In the assembler version the absolute value of 1000 ia stored in
the address register A0.
Line 20 doesn't assign a value to the variable A itself,but rather
to the memory location at the address stored in [Link] is an
indirect access,which is quite easy to duplicate in assembler:

MOVE.L #1000,A0 ;bring address in A0


MOVE #1,(A0) ;write 1 into this address

The parentheses indicates an addressing known as ADDRESS REGISTER


[Link] method only works with address registers,since a
'data register indirect' does not exist.
There are several variations of this [Link] instance,a
distance value can be specified,which is added to the address
presently located in the address register before the register is
actually [Link] instruction MOVE #1,4(A0),if applied to the
example above,writes the value 1 into the memory cell at 1000+4=
[Link] distance value can be positive or [Link],values
from -32768 to +32768 are [Link] specific variation of
addressing is called ADDRESS REGISTER INDIRECT WITH A 16 BIT
DISPLACEMENT value.
There is another very similar variation:ADDRESS REGISTER INDIRECT
WITH AN 8 BIT INDEX [Link] this variation is limited to 8
bits,it also brings another register into [Link] second
register is also a distance value,except that it is a variable as
well.
We'll try to clarify this with an [Link] assume that a
program includes a data list that is structured like this:

...
RECORD: DC.W 2 ;number of entries -1
DC.W 1,2,3 ;elements of list

We'll use MOVE.L #RECORD,A0 to load the list into the address
register [Link] you can use MOVE (A0),D0 to pull the number of
in the list into the data [Link] access the last element of
the listonly one instruction is [Link] whole thing looks
something like this:

CLR.L D0 ;erase D0 completely


MOVE.L #RECORD,A0 ;address of list in A0
MOVE (A0),D0 ;number of elements -1 in D0
MOVE 1(A0,D0),D1 ;last element in D1
...
RECORD: DC.W 2 ;number of entries -1
DC.W 1,2,3 ;elements of list

This last instruction accesses the byte that is located at 1+A0+D0


in other words,the record +1 where the data begins plus the
contents of D0(in this case 2).
This method of accessing is very [Link] works exquisitely for
the processing of tables and lists,as the example [Link]
no distance value is needed,simply use a distance value of zero,
which some assemblers automatically insert as the default value if
for instance only MOVE (A0,D0)is entered.
The latter two methods have a third variation,which as its own
characteristic [Link] dosen't utilize an address register,but
uses the Program Counter(PC)[Link] program counter with
displacement method proves useful when a program must function
without any changes in all address [Link] following two
statements(in the 15 bit limits)have the same effect:

MOVE MARKER,D0

and
MOVE MARKER(PC),D0

This method is actually rather imprecise,since the first


instruction specifies the actual address of the marker with MARKER
while the second line specifies the distance between the
instruction and the [Link] since it would be quite
cumbersome to constanly calculate the distance,the assembler takes
this task off our hands and calculates the actual value automatic.
Lets examine the difference between the two [Link] a
program they'll accomplish the same thing,although they are
interpreted as two completely different things by the assembler.
You'll assume a program being at the address $1000 and the marker
is located at $[Link] generated program code looks something
like this:

$001000 30 39 00 00 11 00 MOVE MARKER,D1

or

$001000 30 3A 00 FE MOVE MARKER(PC),D1

As you can see,the generated code of the second line is two bytes
shorter than the first [Link] addition,if you were to shift this
code to the address $2000,the first version still accesses the
memory at $1100,while the second line using the PC indirect
addressing accesses memory at $2000 [Link],the program can
be transferred to almost any location.
This,then,is PROGRAM COUNTER WITH 16 BIT DISPACEMENT [Link] we
mentioned,there is also PROGRAM COUNTER WITH 8 BIT INDEX value,
which permits a second register as a distance value,also known as
offset.
There are two addressing modes [Link] two are based on
indirect [Link] offer the capability of automatically
raising or lowering the address register by one when memory is
accessed with address register indirect.
To automatically increase the register,you'd use ADDRESS REGISTER
DIRECT WITH [Link] address register raises this by the
number of bytes used AFTER accessing [Link] if you write:

MOVE.L #1000,A0
MOVE.B #1,(A0)+

the 1 is written in the address $1000 and then A0 is raised by one


Instructions like this are very helpful when a memory range is to
be filled with a specific value(for instance when the screen is
cleared).For such purposes the instruction can be placed in a loop
...which we'll get to later.
The counter part to post increment is ADDRESS REGISTER WITH PRE-
[Link] this case the specified address register is lowered
by one BEFORE the access to [Link] instructions:

MOVE.L #1000,A0
MOVE.B #1,-(A0)

writes 1 in the address 999,since the contents of A0 is first


decremented and the 1 is written afterwards.
These two methods of addressing are used to manage the stack
pointer(SP).Since the stack is filled from top to bottom,the
following is written to place a word(s.aD0)on the stack:
MOVE.B D0,-(SP)

and to remove it from the stack,again in D0:

MOVE.B (SP)+,D0

This way the stack pointer always points to the byte last
deposited on the [Link],again,you'll have to be careful that
an access to the stack with a word or a long word is always on an
even [Link],if you're going to deposit a byte on the stack,
either use a whole word or make sure the byte is not followed by a
JSR or [Link] JSR or BSR instructions deposit the addresses from
which they stem on the stack in the form of a long word.
In the code above,the SP is generally replaced by the address
register A7 in the program code,since this register is always used
as the [Link],you can write A7 as well as S,the resulting program
is the [Link],we recommend the use of SP,since this makes
the code somewhat easier to [Link] all,quite often you'll want
to employ your own stacks,in which case the difference between the
processor stack and your own stacks become very important.
These are the twelve ways of addressing the MC68000 processor,Here
is a summary:

No Name Format
-- ---- ------
1 data register direct Dn
2 address register direct An
3 address register indirect (An)
4 address register indirect with post-increment (An)+
5 address register indirect with pre-decrement -(An)
6 address register indirect with 16 bit displacement d16(An)
7 address register indirect with 8 bit index value 8(An,Rn)
8 absolute short xxxx.W
9 absolute long xxxxxxxx.L
10 direct #'data'
11 program counter indirect with 16 bit displacement d16(PC)
12 program counter indirect with 8 bit index value d8(PC,Rn)

The abbreviations above have the following meanings:

An address registers A0-A7


Dn data registers D0-D7
d16 16 bit value
d8 8 bit value
Rn register D0-D7,A0-A7
'data' up to 32 bit value,(either .B .W .L)

These are the addressing modes used by the MC68000 [Link]


bigger brother of this processor,the 32 bit MC68020,has six more
methods which we won't discuss here.
Next you're going to see under what conditions the processor can
operate.

[Link] Modes.
-------------------
In the previous section about registers you encountered the Status
Register(SR).The individual bits of this register reflect the
present operating condition of the [Link] differentiated
between the system byte(bits 8-15)and the user byte(bits 0-7).Now,
lets take a closer look at the system byte and its effects upon
the operation of the processor.

[Link] and Supervisor Modes.


-------------------------------
Isn't it rather strange that the processor classifies you either
as a'user'or a 'supervisor'?Both of these operating modes are
possible,the user mode being the more common [Link] this mode it
is impossible to issue some instructions,and that in your own
computor!
Don't worry though,you can get around that,as [Link] Amiga's
operating system contains a function that allows us to switch the
processor from one mode to the other.
The mode is determined by bit 13 of the Status [Link]
this bit is cleared(0),indicating that the processor is in user
[Link] is possible to write directly into the status register,
although this is a privileged instruction that can only be
executed from the supervisor [Link],this instructioncould only
be used to switch from the supervisor mode into the user mode,by
using AND #$DFFF,SR to clear the supervisor [Link],it is
quite preferable to let the operating system perform the switch
between these two modes.
Now what differentiates these two modes in terms of application?
Well,we already mentioned the first difference:some instructions,
such as MOVE xx,SR, are privileged and can only be executed from
the supervisor [Link] attempt to do this in user mode would
result in an exception and interruption of the [Link]
are the only way of switching to the supervisor mode,but more
about later.
A further difference is in the stack range [Link] A7 is
still used as the stack pointer,another memory range is used for
the stack [Link],the SP is changed rach time you switch from
one mode to the [Link] of this you differentiate between
the User(USP)and the Supervisor SP(SSP).
Accessing memory can also depend on these two [Link] such
accessing,the processor sends signals to the peripheral components
informing them of the current processor [Link] way a MC68000
computor can protect(privilege)certain memory ranges so they can't
be accessed by the user.
In the supervisor mode it is possible to execute all instructions
and access all areas of [Link] of this,operating systems
usually run in the supervisor [Link] is accomplished through
the use of Exceptions.

[Link].
----------------
Exceptions are similar to interupts on 6500 [Link] allows
stopping a program,running a sub-program,and then restarting the
stopped [Link] an exception occurs the following seps are
taken:

1) The status register is saved.


2) The S bit in SR is set(supervisor mode)and the T bit is
cleared(no trace).
3) The program counter and the user SP are saved.
4) The exception vector,which points to the needed exception
routine,is retrieved.
5) The routine is executed.
The vectors mentioned,which contain the starting addresses for the
various routines,are located at the very beginning of the memory.
Here is an overview of the vectors and their respective addresses:

Number Address Used for


----- ------ --------
0 $000 RESET:starting SSP
1 $004 RESET:starting PC
2 $008 bus error
3 $00C address error
4 $010 illegal instruction
5 $014 division by zero
6 $018 CHK instruction
7 $01C TRAPV instruction
8 $020 privilege violation
9 $024 trace
10 $028 Axxx-instruction emulation
11 $02C Fxxx-instruction emulation
$030-$038 reserved
15 $03C uninitialed interrupt
$040-$05F reserved
24 $060 unjustified interrupt
25-31 $064-$083 level 1-7 interrupt
32-47 $080-$0BF TRAP instructions
$0C0-$0FF reserved
64-255 $100-$3FF user interrupt vectors

The individual entries in the table above need detailed


[Link] lets go through them one by one...
RESET:staring SSP;
At reset,the long word stored at this location is used as the
stack pointer for the supervisor mode(SSP).This way you can
specify the stack for the RESET routine.
RESET:starting PC;
Again at reset,the value at this location is used as the program
[Link] other words,the RESET routine is started at the address
stored here.
Bus Error;
This exception is activated by a co-processor when,for instance,a
reserved or non-existant memory range is accessed.
Address Error;
This error occurs when a word or long word access is atempted at
an odd address.
Illegal Instruction;
Since all MC68000 instructions consist of one word,a total 65536
different instructions are [Link],since the processor
doesn't that many instructions,there are a number of words that
are invalid [Link] such a word occur,the exception is
prompted.
Division by Zero;
Since the processor has a division function,and the division of
anything by zero is mathematically undefined and thus illegal,this
exception occurs when such an operation is attempted.
CHK Instruction;
This exception only occurs with the CHK [Link]
instruction tests that a data registers contents are within a
certain [Link] this is not the case,the exception is activated.
TRAPV Instruction;
If the TRAPV instruction is executed and the V bit(bit 1)in the
status word is set,this exception is prompted.
Privilege Violation;
If a privileged instruction is called from the user mode,this
exception is activated.
Trace;
If the trace bit(bit 15)in the status word is set,this exception
is activated after each instruction that is [Link] method
allows you to employ a step by step execution of machine programs.
Axxx-Instruction Emulation;
Fxxx-Instruction Emulation;
These two vectors can be used for a quite interesting [Link] an
instruction beginning with $A or $F(such as $A010 or $F200)is
called the,the routine to which the corresponding vector is
pointing is [Link] these routines you can create chains of
other instructions,in effect expanding the processors instruction
vocaulary!
Reserved;
These vectors are not used.
Uninitialized Interrupt;
This exception is activated when a peripheral component that was
not initialized sends an interrupt.
Unassigned Interrupt;
Is activated when a BUS error occurs during the interrupt
verification of the activating [Link],the interrupt is
usually only by some type of disturbance.
Level 1-7 Interrupt;
These seven vectors point to the interrupt routines of the
corresponding priority [Link] the level indicated in the status
word is higher than the level of the occuring interrupt,the
interrupt is simply ignored.
TRAP Instructions;
These 16 vectors are used when a corresponding TRAP instruction
[Link],TRAP instructions from TRAP #0 to TRAP #15 are
possible.
User Interrupt Vectors;
These vectors are used for interrupts which are activated by
several peripheral components that generate their own vector
number.

At this point you don't want to delve any deeper into the secrets
of exceptions,since we'd be expanding this book beyond its frame
[Link],there's one last thing to say about exceptions:the
exception routines are ended with the RTE(ReTurn from Exception)
instruction,with which the original status is restored and the
user program is continued.

[Link].
----------------
Interrupts are processed similarly to [Link] are breaks
(or interruptions)in the program which are activated through
hardware(such as a peripherical component or an external trigger).
The interrupt level is stored in bits 8-10 of the status register.
A value between 0 and 7 indicates the interrupt [Link] are
eight possible interrupts,each of which as a different [Link]
the level of this interrupt happens to be higher than the value in
the status register,the interrupt is executed,or else ignored.
When a valid interrupt occurs,the computor branches to the
corresponding routine whose address is indicated in the exception
vector table above.
The interrupts are very important if you're trying to synchronize
a program with connected [Link] this manner,a trigger(s.a the
keyboard)which is to feed the computor data,can signal the request
for a legal value using an [Link] interrupt routine then
simply takes the value [Link] method is also employed for
the operation of the serial interface(RS232).
We'll talk about the use of interrupts at a later [Link] last
thing we want to mention about interrupts at this time is that,
like exceptions,interrupt routines are terminated with the RTE
instruction.

[Link] Codes.
---------------------
When you write a program in any language,the need for a
conditional operation arises quite [Link] instance,in a BASIC
program

IF D1=2 THEN D2=0

represents a conditional [Link] write the equivalent in


machine language,you first need to make the comparison:

CMP #2,D1

CMP stands for compare and compares two operands,in this case D1
and [Link] is this operation evaluated?
For this purpose you have condition codes(CC's),which exist in the
branch instructions of machine [Link] of this,you must
specify when and where the program is to branch.
The simplest variation of the branch instruction is an
unconditional [Link] corresponding instruction is 'BRA address
',although this won't help you [Link] all,you need a
conditional branch.
To retain the result of the operation,in this case a comparrison
(CMP),several bits are reserved in the status [Link] look at
bit 2 first,which is the zero [Link] flag is set when the
result of the previous operation was zero.
To explain the relationship between CMP and the Z flag,you must
first clarify the function of the CMP [Link] this
instruction performs the subtraction of the source operand from
the destination [Link] the example above,the number 2 is
subtracted from the content of the memory cell at [Link] the
result of this subtraction is discarded,the corresponding flags
are set.
If the contents of D1 in our example above happened to be 2,the
result of the subtraction would be [Link],the Z flag would be set,
which can then be evaluated through a corresponding branch
[Link] example would then look like this:

...
CMP #2,D1 ;comparison,or subtraction
BNE UNEQUAL ;branch,if not equal(Z flag not set)
MOVE #0,D2 ;otherwise execute D2=0

UNEQUAL:

... ;program branches to here


BNE stands for Branch if Not [Link] means,that if the Z flag
was cleared(=0)by the previous CMP,the program branches to the
address specified by BNE(here represented by UNEQUAL).The counter
part to the BNE instruction is the BEQ(Branch if EQual)instruction
which is executed if Z=1.
Here's a list of condition codes,which allow you to form
conditional branches using the Bcc(cc=condition code)format:

cc Condition Bits
---------------------------------------------------
T true,corresponds to BRA
F false,never branches
HI higher than C'* Z'
LS lower or same C + Z
CC,HS carry clear,higher or same C'
CS,LO carry set,lower C
NE not equal Z'
EQ equal Z
VC overflow clear V'
VS overflow set V
PL plus,positive
MI minus,negative
GE greater or equal N*V+N'*V'
LT less than N*V'+N'*V
GT greater than N*V*Z'+N'*V'*Z'
LE less or equal Z + N*V' + N'*V

*=logic AND, +=logic OR, '=logic NOT

Here are a few examples to demonstrate how these numerous


conditions can be utilized:

CMP #2,D1
BLS SMALLER_EQUAL

This branches if the contents of D1<=2,whether D1 is 0,1 or [Link]


this example,the BLE instruction would allow the program to branch
even if D1 is [Link] can tell this by the fact that the V
bit is used in the evaluation of this expression(see chart above).
When the sign is changed during the operation,this V bit is
compared with the N [Link] both bits be cleared(N bit=0 and V
bit=0)after the CMP subtraction(D1-2),the result has remained
positive:the condition as not been met.
The conditions EQ and NE are quite important for other uses,as
[Link] instance,they can be used to determine if particular bits
in a data word are set,by writing the following sequence...

...
AND #%00001111,D1 ;masks bits out
BEQ SMALLER ;branches when none of the four
; ;lower bits is set
CMP #%00001111,D1
BEQ ALL ;branches when all four bits set

The AND instruction causes all bits of D1 to be compared with the


bits of the parameter(in this case #%00001111).If the same bits
are set in both bytes,the corresponding bits are also set in the
[Link] one bit of the pair is cleared,the resulting bit is zero
as [Link],in the result,the only bits that are set are those
bits of the lowest four that were set in D1.
The technique is known as [Link] the example above,only the
lowest four bits were masked out,which meansthat in the resulting
byte,only the lowest four appear in their original [Link]
other bits are cleared with the AND [Link] course you can use
any bit combination with this method.
If no bit at all is set in the result,the zeroflag is set,thus
fullfilling the BEQ condition and branching the [Link],
the next instruction is processed,in which D1 is compared with
%[Link] both are equal,at leastall of the four lowest bits
of the original byte have been set,in which case the following BEQ
instruction branches.
Aside from CMP,the CC and CS conditions can also be used to
determine whether a HI bit was pushed out of the data word during
data rotation with the ROL and ROR instructions.
Before you move on the instruction vocabulary of the MC68000,we'd
like to give you another tip:
The AssemPro assembler makes it quite easy to try every command in
posible [Link] the CMP command which we've been talking
about,for [Link] test this command with various values and to
receive the results of the comparisons directly via the flags,try
the following.
Type the following into the Editor.

run:
cmp $10,d1
bra run
end

Assemble it,save the resulting code and enter the [Link]


reloading the code you can then single step through the program
observing the results the program has on the [Link] changing
the values in the register D1 and see how higher and lower values
affect the flag.
By the way,using the start command at this time causes it to run
[Link],at least until reset is hit,which isn't exactly
desirable,either...
This procedure isn't limited to just the CMP [Link] can
use it to try any other instructions you're interested in.

[Link] 68000 Instructions.


--------------------------
Its about time to explain the MC68000 [Link] don't have
room for an in-depth discussion of each instruction in this book;
for that purpose we recommend PROGRAMMING THE 68000 from Sybex by
Steve Williams.
The following tables show the required parameters and arguments
for each [Link] have access to built in help tables
covering effective addressing modes and many of the Amiga
Intuition [Link] following notation is used for arguments:

Label a label or address


Reg register
An address register n
Dn data register n
Source source operand
Dest destination operand
<ea> address or register
#n direct value
Here is a short list of the instructions for the MC68000 processor
AssemPro owners can simply place the cursor at the beginning of
the instruction and press the help key to see the addressing modes
allowed:

Mnemonic Meaning
---------------------------------------------------
Bcc Label conditional branch,depends on condition
BRA Label unconditional branch(similar to JMP)
BSR Label branch to [Link] address is
deposited on stack,RTS causes return to that
address.
CHK <ea>,Dx check data register for limits,activate the
CHK instruction exception.
DBcc Reg,Label check condition,decrement and branch
JMP Label jump to address(similar to BRA)
JSR Label jump to [Link] address is
deposited on stack,RTS causes return to that
address.
NOP no operation
RESET reset peripherals(caution!)
RTE return from exception
RTR return with loading of flags
RTS return from subroutine(after BSR and JSR)
Scc <ea> set a byte to -1 when condition is met
STOP stop processing(caution!)
TRAP #n jump to an exception
TRAPV check overflow flag,the TRAPV exception

Here are a few important notes...


When a program jumps(JSR)or branches(BSR)to subroutine,the return
address to which the program is to return is placed on the stack.
At the RTS instruction,the address is pulled back off the stack,
and the program jumps to that point.
Lets experiment a little with this [Link] enter the
following short program:

run:
pea subprogram ;address on the stack
jsr subprogram ;subprogram called
move.l (sp)+,d1 ;get a long word from stack
; illegal ;for assemblers without
;debuggers

subprogram:
move.l (sp),d0 ;return address in D0
rts ;and return
end

The first instruction,PEA,places the address of the subprogram on


the [Link],the JSR instruction jumps to the [Link]
return address,or the address at which the main program is to
continue after the completion of the subprogram,is also deposited
on the stack at this point.
In the subprogram,the long word pointed to by the stack pointer is
now loaded into the data register [Link] that,the RTS
instruction pulls the return address from the stack,and the
program jumps to that address.
Back in the main program,the long word which is on the top of the
stack,is pulled from the stack and written in [Link] that
do not have the debugging features of AssemPro may need the
ILLEGAL instruction so they can break the program and allow you to
view the register contents.
Assemble the program and load the resulting code into the debugger
Single step thru the program and examine the register contents.
Here you can see that D0 contains the address at which the program
is to continue after the RTS [Link],D1 contains the address
of the subprogram which you can verify by comparing the debugger
listing.
The STOP and RESET instructions are so powerful that they can only
be used in supervisor [Link] if you do switch to the supervisor
mode,you should NOT use these instructions if there is any data in
memory that has not been saved and you wish to retain.
The TRAP instruction receives a number between 0 and $F,which
determines the particular TRAP vector(addresses $0080-$00BF)and
thus the corresponding exception [Link] operating systems
for the 68000 utilize this instruction to call operating system
[Link]'ll deal more with this instruction later.
In the short sample program that compared two numbers,the CMP
instruction performed an arithmetic function,namely a subtraction.
This subtraction could be performed with an actual result as well
using the SUB [Link] counterpart to this is in addition,
for which the ADD instruction is [Link] 8 bit processors,like the
6502,these arithmetic functions are the only mathematical
[Link] MC68000 can also multiply,divide,and perform these
operations with a variety of data sizes.
Most of the functions require two [Link] instance the ADD
instruction...

ADD source,destination

where source and destination can be registers or memory addresses.


Source can also be a direct value(#n).The result of the opoeration
is placed in the destination register or the destination address.
This is same for all operation of this [Link] instructions can
be tried out with the AssemPro [Link] this case we recommend
the use of a register as the destination.
Heres an overview of the arithmetic operations with whole numbers:

Mnemonic Meaning
--------------------------------------------------------------
ADD source,dest binary addition
ADDA source,An binary addition to a address register
ADDI #n,<ea> addition with a constant
ADDQ #n,<ea> fast addition of a constant which can
be only from 1-8
ADDX source,dest addition with transfer in X flag
CLR <ea> clear an operand
CMP source,dest comparison of two operands
CMPA <ea>,An comparison with an address register
CMPI #n,<ea> comparison with a constant
CMPM source,dest comparison of two memory operands
DIVS source,dest sign-true division of a 32 bit
destination by a 16 bit source operand.
The result of the division is stored in
the LO word of the destination,the
remainder in the HI word.
DIVU source,dest division without regard to sign,similar
to DIVS
EXT Dn sign-true expansion to twice original
size(width)data unit
MULS source,dest sign-true multiplication of two words
into one long word
MULU source,dest multiplication without regard to sign,
similar to MULS
NEG <ea> negation of an operand(twos complement)
NEGX <ea> negation of an operand with transfer
SUB source,dest binary subtraction
SUBA <ea>,An binary subtraction from an address
register
SUBI #n,<ea> subtraction of a constant
SUBQ #n,<ea> fast subtraction of a 3 bit constant
SUBX source,dest subtraction with transfer in X flag
TST <ea> test an operand and set N and Z flag

For the processing of whole numbers,the processor can operate with


BCD [Link] are Binary Coded Decimal numbers,which means
that the processor is working with [Link] this method,each
halfbyte contains only numbers from 0 to 9,so that these numbers
can be easily [Link] this method,the following instructions
are available:

Mnemonic Meaning
-----------------------------------------------------------------
ABCD source,dest addition of two BCD numbers
NBCD source,dest negation of a BCD number(nine
complement)
SBCD source,dest subtraction of two BCD numbers

Again,we recommend that you try this out [Link]


handling the BCD numbers is relatively easy,it can be rather
awkward at [Link] sure that you enter only BCD numbers for
source and destination,since the results are not correct
otherwise.
Next are the logical operations,which you might know from BASIC.
With these functions,you can operate on binary numbers bit for
bit.

Mnemonic Meaning
-----------------------------------------------------------------
AND source,dest logic AND
ANDI #n,<ea> logic AND with a constant
EOR source,dest exclusive OR
EORI #n,<ea> exclusive OR with a constant
NOT <ea> inversion of an operand
OR source,dest logic OR
ORI #n,<ea> logic OR wuth a constant
TAS <ea> check a byte and set bit 7

Single bits can also be manipulated by the following set of


instructions:

Mnemonic Meaning
----------------------------------------------------------------
BCHG #n,<ea> change bit n(0 is changed to 1 and vice
versa)
BCLR #n,<ea> clear bit n
BSET #n,<ea> set bit n
BTST #n,<ea> test bit n,result is displayed in Z
flag

These instructions are particularly important from the


manipulation and evaluation of data from [Link] all,in
this type of data,single bits are often very [Link]'ll
come across this more in later chapters.
The processor can also shift and rotate an operand within itself
('n'indicates a register,'#'indicates a direct value which
specifies the number of shiftings)...

Mnemonic Meaning
----------------------------------------------------------------
AS n,<ea> arithmetic shift to the left(*2^n)
ASR n,<ea> arithmetic shift to the right(/2^n)
LSL n,<ea> logic shift to the left
LSR n,<ea> logic shift to the right
ROL n,<ea> rotation left
ROR n,<ea> rotation right
ROXL n,<ea> rotation left with transfer in X flag
ROXR n,<ea> rotation right with transfer in X flag

All these instructions allow you to shift a byte,a word or a long


word to the left or [Link] not too surprising that this is the
equivalentof multipling(dividing)the number by a power of [Link]'s
a little example to demonstrate why
Lets take a byte containing the value 16 as an [Link] binary,
it looks like this:

%00010000 =16

Now,if you shift the byte to the left by inserting a 0 at the


right,you'll get the following result...

%00010000 shifted to the left equals


%00100000 =32,in effect 16*2

Repeated shifting results in repeated doubling of the [Link]


if you shift the number n times,the number is multiplied by 2^n.
The same goes for shifting to the [Link],this operation as
a slight quirk:here's a sample byte with the value 5:

%00000101 =5,shifted once to the right equals


%00000010 =2

The answer in this case is not 2.5 as you might [Link] result
such a division is always a whole number,since any decimal places
are [Link] you use the DIV instruction instead of shifting,
you'll retain the digits to the right of the decimal [Link]
shifting is somewhat faster,and shifting can also receive long
words as results.
After explaining the principle of shifting,you still need to know
why more than two instructions are required for the [Link]
this is because there are several different types of shifting.
First,you must differentiate between shifting and [Link]
shifting,the bit that is added to the left or the right side is
always a [Link] rotating,it is always a specific value that is
[Link] means that with the ROR or the ROL instructions,the
bit that is taken out on one side is the one that is inserted on
the [Link] the ROXR and the ROXL instructions this bit takes a
slight detour to the X [Link],the content of the flag is
inserted into the new bit,while the old bit is loaded into the
flag.
Shifting as well,has two variations:arithmetic and logical
[Link]'ve already dealt with logical [Link] this
variation,the inserted bit is always a zero,and the extracted bit
is deposited in the C flag and in the X flag.
Although the highest bit,which always represents the sign,is
shifted in arithmetic shifting,the sign is still retained by ASR.
This has the advantage that when these instructions are used for
division,the operation retains the correct sign(-10/2 equals-5).
However,should an overflow or underflow cause the sign to change,
this change is noted in the V flag,which always indicates a change
in [Link] logical shifting this flag is always cleared.
Now to the instructions that allow you to move [Link] are
actually the most important instructions for any processor,for how
else could you process data?

Mnemonic Meaning
------------------------------------------------------------------
EXG Rn,Rn exchange of two register contents(don't
confuse with swap)
LEA <ea>,An load an effective address in address
register An
LINK An,#n build stack range
MOVE source,dest carry value over from source to dest
MOVE SR,<ea> transfer the status register contents
MOVE <ea>,SR transfer the status register contents
MOVE <ea>,CCR load flags
MOVE USP,<ea> transfer the user stack point
MOVE <ea>,USP transfer the user stack point
MOVEA <ea>,An transfer a value to the address
register An
MOVEM Regs,<ea> transfer several registers at once
MOVEM <ea>,Regs transfer several registers at once
MOVEP source,dest transfer data to peripherals
MOVEQ #n,Dn quickly transfer a 8 bit constant to
the data register Dn
PEA <ea> deposit an address on the stack
SWAP Dn swap the halves of the register(the
upper 16 bits with the lower)
UNLK An unlink the stack

The LEA or PEA instructions are often used to deposit addresses in


an address register or on the [Link] instruction

LEA label,A0

loads the address of the label'label' into the address register


[Link] practice,this corresponds to

MOVE.L #label,A0

which is equivalent to

PEA label
All these instructions deposit the address of 'label' on the stack
The following instruction also does this:

MOVE.L #label,-(SP)

The LEA instruction becomes much more interesting when the label
is replaced by indirect [Link]'s an example:

LEA 1(A0,D0),A1

The address that's produced by the addition of 1(direct value


offset)+A0+D0 is located in [Link] duplicate this instruction with
MOVE would be quite [Link] a look:

MOVE.L A0,A1
ADD.L D0,A1
ADDQ.L #1,A1

As you can see,the LEA instruction offers you quite some


interesting possibilities.
Those are all the instructions of the [Link] their
combination using the diverse methods of addressing,you can create
a great number of different instructions,in order to make a
program as efficent as possible.
The following table is an overview of all MC68000 instructions
along with their possible addressing types and the influence of
[Link] following abbreviations are used:

x=legal s=source only d=destination only


-=not effected 0=cleared *=modified accordingly
1=set u=undermined P=privileged

Mnemonic 1 2 3 4 5 6 7 8 9 10 11 12 X N Z V C P
-----------------------------------------------------------------
ABCD x
ADD s s x x x x x x x s s s * * * * *
ADDA x x x x x x x x x x x x - - - - -
ADDI x x x x x x x x * * * * *
ADDQ x x x x x x x x x * * * * *
ADDX x x * * * * *
AND s x x x x x x x s s s - * * 0 0
ANDI x x x x x x x x - * * 0 0
ASL, ASR x x x x x x x x * * * * *
Bcc - - - - -
BCHG x x x x x x x x - - * - -
BCLR x x x x x x x x - - * - -
BRA - - - - -
BSET x x x x x x x x - - * - -
BSR - - - - -
BTST x x x x x x x x z x x - - * - -
CHK x x x x x x x x x x x - * u u u
CLR x x x x x x x x - 0 1 0 0
CMP x x x x x x x x x x x x - * * * *
CMPA x x x x x x x x x x x x - * * * *
CMPI x x x x x x x x - * * * *
CMPM x x x x x x x - * * *
cpGEN - - - - -
DBcc - - - - -
DIVS x x x x x x x x x x x - * * * 0
DIVU x x x x x x x x x x x - * * * 0
EOR x x x x x x x x - * * 0 0
EORI x x x x x x x x - * * 0 0
EORI CCR * * * * *
EORI SR * * * * *
EXG - - - - -
EXT - * * 0 0
EXTB - * * 0 0
ILLEGAL - - - - -
JMP x x x x x x x - - - - -
JSR x x x x x x x - - - - -
LEA x x x x x x x - - - - -
LINK x - - - - -
LSL, LSR x x x x x x x * * * 0 *
MOVE x s x x x x x x x s s s - * * 0 0
MOVEA x x x x x x x x x x x x - - - - -
MOVE to CCR x x x x x x x x x x x * * * * *
MOVE from SR x x x x x x x x - - - - - P
MOVE to SR x x x x x x x x x x x * * * * * P
MOVE USP x - - - - - P
MOVEM x s d x x x x s s - - - - -
MOVEP s d - - - - -
MOVEQ d - * * 0 0
MULS x x x x x x x x x x x - * * 0 0
MULU x x x x x x x x x x x - * * 0 0
NBCD x x x x x x x x * u * u *
NEG x x x x x x x x * * * * *
NEGX x x x x x x x x * * * * *
NOP - - - - -
NOT x x x x x x x x - * * 0 0
OR s x x x x x x x s s s - * * 0 0
ORI x x x x x x x x - * * 0 0
PEA x x x x x x x - - - - -
RESET - - - - - P
ROL, ROR x x x x x x x - * * 0 *
ROXL, ROXR x x x x x x x - * * 0 *
RTE - - - - - P
RTR * * * * *
RTS - - - - -
SBCD x x * u * u *
Scc x x x x x x x x - - - - -
STOP x - - - - -
SUB s s x x x x x x x s s s * * * * *
SUBA x x x x x x x x x x x x - - - - -
SUBI x x x x x x x x * * * * *
SUBQ x x x x x x x x x * * * * *
SUBX x x * * * * *
SWAP x - * * 0 0
TAS x x x x x x x x - * * 0 0
TRAP x - - - - -
TRAPV - - - - -
TST x x x x x x x x - * * 0 0
UNLK x - - - - -

Chapter 3.
---------
[Link] With Assemblers.
-------------------------
The instructions that you've learned so far are incomprehensible
to the MC68000 [Link] letters MOVE mean absolutely nothing
to the processor-it needs the instructions in binary [Link]
instruction must be coded in a word-which normally takes a lot of
work.
An assembler does this work for [Link] assembler is a program that
translates the instructions from text into the coresponding binary
[Link] text that is translated is called Mnemonic or
[Link] a lot easier working with text instructions-or does
$4280 mean more to you than CLR.L D0?
This chapter is about working with [Link]'ll describe the
following three:
ASSEM;
This is the assembler from the Amiga's development [Link]
assembler is quite powerful,but it is clearly inferior to its two
fellow compilers in some areas.
AssemPro;
This is the Abacus [Link] has a debugger in addition to the
[Link] lets you test and correct [Link] our opinion,
it is the best one to use for writing and testing practice
[Link] this reason,we wrote the programs in this book with
this assembler.
KUMA-SEKA;
This is a popular assembler which also has a debugger.

All assemblers perform a similar task-they translate memcode,so


that you can write a runable program to [Link] test the program
directly,you need a debugger which is something Assem doesn't
have.

[Link] Development Assembler.


-----------------------------
This assembler is a plain disk [Link] means that it can
only assemble text files that are on disk and write the result
back to [Link] can't make direct input or test run the new
program.
You can call ASSEM from the CLI by typing ASSEM followed by
parameters that specify what you wish the assembler to do.
In the simplest case,you call it like this:

ASSEM Source -O Destination

Source is the filename of the file containing the program text.


Destination is the name of the file that contains the results of
assembling after the process is [Link] "-O"means that the
following name is used for the object file.
There are several other parameters that can be [Link] are
written with their option(ie-O),so that the assembler knows what
to do with the file that you've told it to [Link] following
possible options must be followed by a filename.

-O Object file
-V Error messages that occur during assembling are written
to a [Link] this isn't given,the error messages appear
in the CLI window.
-L The output of the assembled program lines are sent to
this [Link] can also use"PRT:"to have it printed.
-H This file is read in at the beginning of the assembled
file and assembled along with it.
-E A file is created that contains lines which have EQU
instructions.
-C This option isn't followed by a filename but by another
[Link] can also use OPT to do [Link] following
options are available:

OPT S A symbol table is created which contains all the


labels and their values.
OPT X A cross reference list is created(where labels
are used).
OPT W A number must follow this [Link] sets the
ammount of workspace to be reserved.

The assembler creates an object [Link] is not [Link] make


it runnable,you need to call the linker,[Link] program can
link several assembled or compiled object files together to make a
runnable [Link] the simplest case,you enter the following
instruction in the CLI:

ALINK Source TO Destination

Source is the object file produced by the [Link] is


the name of the [Link] can be started directly.

[Link].
------------
Abacus's AssemPro is a package which combines editor,assembler and
debugger in an easy to use package.
The AssemPro Program is divided into several windows-one for the
assembler,the editor,the debugger and several help functions.
Producing a program is very easy:

1) Write the program with the editor and then store it to disk.
2) Start the assembler,so that the program is translated.
3) If desired,start the debugger,load the program and test it.

Within the debugger you can work through parts of the program or
even through single [Link] after each one of these steps the
debugger shows you the state of the registers and flags in the
status register,you can easily try the programs presented in this
book.
You need to load AssemPro only once when working with machine
language [Link] you don't need to save back and to between
editor,assembler,linker and debugger.
AssemPro has an especially interesting function:the reassembler.
With this debugger function you are able to convert runnable
programs into the source text of the [Link] you have made
the source text,you can edit the program using the editor and
assemble it [Link] is equipped with functions other
assemblers [Link] are however,some differences you should know
[Link] many programs you see were written for the K-SEKA,be
aware of one difference:the EVEN [Link] uses the ALIGN
instruction.
Note,that when entering and assembling one of the programs in
AssemPro you must make sure that you place an END directive at the
end of the source text.
The following is an introduction into working with AssemPro and
the programs in this book.

Start AssemPro normally,next click on the editor window and start


typing in your [Link] the program is on disk already,load it
by selecting the appropriate menu or by using the key combination
right <AMIGA> key and <o>.To do this you only need to ckick on the
filename in the displayed requester and click on the OK gadget.
Once you have typed in or loaded the program into the editor,you
can assemble [Link] is best to save your source before assembling.
You assemble your program by clicking on the assembler window
displayed above the editor window and pressing <AMIGA> and <a>.You
can then choose how to locate your program in the [Link]
that data used by the co-processors must be located in CHIP RAM.
By clicking OK you start the assembler [Link] you additionally
select "breakable",you can cancel the process by pressing both
shift [Link] any error occurs during assembling,AssemPro uses a
window to tell you [Link] this window to correct the error and
continue with "Save and try again".
Now the runnable program is located in the Amiga's [Link] the
menu item "Save as"to save it on [Link] you want to store it on
RAM disk,click the given filename and enter RAM: in front of this
[Link] addition you can click on the menu item "ICON"and choose
if you only want the program itself on disk but the icon [Link]
this icon to start the program at a later time from Workbench.
To test-run the program,you move the debugger window to the
foreground of the screen(for instance by clicking on the back
gadget).Use "Load"in the debugger menu or <AMIGA> <o> to call the
select file window,where you select the saved [Link] program
is then loaded into the memory and its shown disassembled.
The highlighted line(orange)represents the current state of the
program [Link] is the line where the processor reads its
next instruction,provided you tell the processor [Link] are
three ways to do so.
The first one is to start the program with "Start".This
alternative does not enable you to stop the program if anything
goes wrong.
The second possibility,"Start breakable"is better in this respect.
After the program starts,it continuously displays the registers
contents on the left side of the [Link] addition to that you
can cancel the process by pressing <ESC>.Note that this only works
if your program doesn't use the <ESC>key itself.
The third possibility enables you to only partly run your program.
You can do this by stepping through the program or by placing
breakpoints throughout the [Link] place these by clicking on
the desired address and then pressing <AMIGA> <b>."BREAKPOINT"is
displayed where the command was displayed [Link] you start the
program now,it stops whenever it comes across any breakpoints.
You can start a small part of the program by moving the mouse
pointer to the orange line,clicking the left button and holding it
down while you drag the mouse pointer [Link] you release the
button,the processor works through this part of the program,
stopping at the line,where you positioned the mouse [Link]
is a very useful method to step by step test a program.
AssemPro as another helpful window:the [Link] window lists the
valid address methods for instructions and the parameters of Amiga
[Link] is extremely helpful whenever you are not sure
about one of the instructions.
[Link] K-SEKA Assembler.
------------------------
The SEKA assembler,from KUMA,has a simple text editor and a
debugger in addition to the [Link] program is controlled
by simple instructions and it is easy to [Link] is also multi-
functional and quick,so it is great for small test and example
[Link] can use it to write bigger programs once you've got
use to the [Link] lets look at the editor.
To load a program as source code(text)into the editor,enter"r"
(read).The program asks you for the name of the file with the
"<FILENAME>"[Link] then enter the name of the text [Link] you
created the file with SEKA,the file is stored on disk with".s" on
the end of its [Link] don't need to include the".s"when you load
the [Link] taken care of automatically.("s"stands for source.)
You can store programs you've just written or modified by using
the"w"[Link] program asks you for the [Link] you enter
"Test",the file is written to the disk with"Test.s"as its name.
This is a normal text file in ASCII format.
There are two ways to enter or change a programs:using the line
editor or the screen [Link] can enter the second by hitting
the <ESC>[Link] upper screen section is then reserved for the
[Link] can move with the cursor keys and change the text
[Link] lines that you enter are inserted into the existing
text and automatically [Link] hitting the <ESC>key again,you
leave the screen editor.
There's really not much to say about this [Link]'s really just
for simple insertions and [Link] functions are called in
normal instruction mode,the mode in which">"is the input prompt.
The following instructions are available to you for text editing
(<n>stands for a [Link] meaning of the instructions is in
parenthesis.)

Instruction Function
----------------------------------------------------------------
t(Target) Puts the cursor on the highest line in the
text.
t<n> Puts the cursor on line n.
b(Bottom) Puts the cursor on the last line in the text.
u(Up) Go up one line.
u<n> Go up n lines.
d(Down) Go down one line.
d<n> Go down n lines.
z(Zap) Deletes the current line.
z<n> Deletes n lines starting at the cursor line.
e(Edit) Lets you edit the current line(and only that
line).
e<n> Edit from line n.
ftext(Find) Searches for the text entered starting at the
current [Link] case of a letter makes a
difference,so make sure to enter it correctly.
Blanks that appear after the f are looked for
as well!
f Continues searching beyond the text that was
previously given.
i(Insert) Starts the line [Link] you can enter a
program line by [Link],you can't use the
cursor to move into another [Link] numbers
are generated [Link] lines that
follow are moved down,not erased.
ks(Kill Source) The source text is deleted if you answer"y"
when the program asks if you are [Link]
nothing happens.
o(Old) Cancels the "ks"function and saves the old text
p(Print) Prints the current line.
p<n> Prints n lines starting at cursor line.

Those are the K-SEKA's editor [Link] combination with the


screen editor,they allow for simple text [Link] can,for
example,delete the current line(and other lines)while working in
the screen editor by hitting <ESC> to get into instruction mode
and then entering"z"(or "z<n>").
If you'd like to edit all lines that contain "trap",for example,
you can do the following:

-Jump to the beginning of the text using "t"


-Search for a "trap"instruction by entering "ftrap" in the
first line.
-Press <ESC> and edit the line.
-Press <ESC> again to get into instruction mode.
-Search using "f",<ESC>,[Link] you get to the end of the
text.

This sounds very clumsy,but in practise it works quite well and


goes [Link] with the editor bit,so you can get use to
it.
Now here are the instructions for working with disks:

Instruction Function
-----------------------------------------------------------------
v(View files) Look at the disk's [Link] can also
include the disk drive or subdirectory
that interests [Link] example,"vc"causes
the "c"subdirectory to be listed and makes
it the current directory.
kf(Kill file) The program asks for the name of the file.
The file is deleted(and you aren't asked
if your sure either-so be careful).
r(Read) After inputting this instruction,you'll be
asked which file to load(FILENAME>).The
file that you specify is then [Link]
only "r"is entered,a text file is loaded
in the editor.
ri(Read Image) Loads a file into [Link] you've
entered the filename,SEKA asks for the
address the file should begin at in memory
(BEGIN>)and the highest address that
should be used for the file(END>).
rx(Read from Auxillary) This works just like the "ri"function
except that it reads from the serial port
instead of from disk(You don't need a file
name).
rl(Read Link file) This instruction reads in a SEKA created
link [Link] you'll be asked if you are
sure,because the text buffer is erased
when the link file is loaded.
w(Write) After entering this instruction,you'll be
asked for the name of the file the text
should be written to.A".s"is automatically
appended to the name,so that it can be
recognized as a SEKA file.
wi(Write Image) Stores a block of memory to disk after the
name,beginning and end are entered.
wx(Write to Auxillary) This is similar to"wi";the only difference
is that the output is to the serial inter-
face.
wl(Write Link file) Asks for the name and then stores a link
file that was assembled with the"I"option
to [Link] this isn't available,the
message "* * Link option not specified"
appears.

Once you've typed in or loaded a program,you can call the


assembler and have the program [Link] enter"a"to do so.
You'll then be asked which options you want to [Link] you enter a
<RETURN>,the program is assembled normally-ie the results of
translating a program in memory is stored in [Link] the
program can be executed straight away.
You can enter one or more of the following options,however:

v The output of the results goes to the screen.


p or
e goes to the printer with a title line.
h The output stops after every page and waits for a key
[Link] is useful for controlling output to the screen
or for putting new sheets of paper in the printer.
o This option allows the assembler to optimize all possible
branch [Link] allows the program code to be
shorter than it would otherwise [Link] messages appear
but you can ignore them.
l This option causes linkable code to be [Link] can
save it with the"wl"instruction and read it with the "rl"
instruction.

A symbol table is included at the end of the listing if desired.


The table contains all labels and their [Link] also contains
macro names.A macro allows several instructions to be combined in
to a single instruction.
For example,suppose you wrote a routinethat outputs the text that
register A0 points [Link] time you need to use the routine,you
must type:

lea text,a0 ;pointer to text in A0


bsr pline ;output text

You can simplify this by defining a macro for this [Link] do


this,put the following at the beginning of the program:

print:macro ;Macro with the name "Print"


lea ?1,a0 ;Parameter in A0
bsr pmsg ;Output text
endm ;End of macro

Now,you can simply write the following in your program:

print text ;Output text

This line is replaced using the macro during [Link]


parameter "text"is inserted where "?1"appears in the [Link] can
have several parameters in a [Link] give them names like "?2",
"?3",etc...
You can also decide whether you'd like to see the macros in the
output listing of the [Link] is one of the pseudo-ops that
are available in the [Link] SEKA assembler has the
following pseudo-ops:

dc Defines one or more data items that should appear in


this location in the [Link] word length can be
specified with .B,.W,or .L-and if this is left off, .B
is [Link] can be entered in question marks or
[Link] example:dc.b "Hello",10,13,0
blk Reserves a number of bytes,words or long words,depending
on whether .B,.W,or .L is [Link] first parameter
specifies the number of words to be [Link] second
(which is optional)is used to fill the memory [Link]
example:blk.w 10,0
org The parameter that follows the org instruction is the
address from which the (absolute) program should be
[Link] example: org $40000
code Causes the program to be assembled in relative mode,the
mode in which a program is assembled starting at address
[Link] Amiga takes care of the new addressing after the
program is loaded.
data This means that from here on only data [Link] can
be left out.
even Makes the current address even by sometimes inserting a
fill byte.
odd The opposite of even-it makes the address odd.
end Assembling ends here.
equ or Used for establishing the value of a label
= For example: Value=123 or Value:equ 123
list Turns the output on again(after nlist).You can use the
following parameters to influence the output:
c Macro calls
d Macro definitions
e Macro expansion of the program
x Code expansions
For example: list e
nlist Turns off [Link] can use the same parameters here as
with "list".
page Causes the printer to execute a page feed,so that you'll
start a new page.
if The following parameter decides whether you should
continue [Link] it is zero,you won't continue
assembling.
else If the "if"parameter is zero,you'll begin assembling
here.
endif End of conditional assembling.
macro Start of a macro definition.
endm End of macro definition.
?n The text in the macro that is replaced by the nth
parameter in the calling line.
?0 Generates a new three digit number for each macro call-
this is very useful for local labels.
For example: x?0:bsr pmsg
illegal Produces an illegal machine language instruction.
globl Defines the following label as globel when the "I"option
of the assembler is chosen.

Once you've assembled your program,the program code is in memory.


Using the "h"instruction,you can find out how large the program is
and where it is located in [Link] beginning and end address is
given in hex and the length in decimal(according to the last
executed operations):

Work The memory area defined in the beginning


Src Text in memory
RelC Relocation table of the program
RelD Relocation table of the memory area
Code Program code produced
Data The program's memory area

You'll find program in memory at the location given by [Link]'s a


pain to have to enter this address whenever you want to start the
[Link] make's good sense to mark the beginning of the program
with a label(for example,"run:").You can use the "g"instruction to
run the program as follows:

g run

The"g"(GO)instruction is one of SEKA's debugger [Link]


an overview:

x Output all registers.


xr Output and change of registers(ie xd0)
gn Jump to address [Link]`ll be asked for break points,addresses
at which the program should be terminate.
jn This is similar to the one above-a JSR is used to jump into
the [Link] program must end with a RTS instruction.
qn Output the memory starting at address [Link] can also specify
the word [Link] example: q.w $10000
nn Disassembled output starting at address n.
an Direct assembling starting at address [Link] program
instructions are entered.
nn Modify the contents of memory starting at address [Link] too
the word length can be [Link] can terminate input with
the <ESC> key.
sn Executes the program instruction that the PC points [Link]
you enter this instruction,n program steps are executed.
f Fill a memory [Link] can choose the word [Link] the
needed parameters are asked for individually.
c Copies one memory area to [Link] the needed parameters
are asked for individually.
? Outputs the value of an expression or a label.
For example: ?run+$1000-256
a Sets an instruction sequence that is passed to the program
when it starts as if it were started from CLI with this
sequence.
! Leaves the SEKA assembler after being asked if your sure.

You saw some of the calculations like SEKA can make in the "?"
[Link] can also use them in [Link] folowing
operations work in SEKA:

+ Addition
- Subtraction
* Multiplication
/ Division
& Logic AND
! Logic OR
~ EXclusive OR (XOR)

These operations can also be [Link] can choose the counting


system.A "$"stands for hexadecimal,"@"for octal,and "%"for binary.
If these symbols aren`t used,the number is interpreted as a
decimal number.
Lets go back to the [Link] mentioned,after entering "g
address",you`ll be asked for break [Link] can enter up to 16
addresses at which the program [Link] you don`t enter break
points,but instead hit <RETURN>,the program must end with an
ILLEGAL [Link] it ends instead with a RTS,the next return
address from the stack is retrieved and jumped [Link] is usually
address 4 which causes SEKA to come back with "**Illegal
Instruction at $000004",but theres no guarantee that it [Link]
computor can end up so confused that it can`t function.
The SEKA program puts an ILLEGAL instruction in the place
specified as break points after saving the contents of these
[Link] the processor hits an illegal instruction,it jumps
back to the debugger by using the illegal instruction vector that
SEKA set up [Link] SEKA repairs the modified memory
locations and then displays the status [Link] you can find out
where the program terminated.
Using break points is a good technique for finding errors in the
[Link] can,for example,put a break point in front of a
routine that you`re not sure about and start the [Link] the
program aborts at this spot,you can go through the routine step by
step using the "s"[Link] you can watch what happens to the
status line after each instruction and find the mistake.
Program errors are called [Link]`s why the program that finds
them is called a debugger.

Chapter 4.
---------
[Link] First Programs.
--------------------
You`re getting pretty far along in your knowledge of machine
language [Link] fact,you`re to the point where you can
write programs,and not just programs for demonstration purposes,
but ones that serve a real [Link]`re assuming that you have
the AssemPro assembler and have loaded it.
If you`re using a different assembler,a few things must be done
[Link] covered those differences already in the chapter on
the different assemblers.
We`ve written the example programs as subroutines so they can be
tried out directly and used [Link] assembling the program,you
can put the desired values in the [Link] you can either
single-step thru the programs or run the larger programs and
observe the results in the registers directly.(using the SEKA
assembler you can type "j program_name"to start the [Link]
you can read the results from the register directly,or use "q
address"to read it from memory.)
Lets start with an easy example,adding numbers in a table.
[Link] Tables.
-----------------
Imagine that you have numbers in memory that you'd like to add.
Lets assume that you have five numbers whose length is one word
[Link] want their sum to be written in register [Link] easiest
way to do this is:

;(4.1A)
adding1:
clr.l D0 ;Erase D0 (=0)
move table,d0 ;First entry in D0
add table+2,d0 ;Add second entry
add table+4,d0 ;Add third entry
add table+6,d0 ;Add fourth entry
add table+8,d0 ;add fifth entry
rts ;Return to main program
table: dc.w 2,4,6,8,10,
end

Try out the program using the debugger by single stepping thru the
program until you get to the RTS instruction(left Amiga T).(SEKA
owners use "j adding1").You see that data register D0 really
contains the sum of the values.
The method above only reads and adds numbers from a particular set
of [Link] Amigas processor has lots of different sorts of
addressing modes that give us a shorter and more elegant solution.
Lets add a variable to the address of the table,so that the
program can add different tables.
Lets put the addresses of the table in an address register(for
example, A0)[Link] register can be used as a pointer to the
[Link] must use move.l since only long words are [Link]
using a pointer to a table you can use indirect [Link] can
change the expression "table+x" to"x(A0)".

;(4.1B)
adding1:
clr.l D0 ;Erase D0 (=0)
move.l #table,a0 ;Put table addresses in A0
move 0(a0),d0 ;Put first entry in d0
add 2(a0),d0 ;Add second entry
add 4(a0),d0 ;Add third entry
add 6(a0),d0 ;Add forth entry
add 8(a0),d0 ;Add fifth entry
rts ;Return to main program]
table: dc.w 2,4,6,8,10
end

Assemble this program,load it into the [Link] single step


(left Amiga T)thru this program and you'll see that this program
adds five numbers in order just like the last [Link] reason you
used a step size of two for the ofset is that words are two bytes
[Link] also defaults to relocate code so that you must move
#table as a long word.
Lets improve the program more by using "(a0)+"instead of "x(a)".
This way,every time you access elements of the table,the address
register A0 is automatically incremented by the number of bytes
that are read(in this case two).The difference between this and
the last example is that here the registers contents are modified.
The pointer is to the next unused byte or word in memory.
Lets make it even [Link] make the number of words to be added
to a [Link]'ll pass the number in register [Link] you need
to do a different sort of programming,since you can't do it with
the old methods.
Lets use a [Link] need to add D1 [Link] can use(a0)+ as the
addressing method(address register indirect with post increment),
since this automatically gets you to the next word.
Now for the [Link]'ll have D1 decremented by one every time the
contents of the pointer are [Link] D1 is zero,then you're done.
Otherwise,you need another [Link] program looks like this:

;(4.1C)
adding2:
clr.l d0 ;Erase D0
move.l #table,a0 ;Put table addresses in A0
move #$5,d1 ;Put number of entries in D1

loop: ;Label for loop beginning


add (a0)+,d0 ;Add a word
subq #1,d1 ;Decrement counter
bne loop ;Continue if non-zero
rts ;Else done

table: dc.w 2,4,6,8,10


end

Lets take a close look at this [Link] the pointer A0 with


the addresses of the data and the counter D1 with the number of
[Link] you can single step thru the program and watch the
[Link] sure not to run the final command,the RTS command,
because otherwise a return address is popped from the stack,and
the results of this are unpredictable.(SEKA owners can use"x pc"
to point the program counter to "adding2".You can then step thru
the program by using the "s"command and watch the results).
To finish up this example,your assigning a little [Link]
the program so that it adds single bytes or long [Link] to
write a program that takes the first value in a table and
subtracts the following [Link] example,the table

table: dc.w 50,8,4,6

should return the value 50-8-4-6, ie 32 ($20).

[Link] a Table.
-------------------
Lets keep working with [Link] don't want to just read data
from one this [Link] want to change [Link]'ll assort the table
in assending order.
You need to decide how to do the [Link] simplest method is to
do the following.
Compare the first and the second [Link] the second value is
larger than the first one,things are OK so [Link] the next step,
compare the second and third values,and so [Link] you come to the
final pair and in each case the preceding value was smaller than
the following value,then the sorting is done(it was unnescessary).
If you find a pair where the second value is smaller than the
first,the two values are [Link] then get a flag(here let's
use a register)that is checked once you're done going thru the
[Link] it is set,the table probably isn't completely [Link]
then erase the flag and start again from the [Link] the flag
is still zero at the end,the sorting is complete.
Now let's write a program to do [Link] let's figure out the
variables you [Link]'ll use registers for the [Link] need
a pointer to the table you're sorting(A0),a counter(D0)and a flag
(D1).While the program is running,change these values,so you'll
need two more registers to store the starting values(address and
the number of the table entries).You'll use A1 and D2.
Let's start writing the program,each section will be written and
then [Link] the complete program will be [Link] put the
tables address in A1 and the number of entries in D2.

;(4.2A) part of sort routine


sort: ;Start address of the program
move.l #table,a1 ;Load pointer with address
move.l a1,a0 ;Copy pointer to working register
move.l #5,d2 ;Number in the counter
move.l d2,d0 ;Copy number of elements
subq #2,d0 ;Correct conter value
clr d1 ;Erase flag

table: dc.w 3,6,9,5

end

Now the preparations are [Link] pointer and the counter are
ready and the flag is [Link] counter is decremented by two
because you want to use the DBRA command(take one off)and only X-1
comparrisons are needed for X numbers(take off one more).
Next let's write the loop that compares the [Link] compare one
word with [Link] looks like this:

loop:
move 2(a0),d3 ;Next value in register D3
cmp (a0),d3 ;Compare values

You need to use register D3 because CMP (A0),2(A0) isn't a legal


[Link] the second value is greater than or equal to the first
value,you can skip an exchange.

bcc noswap ;Branch if greater than or equal


;to

Now you need to do the exchanging(unfortunatly you can't use EXC


2(a0),(a0) since this form of addressing does not exist).

doswap:
move (a0),d1 ;Save first valus
move 2(a0),(a0) ;Copy second into first word
move d1,2(a0) ;Move first into second
moveq #1,d1 ;Set flag
noswap:

Now increment the counter and continue with the next [Link] do
this until the counter is negative.

addq.l #2,a0 ;Pointer+2


dbra d0,loop ;Continuing looping until the end
Now you'll see if the flag is [Link] start again at the beginning
if it is.

tst d1 ;Test flag


bne sort ;Not finished sorting yet!
rts ;Otherwise [Link]

If the flag is zero,you're done and the subroutine [Link] jump


back to the main program using the RTS command.
Now a quick overview of the complete program.

;(4.2B)
sort: ;Start address of the program
move.l #table,a1 ;Load pointer with address
move.l a1,a0 ;Copy pointer to working register
move.l #5,d2 ;Number in the counter
move.l d2,d0 ;Copy number of elements
subq #2,d0 ;Correct counter value
clr d1 ;Erase flag

loop:
move 2(a0),d3 ;Next value in register D3
cmp (a0),d3 ;Compare values
bcc noswap ;Branch if greater than or equal to

doswap:
move (a0),d1 ;Save first value
move 2(a0),(a0) ;Copy second into first word
move d1,2(a0) ;Move first into second
moveq #1,d1 ;Set flag

noswap:
addq.l #2,a0 ;Pointer+2
dbra do,loop ;Continue looping until the end
tst d1 ;Test flag
bne sort ;Not finished sorting yet!
rts ;Otherwise [Link]

table:
dc.w 10,8,6,4,2 ;When finished acceding

end

To test this subroutine,assemble the routine with AssemPro,save it


and then load it into the [Link] table is directly after the
RTS,notice its [Link] a breakpoint at the RTS,select the
address with the mouse and press left-Amiga-B sets a breakpoint in
[Link] the program the redisplay the screen by selecting
"Parameter-Display-Dissassem-bled"and examine the order of the
numbers in the table,they should now be ascending order.
You use several registers in this example for storing values.
Usually in machine language programming your subroutines cannot
change any register or can only change certain [Link] this
reason,there is a machine language command to push several
registers onto the stack at the same [Link] is the MOVEM ("MOVE
multiple")[Link] you insert this command twice in your program
then you can have the registers return to the main program with
the values they had when the subroutine was [Link] do this,you
need one more [Link]'s call it"start";the subroutine is started
from here.

start:
movem.l d0-d7/a0-a6,-(sp) ;save registers

sort:
etc...
...
...
bne sort ;not finished sorting yet!

movem.l (sp)+,d0-d7/a0-a6 ;retrieve registers


rts ;finished

The powerful command moves several registers at the same [Link]


can specify which registers should be [Link] you want to move
the D1,D2,D3,D7,A2 and A3 registers,just write

movem.l d1-d3/d7/a2-a3,-(sp)

Before you quit sorting,do one little homework [Link]


the program,so that it sorts the elements in descending order.

[Link] Number Systems.


-----------------------------
As we mentioned in the chapter on number systems,converting
numbers from one base to another can be rather [Link] is
another form of numeric representation-as a string that can be
entered via the keyboard or output on the screen.
You want to look at some of the many conversions possible and
write programs to handle the [Link]'ll start by converting a hex
number into a string using binary numbers and then print the value
in hex.

[Link] Hex To ASCII.


-----------------------------
First you need to set the start and finish [Link] this
example,let's assume that data register D1 contains a long word
that should be converted into a 8-digit long string of ASCII
[Link]'ll write it to a particular memory location so that
you can output it later.
The advantage of using hex instead of decimal is pretty clear in
this [Link] find out the hexadecimal digit for a particular
spot in the number,you just need to take the corresponting 4 bits
(half byte)and do some work on it.A half byte(also called a
nibble)contains one hex digit.
You'll work on a half byte in [Link] convert this to a printable
character,you need to use the correct ASCII [Link] codes of the
16 characters that are used as hex digits are the following:

0 1 2 3 4 5 6 7 8 9 A B C D E F

$30 $31 $32 $33 $34 $35 $36 $37 $38 $39 $41 $42 $43 $44 $45 $46

To convert the digits 0-9,you just need to add $[Link] the letters
A-F that correspond to the values 10-15,you need to add $[Link]
program to evaluate a half byte must make a destinction between
values between 0 and 9 and those between A and F and add either
$30 or $37.
Now let's write a machine language subroutine that you'll call for
each digit in the long words hex representation.

nibble:
and #$0f,d2 ;just keep low byte
add #$30,d2 ;add $30
cmp #$3a,d2 ;was it a digit?
bcs ok ;yes:done
add #7,d2 ;else add 7

ok:
rts ;done

This routine converts the nibble in D2 to an ASCII character that


corresponds to the hex value of the [Link] convert an entire
byte,you need to call the routine [Link] is a program to do
[Link] program assumes that A0 contains the address of the
buffer that the characters are to be put in and that D1 contains
the byte that is converted.

;(4.3.1a) bin-hex
; ;your program
lea buffer,a0 ;pointer to buffer
move #$4a,d1 ;byte to be converted(example)
bsr byte ;and convert
rts
; ... ;more of your program
byte:
move d1,d2 ;move value into d2
lsr #4,d2 ;move upper nibble into lower nibble
bsr nibble ;convert d2
move.b d2,(a0)+ ;put character into buffer
move d1,d2 ;value in d2
bsr nibble ;convert lower nibble
move.b d2,(a0)+ ;and put it in buffer
rts ;done
nibble:
and #$0f,d2 ;just keep low byte
add #$30,d2 ;add $30
cmp #$3a,d2 ;was it a digit?
bcs ok ;yes:done
add #7,d2 ;else add 7
ok:
rts ;done
buffer:
blk.b 9,0 ;space for long word data

end

To test this subroutine,use AssemPro to assemble the routine,save


the program and load it intoi the [Link] set a breakpoint
at the first RTS,to set the breakpoint in AssemPro select the
correct address with the mouse and press the right-Amiga-B keys.
Start the program and watch the contents of D2,it is first $34
(ASCII 4)and finally $41(ASCII A).Select "Parameter-Display-HEX-
Dump"and you'll see that 4A has been moved into the buffer.
This is how the routine [Link],you move the value that you
wish to convert into [Link] you shift the register four times to
the right to move the upper nibble into the lower four [Link]
the subroutine call,you use "move.b d2,(a0)+"to put the HI nibble
in the [Link] the original byte is put in D2 [Link] is
[Link] gives us the LO nibble as an ASCII character in D2.
You put this in the next byte of the buffer.
The buffer is long enough to hold a long word in characters and
closing the null [Link] null byte is usually required by screen
output [Link] output will be discussed in a later
[Link] let's worry about converting a long word.
When converting a long word,you need to be sure to deal with the
nibbles in the right [Link] calling the "nibble"routine for
the first time,you need to move the upper nibble into the lower 4
bits of the long [Link] need to do this without losing anything.
The LSR command isn't very good for this [Link] you use it
you'll lose [Link] better to use the rotation commands like ROR
or ROL,since they move the bits that are shifted out,back in on
the other side.
If you shift the original long word in D1 four times to the left,
the upper four bits are shifted into the lower four [Link] you
can use our "nibble"routine to evaluate it and then put the
resulting ASCII character in the [Link] repeat this eight
times and the whole long word has been [Link] even have D1
looking exactly the way it did before the conversion process began

;(4.3.1B) bin-hex-2
hexlong:
lea buffer,a0 ;pointer to the buffer
move.l #$12345678,d1 ;data to convert
move #7,d3 ;counter for the nibbles:8-1

loop:
rol #4,d1 ;move upper nibble into lower
move d1,d2 ;write in d2
bsr nibble ;and convert it
move.b d2,(a0)+ ;character in buffer
dbra d3,loop ;repeat 8 times
rts ;finished!

nibble:
and #$0f,d2 ;just keep low byte
add #$30,d2 ;add $30
cmp #$3a,d2 ;was it a digit?
bcs ok ;yes:done
add #7,d2 ;else add 7

ok:
rts ;done

buffer:
blk.b 9,0 ;space for long word,null byte

end

To test this subroutine,use AssemPro to assemble the routine,save


the program and load it into the [Link] set a breakpoint at
the first RTS,to set the breakpoint in AssemPro select the correct
address with the mouse and press the right-Amiga-B [Link] the
program and when it is finished redisplay the output by selecting
"Parameter-Display-HEX-dump"so you can examine the new buffer
contents.
You'll find that there's an error in the program-the buffer
contains the digits "56785678"instead of "12345678".Try to find
the error.
Have you found it?This is the sort of error that causes you to
start pulling your hair [Link] sort is hard to [Link]
assembler assumes that the rotation operation should be done on a
word,because the ".l"was left [Link] a result,only the lower word
of D1 was rotated-so you get the same value [Link] you change
the "rol.l",things work just right.
The error shows how easy it is to convert the program above into
one that converts four digit hex numbers into ASCII characters.
Just leave off the ".l"on the "rol"command and change the counter
from seven to [Link] program is done.
Now for a little homework:change the program so that it can handle
six digit hex numbers(D1 doesn't nescessarily have to stay the
same...)!
Now lets look at a different conversion problem:converting a four
digit decimal number.

[Link] Decimal To ASCII.


---------------------------------
It's not quite as easy to convert decimal as [Link] can't group
the bits to form individual [Link] need to use another method.
Lets look at how a decimal number is [Link] a four digit
number,the highest place is in the thousands place,the next is the
hundreds place,etc...
If you have the value in a register and divide by 1000,you'll get
the value that goes in the highest place in the decimal number.
Since the machine language command DIV not only gives us the
result of the division but also gives us the remainder,you can
work out the remainder quite [Link] divide the remainder by
100 to find the hundreds place,divide the remainder by 10 and get
the tens place,and the final remainder is the ones place.
This isn't so hard after all!Heres the program that follows the
steps above to fill the buffer with D1's ASCII value.

main:
lea buffer,a0 ;pointer to the buffer
move #1234,d1 ;number to convert
jsr deci_4 ;test subroutine
illegal ;room for breakpoint

deci_4: ;subroutine-four digit numbers

divu #1000,d1 ;divide by 1000


bsr digit ;evaluate result-move remainder

divu #100,d1 ;divide by 100


bsr digit ;evaluate result and move

divu #10,d1 ;divide by 10


bsr digit ;evaluate result-move remainder

;evaluate the remainder directly

digit:
add #$30,d1 ;convert result into ASCII
move.b d1,(a0)+ ;move it into buffer
clr d1 ;erase lower word
swap d1 ;move the remainder down
rts ;return

buffer:blk.b 5,0 ;reserve bytes for result

end

To test this subroutine,use AssemPro to assemble the routine,save


the program and load it into the [Link] set a breakpoint at
the illegal [Link] set the breakpoint in AssemPro select
the correct address with the mouse and press the right-Amiga-B
[Link] breakpoint stops the [Link] the program and when
it is finished redisplay the output by selecting"Parameter-Display
-HEX-dump"so you can examine the ASCII values now in the buffer.
You use a little trick in this program that is typical for machine
language [Link] calling"digit"three times from the sub-
routine"deci_4",you go right into the"digit"[Link] don't
use a BSR or JSR [Link] the processor hits the RTS command,
it returns to the main program,not the "deci_4"[Link]
this,you save a fourth "bsr digit"command and an "rts"command for
the "deci_4"routine.
Try the program [Link] sure that you use values that are smaller
than 9999,because otherwise strange things can happen.
Now let's reverse what you've been doing and convert strings into
binary numbers.

[Link] ASCII To Hex.


-----------------------------
In a string,each hex digit represents a half [Link] just need to
write a program that exactly reverses what the hex conversion
program did.
You have two choices

1. The number of hex digits is known in advance


2. The number is unknown

The first is easier to program,but has the disadvantage that if,


you assume the strings are four digits in length and want to enter
the value 1,you must enter [Link] is rather awkward,so you'll
use the second method.
Let's convert a single digit [Link]'ll pass a pointer to this
digit in address register [Link] want the binary value to come
back in data register D0.
The program looks like this:

move.l #string,a0 ;this example


jsr nibblein ;test routine
nop ;set breakpoint here

nibblein: ;*convert the nibble from (A0)


clr.l d0 ;erase D0
move.b (a0)+,d0 ;get digit,increment A0
sub #'A',d0 ;subtract $41
bcc ischar ;no problem:in the range A-F

add #7,d0 ;else correct value


ischar:
add #10,d0 ;correct value
rts

string:dc.b 'B',0 ;character to convert

end

To test this subroutine,use AssemPro to assemble the routine,save


the program and load it into the [Link] set a breakpoint at
the first NOP,to set the breakpoint in AssemPro select the correct
address with the mouse and press the right-Amiga-B [Link] the
program and watch the contents of D0.
Let's see how the program works.A0 points to a memory location
that contains the character "B"that is represented by the ASCII
value $[Link] number is loaded into D0 right after this register
is erased.
After subtracting $41,you end up with the value $[Link] you're
almost [Link] returning to the main program,you add 10 to get
the correct value 11,$B.
If the buffer has a digit in it,the subtraction causes the
register to become [Link] C flag is [Link]'s take the digit
5 as an example.
The ASCII value of 5 is $[Link] subtracting $41,you end up with
-12 and the C flag is [Link] this case,you won't branch with the
BCC [Link] you'll add 7 to get -[Link] 10 is added,and
you end up with [Link]!
The routine as a [Link] an illegal character is given,one
that doesn't represent a hex digit,you'll get some nonsense result
Let's ignore error checking for the moment though.
Let's go on to multi-digit hex [Link] first digit that you
convert has the highest value and thus represents the highest
[Link] allow for this and to allow for an arbitrarily long
number(actually not arbitrarily long,the number should fit in a
long word-so it can only be eight digits long),you'll use a trick.
Take a look at the whole [Link] handles the calculations and
puts the result in [Link] assumes that A0 is a pointer to a string
and that this string is ended by null byte.

hexin: ;converting a hex number


clr.l d1 ;first erase D1
move.l #string,a0 ;address of the string in A0
jsr hexinloop ;test subroutine
nop ;set breakpoint here

hexinloop:
tst.b (a0) ;test digit
beq hexinok ;zero,then done
bsr nibblein ;convert digit
lsl.l #4,d1 ;shift result
or.b d0,d1 ;insert nibble
bra hexinloop ;and continue

hexinok:
rts

nibblein:
clr.l d0 ;convert the nibble from (A0)
move.b (a0)+,d0 ;get digit,increment A0
sub #'A',d0 ;subtract $41
bcc ischar ;no problem:in range A-F
add #7,d0 ;else correct value

ischar:
add #10,d0 ;correct value
rts

string:DC.B "56789ABC',00 ;eight digit string,null byte


;to be converted
end

To test this subroutine,use AssemPro to assemble the routine,save


the program and load it into the [Link] set a breakpoint at
the NOP,to set the breakpoint in AssemPro select the correct
address with the mouse and press the right-Amiga-B [Link] the
program and watch the contents of D1,the hex value is placed in
this register.
The trick is to shift left four times,to shift one [Link] this
way,the place of the last digit is incremented by one and there is
room for the nibble that comes back from the "nibblein"[Link]
program uses the TST.B instruction to check for the null byte at
the end of the string,when it encounters the null byte the program
[Link] result is in the D1 long word already!
To do some error checking,you need to make some changes in the
[Link]'ll do this right after you come back from the"nibblin"
routine with the value of the current character.
If the value in D0 is bigger than $F,there is an [Link] can
detect this in several [Link] chose the simplest one-you'll use
CMP #$10,D0 to compare D0 with $[Link] it smaller,then the C flag
is set(since CMP uses subtraction)and everything is [Link] C is
zero,there is an error.
You can use this trick to skip the test for a null byte,since its
an invalid character as [Link] program looks like this:

;(4_3_3C) hex-conv2 optional disk name


hexin: ;converting a hex number
clr.l d1 ;first erase D1
move.l #string,a0 ;address of string in A0
jsr hexinloop ;test subroutine
nop ;set breakpoint here

hexinloop:
bsr nibblein ;convert digit
cmp $10,d0 ;test if good
bcc hexinok ;no,then done
lsl.l #4,d1 ;shift result
or.b d0,d1 ;insert nibble
bra hexinloop ;and continue

hexinok:
rts

nibblein: ;convert the nibble from (A0)


clr.l d0 ;erase D0
move.b (a0)+,d0 ;get digit,increment A0
sub #'A',d0 ;subtract $41
bcc ischar ;no problem:in the range A-F
add #7,d0 ;else correct value
ischar:
add #10,d0 ;correct value
rts

string:DC.B "56789ABC',00 ;8 digit string ending with a


;null byte to be converted
end

To test this subroutine,use AssemPro to assemble the routine,save


the program and load it into the [Link] set a breakpoint at
the NOP,to set the breakpoint in AssemPro select the correct
address with the mouse and press the right-Amiga-B [Link] the
program and watch the contents of D1,the hex value is placed in
this register.
This is the method for converting hex to [Link] you convert
decimal to binary,the conversion is not much harder.

[Link] ASCII To Decimal.


---------------------------------
You can use a very similar method to the one used [Link] you
are not sure how many digits there are,you'll use a similar method
for putting digits of a number in the next place [Link] can't do
this with shifting,but you can multiply by 10 and add the value of
the digit.
Heres the program for converting decimal numbers.

decin: ;converting a decimal number


clr.l d1 ;first erase D1
move.l #string,a0 ;the string to convert
jsr decinloop ;test subroutine
nop ;breakpoint here

decinloop:
bsr digitin ;convert digit
cmp #10,d0 ;test,if valid
bcc decinok ;no,then done
mulu #10,d1 ;shift result
add d0,d1 ;insert nibble
bra decinloop ;and continue

decinok:
rts ;end of conversion

digitin: ;converting the nibble from (A0)

clr.l d0 ;erase D0
move.b (a0)+,d0 ;get digit,increment A0
sub #'0',d0 ;subtract $30
rts

string:dc.b '123456' ;ASCII decimal string to convert

end

To test this subroutine,use AssemPro to assemble the routine,save


the program and load it into the [Link] set a breakpoint at
the NOP,to set the breakpoint in AssemPro select the correct
address with the mouse and press thr right-Amiga-B [Link]
"Parameter-Output-numbers-Decimal"so the registers are displayed
as decimal [Link] start the program and watch the contents
of D1,the decimal value is placed in this register.
This program can ONLY convert numbers upto 655350,although the hex
conversion routine can go [Link] because the MULU command
can only multiply 16-bit [Link] last multiplication that can be
done correctly is $FFFF*10--65535*10,which gives us the value
[Link] this is a large enough range,so you won't
complicate the program further.

CHAPTER 5.
---------
[Link] Registers.
--------------------
You can get information about hardware functions without using
library [Link] can use the hardware registers [Link]
are memory locations at particular addresses that are neither in
RAM nor in [Link] are direct interfaces between the processor
and its peripheral devices.
Each device has a number of hardware registers that the processor
accesses to control graphics,sound and input/[Link] are lots
of possibilities for assembly language [Link]'ll only be
able to go into a few examples.
The registers are generally used in byte-wise [Link]'ll find
an example in the next chapter.

[Link] For Special Keys.


-----------------------------
Load AssemPro and enter the debugger,select "Parameter-Display-
From-Address"and enter $[Link] select "Parameter-Display-Hex
-Dump"to display the memory.(To use the SEKA assembler or a similar
monitor program,enter "q $bfec00".)
Yoy'll see a byte-wise listing of the addresses starting at
$BFEC00 in which two bytes always [Link] two bytes represent
the status of the two hardware registers.
The mirroring occurs because not all the address bits are used in
decoding the [Link] addressing this register,only the upper
two bytes of the address and the low bit,bit 0,are [Link]
address of the two registers goes like this:$BFECxx,where the
lower address byte xx doesn't contain any information in bits 1-7.
Only bit 0 contains information about the desired [Link]'ll
find this odd form of addressing with most hardware registers.
Let's look at the information in these [Link]'s look at the
second register,$[Link] down the<ALT>key and select"Parameter
-Display-HEX-Dump"to redisplay the screen.(SEKA owners must enter
"q $bfec00"and press the<ALT>key right after pressing the<Return>
key.)You'll see that contents of every two bytes($BFEC01,$BFEC03,
etc...)have been changed to $[Link] is the status of the special
[Link] is also true for the other special [Link] following
keys produce the bytes:

Shift left $3F


Shift right $3D
Control $39
Alternate $37
Amiga left $33
Amiga right $31

You can use this register to have a machine language program check
if one of these keys was pressed and then respond by calling or
ending a function.A program section might look like this:

skeys=$bfec01
...
cmp.b #$37,skeys ;Alternate pressed?
beq function1 ;Yes!
cmp.b #$31,skeys ;or right Amiga?
beq function2 ;Yes!
... ;and so on...

[Link].
----------
If you want to find out how much time elapsed between two events,
you can use a hardware register to keep track of time quickly and
[Link] Amiga contains just such a timekeeper:the I/O port
[Link] chip has a 24 bit wide counter that has a 60 Hertz
clock.
These 24 bits can't be read at once,for instance with a MOVE.L
command,because the register is divided into three [Link] low
byte is at address $BFE801,the middle at $BFE901,and the high byte
with bits 16-23 at $BFEA01.
Here's an example of a way to use this register:finding out how
long a subroutine takes to run.

test:
bsr gettime ;put current time in D7
move.l d7,d6 ;save it in D6
bsr routine ;routine to be timed
bsr gettime ;get the time again
sub.l d6,d7 ;elapsed time in
... ;1/50 seconds in D7!
nop ;set break point here to stop

routine: ;test routine


move #500,d0 ;delay counter

loop:
dbra d0,loop ;count down
rts

gettime:
move.b $bfea01,d7 ;hi-byte in D0
lsl.l #4,d7 ;shift twice by 4 bits
lsl.l #4,d7 ;(8 bits shifted)
move.b $bfe901,d7 ;get mid-byte
lsl.l #4,d7
lsl.l #4,d7 ;shift again
move.b $bfe801,d7 ;get the lo-byte
rts ;done

[Link] The Mouse-Joystick.


-------------------------------
There are two hardware registers for the mouse and the joystick.
They contain the state(or the position)of these input [Link]
interesting that the same port is used with both the mouse and the
joystick even through they work completely different.
The joystick as four switches that are closed during movement and
give off a potential(-)that is related to the movement of the
joystick/[Link] mouses movements give off lots of quick signals
-two for horizontal and two for vertical movements.
The computor must keep an eye on the ports so that it can evaluate
the signals and calculate the new mouse [Link] isn't the
work of the processor though;it already has too much to do.
You find the status of the mouse/joystick port at address $DFF00A
for port 1 and $DFF00C for port [Link] information in these words
is for vertical mouse movement in the lower byte and for
horizontal movement in the upper byte.
AssemPro owners be careful!Don't read these addresses,because for
some reason that causes the computor to [Link] looks
interesting(the screen begins to dance)but you can only recover by
pressing <RESET>and losing all your data.
To read this register,lets write a short program:

;(5.3A) mouse

test:
jsr run ;test subroutine
jmp test ;continue until broken
nop ;breakpoint here

joy= $dff00a

run:
move joy,d6 ;data item 1 in D6
move joy+2,d7 ;data item 2 in D7
jmp run ;rts for SEKA and other

end

If you assemble the program and start breakable in the debugger


(SEKA-"j run"),D6 and D7 contain the contents of the two registers
Move the mouse a bit and watch the register contents.
As you see,the value in D6 is [Link] you just move the mouse
horizontaly,only the upper bytes value is different,if just moved
vertically only the upper byte is different.
You are not getting the absolute position of the mouse pointer on
the [Link] can see that easily by moving the mouse in the
upper left corner,then reading the value by restarting the program
and moving the mouse left [Link] you can see,the registers
contents are always relative.
Change the program as follows:

;(5.3B) mouse difference

test:
jsr run ;test subroutine
jmp test ;continue until broken
nop ;breakpoint here

joy= $dff00a

run:
move d7,d6 ;old position in D6
move joy,d7 ;new position in D7
sub d7,d6 ;difference in D6
jmp run ;rts for SEKA and other
end

Start Breakable(right-Amiga-A)in the AssemPro debugger and watch


D6,the result is zero or D7.(SEKA owners have to start the program
two [Link] result in D6 is zero.)If you move the mouse,D6
contains the difference between the old and new positions since
the [Link]'ll find the vertical and horizontal positions of the
mouse relative to the last time you [Link] this way,you can use
this register to find the relative mouse movement between two
checks.
Now to check the [Link] a joystick in port 2 and change the
address $DFF00A to $DFF00C in the [Link] Breakable in the
AssemPro debugger and watch D6,the result is zero or D7.(SEKA
owners have to start the program two [Link] result in D6 is
zero.)
Move the joystick [Link]'ll get the value $[Link] was subtracted
from the upper [Link] the joystick [Link] time you get the
value $100-one is [Link]'ll get the same effect if you move the
joystick left-after you let go,one is subtracted.
The individual movements and their effects on the joystick program
are:

UP $FF00 HI-BYTE -1
DOWN $FFFF LO-BYTE -1
LEFT $0100 HI-BYTE +1
RIGHT $0001 LO-BYTE +1

These values aren't terribly [Link] you move the joystick a


lot and then look at the value,you'll find a crazy value in D6.
This is because the input driver thinks that a mouse is attached.
Nevertheless,this is the quickest way to read a [Link] this
way,an external device that gives off evaluatable TTL signals can
be connected to the port and watched by a machine language
program.
Now you just need to find out whether the fire button has been
pressed,and you'll know how to get all the information you need
from the [Link] buttons state is in bit 7 of the byte that
is in memory location $[Link] the bit is set,the button was'nt
[Link]'s true for the joystick connected to port [Link] 6 of
this byte contains the buttons state when the joystick is in port
1 or the state of the left mouse button.
Let's stay on port [Link] can test bit 7 to execute a function when
the joystick button is pressed without any [Link] 7 is the
sign [Link] can use this program segment:

tst.b $bfe001 ;was fire button 2 hit?


bpl fire ;yes!branch

The TST.B instruction tests the addressed byte and sets the Z and
the N [Link] the N flag is set,you know that bit 7 of the tested
byte is [Link] the fire button turns on LO potential,the bit is
erased when the button is [Link] N flag works that way with
the TST command as [Link] BPL command in the program above
branches if the button was [Link] PL stands for plus and is
set when the sign bit is cleared.
Here is the complete program to check the fire button and joystick
difference:

;(5.3C) fire button and joy difference


test:
jsr run ;test subroutine
tst.b $bfe001 ;was fire button 2 hit?
bpl fire ;yes! branch
jmp test ;continue until broken

joy = $dff00a
run:
move d7,d6 ;old position in D6
move joy,d7 ;new position in D7
sub d7,d6 ;difference in D6
jmp run ;rts for SEKA and other

fire:
nop ;breakpoint here

end

[Link] Production.
-------------------
It's fun to make noises and [Link] Amiga lets you use Audio
Devices and various I\O structures to play tones,noises and/or
music pieces in the [Link]'ll leave this method to C or
Basic programmers,since you can use short machine language
programs to directly program the audio hardware.
The Paula chip has all the capabilities needed for tone production
This chip can be accessed using the hardware registers of the
[Link] library of any high level language can do more than
you can-program the chip.
How does it work?Since the disk uses Direct Memory Access(DMA)to
get information,you just need to tell it where to look for the
tone or tone sequences that you would like [Link] also need to
tell it how to interpret the data.
Lets start with the easiest case-producing a constant tone.A tone
like this consists of a single oscillation that is repeated over
and [Link] you make a diagram of the oscillation,you see the wave
form of the [Link] are several standard waves: sine,
square,triangle and saw [Link] simplest is the square wave.
To produce a square wave,you just need to turn the loud speaker on
and [Link] frequency that occurs here is the frequency of the
tone.
You want to produce such a tone using the [Link] you need to
make a table that contains the amplitude of the tone you wish to
[Link] a square wave,you only need two entries in the table,a
large and a small [Link] the sound chip in the Amiga has
amplitude values between -128 and +127,our table looks like this:

soundtab:
dc.b -100,100

You need to give the address of the table to the sound [Link]
have four choices,since the Amiga as four sound [Link]
address of the hardware register in which the table address for
channel 0 must be written is $DFF0A0;for channel 1 it is $DFF0B0;
for channel 2 its $DFF0C0;for channel 3 its $[Link] stereo
output,channels 0 and 3 control the left loud [Link] 1
and 2 control the right loud [Link] example,choose channel 0
and write the following:
move.l #soundtab,$DFF0A0 ;address of the table

Next you need to tell the sound chip how many items there are in
the [Link] data is read from beginning to end and sent to the
loud [Link] it reaches the end,it starts over at the
[Link] the sound chip gets this one word at a time,even
though the data is in bytes,the table must always have an even
number of [Link] length that you give it is the number of words
the number of bytes/2.
You put the length for channel 0 in the register at address
$DFF0A4(for channel x just add x*$10!):

move #1,$dff0a4 ;length of table in words

Now you have to tell it how quickly to read the data and output it
to the loud [Link] word determines the [Link],it
does this "backwards".The larger the value,the lower the frequency
Choose the value 600 for this example:

move #600,$dff0a6 ;read in rate

Now you need to decide the loudness level for the tone or noise.
You have 65 different levels to choose [Link] choose the middle
value 40 for our example:

move #40,$dff0a8 ;loudness level

Thats the data that the sound chip needs to produce the tone.
However nothing happens [Link] next?The chip can't tell if the
data thats in the registers is valid,so it doesn't know if it
should use the data.
You need to work with the DMA control register at address $DFF096
to let it [Link] only need six bits of this word for your
purposes:

Bit 15 ($8000) If this bit is set,every bit that is written to


this internal register is [Link] the bits
are [Link] bits aren't [Link] is very
useful because this word also contains DMA
information for disk operations that should'nt be
changed.

Bit 9 ($200) This bit makes it posible for the chip to access
DMA [Link] you want to start playing the tone,
you need to set this bit.

Bit 0-3 Turn channel 0-3 on when bits are set.

You'll start your tone by setting bits 15,9 and 0:

move #$8000+$200+1,$dff096 ;start DMA

Heres an example of tone production-this time with tone using a


sine wave:

;**Sound Generation using hardware registers** (5.5A)

ctlw = $dff096 ;DMA control


cothi = $dff0a0 ;table address HI
c0tlo = $c0thi+2 ;table address LO
c0tl = $c0thi+4 ;table length
c0per = $c0thi+6 ;read in rate
c0vol = $c0thi+8 ;loudness level

run: ;*Produce a simple tone


move.l #table,c0thi ;table beginning
move #8,c0tl ;table length--8 words
move #400,c0per ;read in rate
move #40,c0vol ;loudness level (volume)
move #$8201,ctlw ;DMA/Start sound
rts

data ;>500K place in CHIP memory


table: ;sound table:sine
dc.b -40,-70,-40,0,40,70,40,0

end

To test this subroutine,use AssemPro to assemble the routine,save


the program and load it into the [Link] set a breakpoint at
the RTS,to set the breakpoint in AssemPro select the correct
address with the mouse and press the right-Amiga-B [Link] the
program and listen to the [Link] need another routine to turn
the tone off,turn your sound down for now.
To turn the tone off,you just need to erase bit 0 of the DMA
control [Link] do this,you just need to write a 0 in bit 15
and all the set bits in this register are [Link] erase bit 0,
just write a one to the memory location:bit 15=0=> bit 0 is erased
Heres a small routine to stop the tone coming from channel 0:

still: ;*turn off tone


move #1,ctlw ;turn off channel 1
rts

Now lets use the routine in a program to produce a short peep tone
that you culd,for instance,use as a key click:

;** Producing a Peep Tone **


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

beep: ;*Produce a short peep tone


move.l #table,c0thi ;table beginning
move #8,c0tl ;table length
move #400,c0per ;read in rate
move #65,c0vol ;volume
move #$8201,ctlw ;Start DMA (sound)
move.l #20000,d0 ;delay counter

loop:
dbra d0,loop ;count down

still:
move #1,ctlw ;turn off tone
rts

table:
dc.b 40,70,90,100,90,70,40,0,-4,0
end

You can play upto four tones at the same time in such a way that
they are independant of each [Link] Amiga also offers another
method of making the sound more interesting:you can modulate the
tone.
Lets produce a siren [Link] could do this by figuring out the
entire sequence and programming [Link],as you can well imagine
thats a lot of work.
Its much easier to use two tone [Link] use channel 1 for
the bass tone and channel 0 for its [Link] 0 needs to
hold the envelope of the siren [Link] needs to give the expanding
and contracting of the tone at the right speed.
You then have two ways that you can have channel zero work with
channel [Link] can control the volume via channel 0,the read in
rate(frequency),or [Link] our example,you'll use frequency
modulation.

Change the program as follows:

;** Modulated sound generation via hardware registers **


ctlw = $dff096 ;DMA control
adcon = $dff09e ;Audio/Disk 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

run:
move.l #table,c0thi+16 ;table start for channel 1
move #8,c0tl+16 ;table length--8 words
move #300,c0per+16 ;read in rate
move #40,c0vol+16 ;volume

move.l #table2,c0thi ;table start for channel 0


move #8,c0tl ;table length
move #60000,c0per ;read in rate
move #30,c0vol ;volume

move #$8010,adcon ;modulation mode:FM


move #$8203,ctlw ;start DMA
rts

still: ;*Turn Off Tone


move #$10,adcon ;no more modulations
move #3,ctlw ;turn off channels
rts

table: ;data for basic tone


dc.b -40,-70,-90,-100,-90,-70,-40,0
dc.b 40,70,90,100,90,70,40,0

table2: ;data for modulation


dc.w 400,430,470,500,530,500,470,430

end

When you start the program,you'll here a [Link] can change this
tone to your hearts content.
Did you notice the added "adcon"[Link] register controls
the modulation of the audio channel as well as handling disk
[Link] same technique is used here as for the DMA control
register,bits can only be set if bit 15 [Link] a result,you don't
have to worry about the disk bits.I'd recommend against
experimentation.
Control bit 15 isn't the only one of interest to [Link] can also
use bits 0-7,because they determine which audio channel modulates
another [Link] is a restriction,though.A channel can only
modulate the next higher numbered [Link] this reason you use
channel 1 for the basic tone and channel 0 for the modulation in
the [Link] can't for example,modulate channel three with
channel [Link] 3 can't be used to modulate any other
channel.

Here is an overview of bits 0-7 of the "adcon"register.

Bit Function
-----------------------------------------------------------------
0 Channel 0 modulates the volume of channel 1
1 Channel 1 modulates the volume of channel 2
2 Channel 2 modulates the volume of channel 3
3 Turn of channel 3
4 Channel 0 modulates the frequency of channel 1
5 Channel 1 modulates the frequency of channel 2
6 Channel 2 modulates the frequency of channel 3
7 Turn off channel 3

In the example,you set bit 4,which put channel 0 in charge of


channel one's frequency modulations.
When you've chosen a channel for use in modulating another channel
some of the parameters of the channel [Link] don't need to
give volume for this channel,so you can omit [Link] the tables
data is looked at as words instead of as [Link] words are
read into the register of the modulated register at a
predetermined [Link] Read in Rate Register determines the rate.
If you want to modulate the frequency and the volume of another
channel,(In the example,set bits 0 and 4 of "adcon"),the data is
interpreted a little [Link] first word in the table is
the volume,the second is the read in rate,and so [Link] alternates
back and [Link] this way,you can for instance,produce the siren
tone.

[Link] Registers Overview.


-------------------------------
The following tables should give you an overview of the most
important hardware [Link] not enough room to describe
each register,so I'd recommend getting a hold of the appropriate
[Link] you experiment with these registers,you should keep
in mind that this can cause the computor to [Link] your data
to disk and then take the disk out of the drive,because you might
cause the disk drive to execute some wierd functions.
Lets start with the PIA'[Link] covers the PIA type [Link] should
keep in mind that some functions and connection of the 8520 are
integrated into the Amiga and so there are limitations on what you
can do with the PIA's.

PIA A PIA B Registers Meaning


------------------------------------------------------------------
BFE001 BFE000 Data register A
BFE101 BFE100 Data register B
BFE201 BFE200 Data direction register A
BFE301 BFE300 Data direction register B
BFE401 BFE400 Timer A LO
BFE501 BFE500 Timer A HI
BFE601 BFE600 Timer B LO
BFE701 BFE700 Timer B HI
BFE801 BFE800 Event register Bits 0-7
BFE901 BFE900 Event register Bits 8-15
BFEA01 BFEA00 Event register Bits 16-23
BFEB01 BFEB00 Unused
BFEC01 BFEC00 Serial data register
BFED01 BFED00 Interrupt control register
BFEE01 BFEE00 Control register A
BFEF01 BFEF00 Control register B

Some internal meanings:

$BFE101 Data register for parallel interface


$BFE301 Data direction register for the parallel interface
$BFEC01 State of the keyboard,contains the last special key
pressed(Shift,Alternate,Control,Amiga)

Now come the registers that are used for tone [Link] first
two registers should be treated especially carefully-if they are
used wrong,very nasty effects can occur.
These registers can be either read or written [Link]
information is included under R/W in the table.

Address R/W Meaning


------------------------------------------------------------------
DFF096 W Write DMA Control
DFF002 R Read DMA Control and Blitter Status
--Audio Channel 0--
DFF0AA W Data register
DFF0A0 W Pointer to table beginning Bits 16-18
DFF0A2 W Pointer to table beginning Bits 0-15
DFF0A4 W Table length
DFF0A6 W Read in Rate
DFF0A8 W Volume
--Audio Channel 1--
DFF0BA W Data register
DFF0B0 W Pointer to table beginning Bits 16-18
DFF0B2 W Pointer to table beginning Bits 0-15
DFF0B4 W Table length
DFF0B6 W Read in Rate
DFF0B8 W Volume
--Audio Channel 3--
DFF0CA W Data register
DFF0C0 W Pointer to table beginning Bits 16-18
DFF0C2 W Pointer to table beginning Bits 0-15
DFF0C4 W Table length
DFF0C6 W Read in Rate
DFF0C8 W Volume
--Audio Channel 4--
DFF0DA W Data register
DFF0D0 W Pointer to table beginning Bits 16-18
DFF0D2 W Pointer to table beginning Bits 0-15
DFF0D4 W Table length
DFF0D6 W Read in Rate
DFF0D8 W Volume

Now for the registers that contain information about the joystick,
mouse or [Link] addresses have been gone over in part
previously.

Address R/W Meaning


------------------------------------------------------------------
DFF00A R Joystick/Mouse Port 1
DFF00C R Joystick/Mouse Port 2
DFF012 R Potentiometer pair 1 Counter
DFF014 R Potentiometer pair 2 Counter
DFF018 R Potentiometer connection
DFF034 W Potentiometer port direction

Chapter 6
---------
[Link] Operating System.
-----------------------
Now lets take a step forward in your ability to write assembly
language [Link] not enough to put a piece of text in memory
[Link] want to be able to put it on the [Link] you know
how to write a character on the screen?Do you know how to draw a
window on the screen that can be modified by the mouse?Actually
you don't have to have terribly precise knowledge about such
topics.
Fortunately,the Amigas operating system supplies routines that
take care of common tasks like [Link] can seem quite complicated
due to the number of routines [Link] routines are in
[Link]'ll look at the libraries in some depth now.

[Link] Libraries.
-------------------
Before you can use a library,it must be [Link] has to be
loaded into [Link],the whole library must be loaded,
even if you only need one of the functions.
First you need to decide what the program must be able to do,so
you can see which libraries you'll [Link] simple I/O text,you
don't need a library that contains routines for moving graphics!
There are a number of libraries onj a normal Workbench [Link]
an overview of the names and the sort of functions they do:

[Link];
This library is needed to load the other [Link] is already
in memory and doesn't need to be [Link] in charge of basic
functions like reserving memory and working with I/O channels.

[Link];
Contains all the functions for normal I/O operations,for instance
screen or disk access.

[Link];
Used for working with screens,windows,menus,etc...

[Link];
This contains routines for working with the Copper lists that are
used for controlling the screen.

[Link];
Contains graphics routines for text output in console windows.

[Link];
Used for working with the character fonts that are stored on the
disk.

[Link];
This library contains functions to control the Blitter(or graphics
)[Link] used for basic graphics functions.

[Link];
Used in the development and use of workbench symbols(icons).

[Link];
Used for working with screen memory (layers).

[Link];
Contains basic math floating point operations.

[Link];
Contains basic math functions for integers.

[Link];
Contains higher level mathmatical functions.

[Link];
Used for evaluating analog input to the Amiga.

[Link];
Contains routines for time critical [Link] can be used to
program exact time intervals.

[Link];
Contains the single function "Translate",that translates normal
text written phonetically for the narrator,the speech synthesisor.

You can open(load)all these libraries of [Link] should


remember that this takes time and [Link] this reason,you
should always think about which functions you need and which
libraries they are in.
For example,lets say you want to write a program that does text
input/[Link] need the "[Link]",so it can be loaded.
The "[Link]"is in charge of [Link] library contains
the OpenLib function that can be called once you've passed the
needed [Link] Amiga includes all the libraries
necessary for the Amiga,it also includes files that contain the
offsets for the operating system [Link] macros contained in
AssemPro ease assembly language programming [Link] make
the programs in this book useful to the largest audience the
following examples are written for generic assemblers and do not
include AssemPro's [Link] have used the AssemPro ILABEL and the
macros INIT_AMIGA and EXIT_AMIGA so AssemPro owners can start the
programs from the desktop.(If you are using a different assembler
check your documentation for instructions on linking programs).

[Link] Functions.
----------------------
Since this chapter is rather complex we'll first describe the
fundamental routines necessary to use the Amiga's operating system
after a description a complete program is [Link] library
begins in memory with a number of JMP [Link] JMPs branch
to the routines that are in the [Link] call a function,you
need to find the beginning of this JMP table and call function x
by going to the xth JMP [Link] you use an offset to get
to the right JMP [Link],you don't start at the beginning
but at the end of the JMP table,so use negative offsets.
It works out very [Link] lets open the "[Link]"by using
"[Link]'s"base [Link] address is $[Link] call a
fuction from another library,you need to use another base address.
Now you need the offset for the function that you [Link] want
the OpenLib function that has -408 as an [Link]'ll find a list
of function offsets in the appendix.
You need a pointer to the name of the library you are loading for
the OpenLib function(in this case "[Link]")and a long word in
memory that you can use to store the base address of the DOS
[Link] get this back from the OpenLib [Link] need to be
sure to write the library name in lower case letters([Link]),
otherwise you can't open it.I entered a name in capitol letters
once and spent a lot of time finding this error.

The routine looks like this:

;** Load the DOS library '[Link]' (6.2A) **


Execbase = 4 ;base address of the EXEC library
OpenLib = -408 ;offset for the OpenLib function

IoErr = -132 ;offset for IoErr information

init:
move.l Execbase,a6 ;base address in A6
lea dosname,a1 ;address of library name
moveq #0,d0 ;version number
jsr OpenLib(a6) ;open DOS library
move.l d0,dosbase ;save DOS base address
beq error ;if zero,then error!
... ;your program goes here
... ;more program...

error: ;error
move.l dosbase,a6 ;address of library name
jsr IoErr(a6) ;call IoErr for error info
move.l d0,d5
... ;your error routine goes here
rts
dosname: ;name of library to open
dc.b '[Link]',0,0
align ;SEKA uses-even

dosbase: ;storage for DOS base address


blk.l 1

end

This is the way to load the DOS library so that you can use [Link]
library functions are called this [Link] are put in
registers and passed to the [Link] there is an error,when
the function doesn't run correctly,a zero is usually put in data
register D0.
Once your program is done with its work,you need to close the
libraries that are still open before you return to the CLI or
[Link] CloseLib function (offset -414)takes care of this
[Link] function is in the EXEC library just like the [Link]
only parameter it needs is the base address of the library that is
[Link] close "[Link]",do the following:

CloseLib = -414 ; (6.2B)


...
move.l Execbase,a6 ;EXEC base address
move.l dosbase,a1 ;DOS base address
jsr CloseLib(a6) ;close library

[Link] Initialization.
---------------------------
Before you can start a program,you need to initialize many things
so that the program can run.
Lets take an example program that does some text editing.A program
like this must be able to store text,so it needs to be able to
access [Link] also needs to be able to accept keyboard input
and do screen output,so it needs an output window.
To do this,you need to open one or more of the libraries that we
talked about [Link] assume that you've loaded the DOS
library,so that you can do the next steps.

[Link] Memory.
---------------------
There are several ways to get the operating system to assign you a
chunk of [Link] need to use one of them,so that during multi-
tasking,you don't have one program overwriting another programs
memory area.
Lets look at the function that is normally [Link] function is
in the resident EXEC library and has the name AllocMem (offset
-$c6).It reserves a memory area,using the value in D0 as the
[Link] address that the memory area begins at is returned in
the D0 data [Link] it returns zero,the program could'nt give
you that much memory.
You can also use a mode word in D1 to determine whether the memory
area that is reserved should be erased or not.
The routine looks like this:

ExecBase = 4 ; (6.3.1A)
AllocMem = -$c6
...
move.l #number,d0 ;number of bytes to reserve
move #mode,a6 ;mode word
move.l ExecBase,a6 ;DOS base address in A6
jsr AllocMem(a6) ;call function
move.l d0,address ;save memory's start address
beq error ;memory not reserved
...

The second way to reserve memory is to use the AllocAbs function


(offset -$CC).This function in contrast to the AllocMem function
reserves a particular memory [Link] D0 register contains the
number of bytes that should be [Link] register A1
contains the desired start [Link] function returns a zero in
D0 if the memory area can't be reserved.

ExecBase = 4 ; (6.3.1B)
AllocAbs = -$cc
...
move.l #number,d0 ;number of bytes to reserve
lea address,a1 ;desired start address
move.l execbase,a6 ;EXEC base address
jsr AllocAbs(a6) ;reserve memory
tst.l d0 ;everything ok?
beq error ;no!
...

When the program has done its work and must return to the CLI or
the Workbench,it needs to return the memory it as reserved to the
[Link] FreeMem function (offset -$D2) handles this.
The function works like AllocAbs in that the number of bytes is
put in D0 and the start address of the memory area is put in A1.
If you try to free up a memory area that was'nt reserved,you'll
usually crash the computor.
The routine to free up a memory area looks like this:

ExexBase = 4 ; (6.3.1C)
FreeMem = -$d2
...
move.l #number,d0 ;number of bytes released
lea address,a1 ;start address from AllocAbs
move.l ExecBase,a6 ;ExecBase address
jsr FreeMem(a6) ;free up memory
tst.l d0 ;everything ok?
beq error ;no!
...

[Link] a Simple Window.


------------------------------
The title of this chapter may sound a bit [Link],the
differences between the two different methods of opening a window
are so great that they should be handled in seperate chapters.
The method of opening a window presented here is very simple,but
it doesn't allow you to work with all the [Link] gadgets
include the close symbol in the upper left corner of a window and
the size symbol in the lower left corner.
If you open the window in the simple manner,almost all the gadgets
are [Link],the close symbol is [Link] a result,this
method isn't appropriate for every [Link] lets look at
the method.
To open a window,use a function from the DOS library,so you need
to open the library first (see the section "Load Library").This
open function is an all purpose function that can be used for many
[Link] this reason,it makes good sense to put a "open"
subroutine in your [Link] can use it a [Link] do the basic
steps:

;** Load the DOS Library '[Link]' (6.3.2A) **


ExecBase = 4 ;base addres of the EXEC library
OpenLib = -408 ;offset of OpenLib function
Open = -30 ;Offset of the DOS function OPEN

init:
move.l ExecBase,a6 ;base address in A6
lea dosname(pc),a1 ;address of library name
move.q #0,d0 ;version number:unimportant
jsr OpenLib(a6) ;call the function
move.l d0,dosbase ;save DOS base address
beq error ;if zero,then error!
... ;more of your program
... ;now open window,etc...

error:
... ;error occured
... ;your error routine

openfile: ;general open function


move.l dosbase,a6 ;DOS base address in A6
jsr Open(a6) ;call OPEN function
tst.l d0 ;test if ok
rts ;done,evaluate test later

dosname: ;name of library to be opened


dc.b '[Link]',0,0
align ;even

dosbase: ;spot for DOS base address


blk.l 1

You call the Openfile routine,because the label "Open"is already


being used for the [Link] routine calls the Open function
that is in the DOS library.
This isn't [Link] function must be given some parameters
so that it knows what to [Link] parameters are sent in registers
D1 and D2.D1 points to a definition block what specifies what
should be [Link] need to have a filename ended with a null
byte there.D1 must be passed as a long word like all addresses.D2
contains the mode that the function should run [Link] is an old
(1005) and a new (1006) [Link] number must be passed in D2's
long word.
Heres an overview of how windows are [Link],AmigaDos
allows you to use input and output channels in the same [Link]
standard channels are disk files,the console (keyboard and screen)
the printer interface and the serial RS232 interface.
The console input/output is what you'll work with [Link] you
specify the console as the filename of the channel to be opened,a
window is opened automatically.
The name must begin with CON:to do [Link] similar to DF0:for
disk operations.A little more infotmation about the window is
still needed.
You need to specify the X and Y coordinates of the upper left and
lower right corners of the window as well as the name that should
appear in the title line of the window.A complete definition block
for a window like this would appear like the following line:

consolname: dc.b 'CON:0/100/640/100/**Window**',0

To open this window,the line above needs to be inserted in the


following program:

mode_old = 1005

lea consolname(pc),a1 ;consol definition


move.l #mode_old,d0 ;mode
bsr openfile ;console open
beq error ;didn't work
move.l d0,conhandle

rts
...
conhandle: dc.l 1 ;space for handle

There are two points to clear up yet.


You should use mode_old as the the mode when you open a window.
Logically the window doesn't exist before opening so this seems
wierd but it doesn't hurt anything.
The parameter that returns from "openfile"in D0 is zero in the
case of an error,in the case that opening didn't [Link]
the value is the identification number (handle number) of the
opened [Link] need to store it away,because every function
that wants to use this channel must give the handle [Link] the
example,you stored this number in the "conhandle"long word.
As mentioned,the window you've opened doesn't have a close symbol
but it can be made bigger and smaller and moved forward and back.
The manipulations that are carried out using the mouse are
completely taken care of by the Amiga (in contrast to the ATARI ST
where the programmer has to take care of these things).
An important function that uses the handle number is the one that
closes the channel (in your case the window).This function is also
in the DOS library and is called "Close".Its offset is -36 and it
only needs one parameter;the handle number of the channel that is
closed must be in the D1 register.
After your work is done,you need to put the following lines in
your program to close the window:

Close = -36 ; (6.3.2C)


...
move.l conhandle,d1 ;handle number in D1
move.l dosbase,a6 ;DOS base address in A6
jsr Close(a6) ;close channel!

The window disappears!

Now for a few remarks about opening and closing the window in this
[Link] you open several windows in the same way,you'll get several
windows and thus several handle [Link] this way,you can put as
many windows on the screen as you [Link] can do your work with
them and close them individually.
Here is the complete program to open and close a simple window in
AssemPro format (We have used the AssemPro ILABEL and the macros
INIT_AMIGA and EXIT_AMIGA so AssemPro owners can start the program
from [Link] you are using a different assembler check your
documentation for instructions on starting and exiting programs):

;***** 6.3.2 S.D *****

OpenLib =-30-378
closelib =-414
;execbase =4 ;defined in AssemPro macros

*calls to Amiga DOS:

open =-30
close =-30-6
IoErr =-132
mode_old = 1005
alloc_abs =-$cc

ILABEL AssemPro:includes/Amiga.l ;AssemPro only

INIT_AMIGA ;AssemPro only

run:
bsr init ;initialization
bra test ;system-test

init: ;system initialization and open


move.l execbase,a6 ;number of execute-library
lea dosname(pc),a1
moveq #0,d0
jsr openlib(a6) ;open DOS-Library
move.l d0,dosbase
beq error

lea consolname(pc),a1 ;consol definition


move.l #mode_old,d0
bsr openfile ;consol open
beq error
move.l d0,conhandle

rts

test:

bra qu ;quit and exit

error:
move.l dosbase,a6
jsr IoErr(a6)
move.l d0,d5

move.l #-1,d7 ;flag


qu:
move.l conhandle,d1 ;window close
move.l dosbase,a6
jsr close(a6)
move.l dosbase,a1 ;[Link] close
move.l execbase,a6
jsr closelib(a6)

EXIT_AMIGA ;AssemPro only

openfile: ;open file


move.l a1,d1 ;pointer to I/O-Definition-Text
move.l d0,d2
move.l dosbase,a6
jsr open(a6)
tst.l d0
rts

dosname: dc.b '[Link]',0,0


Align.w

dosbase: dc.l 0

consolname: dc.b 'CON:0/100/640/100/**CLI-Test**',0


Align.w

conhandle: dc.l 0

end

There is another way to open a window [Link] use RAW:instead


of CON:as the channel [Link] the other parameters and
operations remain the same.
If you try them both out,you won't see any differences between the
two [Link] both look the same and can be worked with in the
same way with the [Link] difference comes when you input to the
[Link] the RAW:window,the cursor keys are [Link] the CON:
window and in CLI,they do work.

[Link]/Output.
-----------------
Besides managing and making calculations with data,the most
important work of a program is to input and output the [Link]
are many methods of data transfer in and out of the computor,for
instance screen or printer output,keyboard input,using the serial
or the parallel interface,tone or speech output and finally disk
operations.
You want to learn about all these methods of data input and output
for programming and [Link]'ve written some programs as
subroutines that should be useful for later [Link] makes good
sense to make a library of these subroutines that can either be
directly integrated in a new program or linked to a [Link] the
end of the sections there is a list of a complete program so you
can see how the subroutines are used.
To prepare for input/output,you need to have data to output and
space to input [Link] get this ready,you need a correct program
beginning in which the EXEC and DOS libraries are opened and
memory is [Link] this,you begin most programs by outputing
some [Link] text can be a program title or the instruction to
input data over the [Link] start looking at screen output.

[Link] Output.
--------------------
For a computor like the Amiga the first question is where should
the screen output be sent?The answer is simple for many computors;
they only have one screen,and output goes [Link] need to
specify which window to write to when you use the Amiga,however.

There are two possibilites:

[Link] to CLI

[Link] to another window

The first posibillity only exists if the program that makes the
output was started from [Link] not,you need to open your own
custom window for your [Link] so,you can use the window that
was opened by the CLI for output.
If you use the second method,you need to open a [Link] you've
already seen,there are three [Link] simple text and character
output,the difference between the three sorts of windows isn't
very [Link] you have a free hand in determining which sort of
window to [Link] open a CON:window and put its handle number in
"conhandle".
You've opened your window and want to output a [Link] choose
text to output and then put it in memory using a code segment like
this:

title: dc.b "** Welcome to this Program! **"


titleend:
align ;even

The "align"(even) is a pseudo-op that should follow text when it


is followed by either word data or program [Link] causes the
assembler to insert a null byte if necessary to make the address
even.
To output this text you need another DOS function:[Link] has
an offset of -48 and needs three parameters:

In D1 the handle of an opened output channel that should be


written to (in your case,this is the handle number that
you go back from the Open command when you opened your
window.).
In D2 the address of the text to be output (in the example,the
address "title").
In D3 the number of characters to be output in bytes.

To find the number of bytes to output,you need to count the number


of characters in your [Link] "titleend"to calculate [Link]
this label,the assembler can calculate the length of your text for
itself (after all,why should you count when you have a computor?)
if you write:

move.l #titleend-title,d3

The advantage of specifying the length is that you can put control
characters between the beginning and end of the [Link] this way,
you can execute certain functions using text [Link]'ll learn
about the control characters in a bit.

Heres the routine:

Write = -48 ; (6.4.1A)


... ;open window
...
move.l dosbase,a6 ;DOS base address
move.l conhandle,d1 ;pass handle
move.l #title,d2 ;text address
move.l #titleend-title,d3 ;and length
jsr Write(a6) ;call function
...

title: dc.b "** Welcome to this Program! **"

titleend:

align ;event

end

You'll certainly use this function a [Link]'ll often want to


output just one character [Link] allow you to do this and
similar text related tasks,there are four subroutines,each of
which do a different sort of output:

Pmsg;
Outputs the text from (D2) to the first null byte.

Pline;
Is the same as the routine above except that the text is
automatically followed by a CR,the cursor is positioned at the
beginning of the next line.

Pchar;
Outputs the character in D0

Pcrlf;
Puts the cursor at the beginning of the next line.

Heres the subroutine package:

Write = -48 ; (6.4.1B)


...

pline: ;*output line and then a CR


bsr pmsg ;output line

pcrlf:
move #10,d0 ;line feed
bsr pchar ;output
move #13,d0 ;and CR

pchar:
move.b d0,outline ;character in output buffer
move.l #outline,d2 ;address of the character
pmsg: ;*output line (D2) upto null
move.l d2,a0 ;address in A0
clr d3 ;length = 0

ploop:
tst.b (a0)+ ;null byte ?
beq pmsg2 ;yes:length found
addq.l #1,d3 ;else length + 1
bra ploop ;and continue looking

pmsg2:
move.l dosbase,a6 ;DOS base address in A6
move.l conhandle,d1 ;our window handle
jsr Write(a6) ;call write function
rts ;done!

outline: dc.w 0 ;output buffer for 'pchar'

conhandle: dc.l 0 ;windows handle

Here is an example program to open and close a simple window and


output a text message in AssemPro format (We have used the
AssemPro macros INIT_AMIGA and EXIT_AMIGA so AssemPro owners can
start the program from [Link] you are using a different
assembler check your documentation for instructions on starting
and exiting programs.):

Here is the complete program in AssemPro format:

;***** [Link] S.D. *****

Openlib =-30-378
closelib =-414
;execbase = 4 ;Defined in AssemPro
;Macros

* calls to Amiga Dos:

open =-30
close =-30-6
write =-48
IoErr =-132
mode_old = 1005
alloc_abs =-$cc

ILABEL AssemPro:include/Amiga.l ;AssemPro only

INIT_AMIGA ;AssemPro only

run:
bsr init ;initialization
bsr test ;system test
nop
bra qu ;quit and exit

test:
move.l #title,d0
bsr pmsg
bsr pcrlf
bsr pcrlf

rts

init: ;system initialization and


;open
move.l execbase,a6 ;number of execute-library
lea dosname(pc),a1
moveq #0,d0
jsr openlib(a6) ;open DOS-library
move.l d0,dosname
beq error

lea consolname(pc),a1 ;console definition


move.l #mode_old,d0
bsr openfile ;console open
beq error
move.l d0,conhandle

rts

pmsg: ;print message (D0)


movem.l d0-d7/a0-a6,-(sp)
move.l d0,a0
move.l a0,d2
clr.l d3

ploop:
tst.b (a0)+
beq pmsg2
addq.l #1,d3
bra ploop ;length calculate

pmsg2:
move.l conhandle,d1
move.l dosbase,a6
jsr write(a6)
movem.l (sp)+,d0-d7/a0-a6
rts

pcrlf:
move #10,d0
bsr pchar
move #13,d0

pchar: ;output char in D0


movem.l d0-d7/a0-a6,-(sp) ;save all
move.l conhandle,d1

pch1:
lea outline,a1
move.b d0,(a1)
move.l a1,d2
move.l #1,d3 ;1 letter
move.l dosbase,a6
jsr write(a6)
movem.l (sp)+,d0-d7/a0-a6 ;restore all
error:
move.l dosbase,a6
jsr IoErr(a6)
move.l d0,d5

move.l #-1,d7 ;flag

qu:
move.l conhandle,d1 ;window close
move.l dosbase,a6
jsr close(a6)

move.l dosbase,a1 ;[Link] close


move.l execbase,a6
jsr closelib(a6)

EXIT_AMIGA ;AssemPro only

openfile: ;open file


move.l a1,d1 ;pointer to I/O-definition-
;text
move.l d0,d2
move.l dosbase,a6
jsr open(a6)
tst.l d0
rts

dosname: dc.b '[Link]',0,0


align.w

dosbase: dc.l 0

consolname: dc.b 'CON:0/100/640/100/** CLI-Test **',0


align.w

conhandle: dc.l 0

title: dc.b '** Welcome to this Program! **'

titleend:
align

outline: dc.w 0 ;output buffer for char

end

Using this program,you can very easily put whatever you want in
the CON:[Link] functions also work in RAW:[Link] should
rename "conhandle"as "rawhandle",so that you don't get things
mixed up later.
Lets stay with the CON:[Link] mentioned earlier,you can output
special characters that execute functions or change parameters for
[Link] characters are called control characters.
You've already learned about one of these control characters,Line
Feed ($A).This character isn't just output;instead,it calls a
function that moves the cursor into the next line and moves the
screen [Link] is very useful,but there are much more interesting
control characters.
Here's a list of control characters that execute [Link]
characters are given in hex.

Control Sequence;

Sequence Function
------------------------------------------------------------------
08 Backspace
0A Line Feed,Cursor down
0B Move Cursor up a line
0C Clear screen
0D Carrige return,cursor in the first column
0E Turn on normal characters (Cancel Of Effects)
0F Turn on special characters
1B Escape

The following sequences begin with $9B,the CSI (Control Sequence


Introducer).The characters that follow execute a [Link]
values in square brackets can be left [Link] n's you see
represent one or more digit decimal numbers given using ASCII
[Link] value that is used when n is left off,is given in
the parenthesis that follow n in the description of the function
in the table.

Control Sequence Introducer;

Sequence Function
------------------------------------------------------------------
9B[n]40 Insert n blanks
9B[n]41 Move cursor n (1) lines up
9B[n]42 Move cursor n (1) lines down
9B[n]43 Move cursor n (1) characters to the right
9B[n]44 Move cursor n (1) characters to the left
9B[n]45 Move cursor down n (1) lines into column 1
9B[n]46 Move cursor up n (1) lines and into column 1
9B[n][3B n]48 Cursor in line;Set column
9B 4A Erase screen from cursor
9B 4B Erase line from the cursor
9B 4C Insert line
9B 4D Delete line
9B[n]50 Delete n characters starting at cursor
9B[n]53 Move up n lines
9B[n]54 Move down n lines
9B 32 30 68 Line feed => Line feed + return
9B 32 30 6C Line feed => just Line feed
9B 6E Sends the cursor position!A string of the following
form is returned:
9B (line) 3B (column) 52
9B(style);(foreground colour);(Background Colour)6D
The three parameters are decimal numbers in ASCII
[Link] mean:
Style: 0 = normal
1 = bold
3 = italic
4 = underline
7 = inverse
Foreground colour: 30-37
Colour 0-7 for Text
Background colour: 40-47
Colour 0-7 for background
9B(length)74 sets the maximum number of lines to be displayed
9B(width)75 sets the maximum line length
9B(distance)78 defines the distance in pixels from the left border
of the window to the place where output should
begin
9B(distance)79 defines the distance in pixels from the upper
border of the window to the place where output
should begin
The last four functions yield the normal values if
you leave off the parameters.

9B 30 20 70 Make cursor invisible


9B 20 70 Make cursor visible
9B 71 Sends window construction.A string of the following
form is returned:
9B 31 3B 31 3B (lines) 3B (columns) 73

To see how the control characters work,have "pmsg"output this text


to your window:

mytext: dc.b $9b,"4;31;40m" ; (6.3.2D)


dc.b "underline"
dc.b $9b,"3;33;40m",$9b,"5;20H"
dc.b "** Hello World! **",0

The parameters for the control sequence are put in quotation marks
so they are treated as an ASCII [Link] you see,just how easy
it is to do text output!
Here is the complete program to open and output the text and
control codes to your window in AssemPro format (We have used the
AssemPro macros INIT_AMIGA and EXIT_AMIGA so AssemPro owners can
start the programs from [Link] you are using a different
assembler check your documentation for instructions on starting
and exiting programs):

; ***** [Link] S.D. *****

openlib =-30-378
closelib =-414
;execbase = 4 ;defined in AssemPro macros

* calls to Amiga Dos:

open =-30
close =-30-6
write =-48
IoErr =-132
mode_old = 1005
alloc_abs =-$cc

ILABEL AssemPro:includes/Amiga.l ;AssemPro only

INIT_AMIGA ;AssemPro only

run:
bsr init ;initialization
bsr test ;system test
nop
bra qu ;quit and exit

test:
move.l #mytext,d0
bsr pmsg
bsr pcrlf
bsr pcrlf

rts

init: ;system initialization and open


move.l execbase,a6 ;number of execute-library
lea dosname(pc),a1
moveq #0,d0
jsr openlib(a6) ;open DOS-Library
move.l d0,dosbase
beq error

lea consolname(pc),a1 ;console definition


move.l #mode_old,d0
bsr openfile ;console open
beq error
move.l d0,conhandle

rts

pmsg: ;print message (D0)


movem.l d0-d7/a0-a6,-(sp)
move.l d0,a0
move.l a0,d2
clr.l d3

ploop:
tst.b (a0)+
beq pmsg2
addq.l #1,d3
bra ploop

pmsg2:
move.l conhandle,d1
move.l dosbase,a6
jsr write(a6)
movem.l (sp)+,d0-d7/a0-a6
rts

pcrlf:
move #10,d0
bsr pchar
move #13,d0

pchar: ;output char in D0


movem.l d0-d7/a0-a6,-(sp) ;save all
move.l conhandle,d1

pch1:
lea outline,a1
move.b d0,(a1)
move.l a1,d2
move.l #1,d3 ;one letter
move.l dosbase,a6
jsr write(a6)
movem.l (sp)+,d0-d7/a0-a6 ;restore all
rts

error:
move.l dosbase,a6
jsr IoErr(a6)
move.l d0,d5

move.l #-1,d7 ;flag

qu:
move.l conhandle,d1 ;window close
move.l dosbase,a6
jsr close(a6)

move.l dosbase,a1 ;[Link] close


move.l execbase,a6
jsr closelib(a6)

EXIT_AMIGA ;AssemPro only

openfile: ;open file


move.l a1,d1 ;pointer to I/O-definition-
;text
move.l d0,d2
move.l dosbase,a6
jsr open(a6)
tst.l d0
rts

dosname: dc.b '[Link]',0,0


align.w

dosbase: dc.l 0

consolname: dc.b 'CON:0/100/640/100/ ** CLI-Test **',0


align.w

conhandle: dc.l 0

mytext:
dc.b $9b,'4;31;40m'
dc.b 'underline'
dc.b $9b,'3;33;40m',$9b,'5;20H'
dc.b '** Hello World !! **',0

align

outline: dc.w 0 ;output buffer for pchar

end

Now that you've done text and character output,its time to move on
to text input.

[Link] Input.
---------------------
You can read keyboard input very [Link] just need to open the
I/O channel of the CON:window and read from [Link] need the read
function from the DOS library to do [Link] offset is -42.
The function has three parameters just like the WRITE function.

In D1 the handle number that you get from the WRITE function.
In D2 the address that the data read in is to start.
In D3 the number of bytes to read.

Here is a subroutine that reads the number of characters from the


keyboard that it finds in [Link] puts them in a buffer.

read = -42 ; (6.4.2A)


...

getchr: ;* Get (D3) characters from the


;keyboard
move.l #inbuff,d2 ;address of buffer in D2
move.l dosbase,a6 ;DOS base address in A6
move.l conhandle,d1 ;our window handle
jsr read(a6) ;call read function
rts ;done!

inbuff: blk.b 80,0 ;buffer for keyboard input

This routine returns to the main program when <Return> is entered.


If more than D3 characters are entered,"inbuff"only gets the first
[Link] routine gets the remaining characters when called a
second time.
This sort of input is fairly [Link] can backspace,because only
the characters that should be there are put in the memory block
starting at "inbuff".The number of characters moved into "inbuff"
is put in D0.

Try the program out as follows:

After opening the CON:window,put the following lines in the main


program:

move #80,d3 ;read 80 characters (6.4.2B)


bsr readchr ;get line from keyboard
lea inline,a0 ;address of line in A0
clr.b 0(a0,d0) ;null byte on the end
bsr pmsg ;output line again

bp:

After this comes the code segment that closes the window again.
After loading the program into the AssemPro debugger,make "bp"a
breakpoint and start the program.(SEKA users start the program
with "g run"and enter "bp"as the breakpoint).The program quits at
the breakpoint and you can take a look at the results on the
[Link] you can continue the program (SEKA with "j bp") and
let the window close.
After starting the program and opening the window,the cursor
appears in the upper left corner of the [Link] some text and
press <Return>.The string that you just entered is output again on
the screen.
You use the "pmsg"routine from the previous chapter to do this
[Link] routine needs a null byte at the end of the text to be
[Link] put a null byte there by putting the address of the
input buffer in A0 and then erasing the byte at A0+D0 using the
CLR.B [Link] D0 contains the number of characters that were
entered,this byte is the first unused byte.
Since you're in the debugger you can redisplay the disassembled
output when the program ends to see what "getchr"put in "inbuff"
(SEKA owners can use "q inbuff"when the program ends to see what
"getchr"put there.)You'll find the characters that you typed plus
a closing $[Link] $A stands for the <Return> key and its counted
too,so if you entered a 12 and then hit <Return>,for example,D0
will contain a 3.
Try this again with a RAW:[Link] the window definition from
CON: to RAW:and reassemble the [Link]'ll notice the diference
right [Link] you've entered one character,a return is executed
D0 always as one bit in it.
The advantage of this form of input is that cursor and function
keys can be [Link] your own routine,you can repeatedly
accept input of characters using "getchr"and then work with the
special characters.
Theres another form of keyboard input:checking for a single key.
This is important when a program is about to execute an important
function and the user must say he wants it executed by entering
"Y"for [Link] can be treated as normal input,but in some cases,
there is a better method.
There is a function in the DOS library that waits a certain
specified length of time for a key to be pressed,and returns a
zero (FALSE) if no key was hit in this time [Link] returns a -1
($FFFFFFFF = TRUE) if one [Link] find out which key it takes
another [Link] WaitForChar function,is only good for tasks
like waiting for the user to let the program know that it can
continue scrolling text.

The function needs two parameters:

In D1 the handle number of the window or file from which the


character should be [Link] can also wait for a character
from an interface.
In D2 you pass the length of time in microseconds that you
should wait for a key stroke.

To wait one second for one key to be hit,you can use the following
routine:

WaitForCh=-30-174 ; (6.4.2C)
...

scankey: ;* Wait for a key stroke


move.l conhandle,d1 ;in our window
move.l #1000000,d2 ;waiting time 1 second
move.l dosbase,a6 ;DOS base address
jsr waitforch(a6) ;wait...
tst.l d0 ;test result
rts

The TST command at the end of the program allows the calling
routine to use a BEQ or BNE command to evaluate the results of the
routine-BEQ branches if no key was [Link] doesn't.
Heres an example program in AssemPro format covering what you have
learned so [Link] and closing a window,displaying text in the
window and inputting text:

;***** [Link] S.D *****

openlib =-30-378
closelib =-414
;execbase =4 ;defined in AssemPro
;Macros

* call to [Link]:

open =-30
close =-30-6
read =-42
write =-48
IoErr =-132
mode_old =1005
alloc_abs =-$cc

ILABEL AssemPro:include/Amiga.l ;AssemPro only

INIT_AMIGA ;AssemPro only

run:
bsr init ;initialization
bsr test ;system test
nop
bra qu ;quit and exit

test:
move.l #mytext,d0
bsr pmsg
bsr pcrlf
bsr pcrlf
move.l #80,d3 ;80 characters to read in (D3)
bsr getchr ;get character
bsr pmsg ;output line

rts

init: ;system initialization and open


move.l execbase,a6 ;number of execute-library
lea dosname(pc),a1
moveq #0,d0
jsr openlib ;open DOS-Library
move.l d0,dosbase
beq error

lea consolname(pc),a1 ;console definition


move.l #mode_old,d0
bsr openfile ;console open
beq error
move.l d0,conhandle

rts

pmsg: ;print message (D0)


movem.l d0-d7/a0-a6,-(sp)
move.l d0,a0
move.l a0,d2
clr.l d3

ploop:
tst.b (a0)+
beq pmsg2
addq.l #1,d3
bra ploop ;check length

pmsg2:
move.l conhandle,d1
move.l dosbase,a6
jsr write(a6)
movem.l (sp)+,d0-d7/a0-a6
rts

pcrlf:
move #10,d0
bsr pchar
move #13,d0

pchar: ;character in D0 output


movem.l d0-d7/a0-a6,-(sp) ;save all
move.l conhandle,d1

pch1:
lea outline,a1
move.b d0,(a1)
move.l a1,d2
move.l #1,d3 ;1 letter
move.l dosbase,a6
jsr write(a6)
movem.l (sp)+,d0-d7/a0-a6 ;restore all
rts

getchr: ;get character for keyboard


move.l #1,d3 ;1 character
move.l conhandle,d1
lea inbuff,a1 ;buffer address
move.l a1,d2
move.l dosbase,a6
jsr read(a6)
clr.l d0
move.b inbuff,d0
rts

error:
move.l dosbase,a6
jsr IoErr(a6)
move.l d0,d5

move.l #-1,d7 ;flag

qu:
move.l conhandle,d1 ;window close
move.l dosbase,a6
jsr close(a6)
move.l dosbase,a1 ;[Link] close
move.l execbase,a6 jsr ;close lib (A6)

EXIT_AMIGA ;AssemPro only

openfile: ;open file


move.l a1,d1 ;pointer to I/O-Definition-
;Text
move.l d0,d2
move.l dosbase,a6
jsr open(a6)
tst.l d0
rts

dosname: dc.b '[Link]',0,0


align.w

dosbase: dc.l 0

consolname: dc.b 'CON:0/100/640/100/** CLI-TEST **',0


align.w

conhandle: dc.l 0

mytext: dc.b '** Hello World !! **',0

align

outline: dc.w 0 ;output buffer for pchar

inbuff: blk.b 8 ;input buffer

end

[Link] Control.
----------------------
Now that you've looked at console I/O,lets look at outputting data
from the [Link] first device that we'll discuss is the
printer.
Its very easy to use the [Link] just need to open another
[Link] goes just the way you learned it with CON: and RAW:
windows;the only difference is you enter PRT:instead.
You open this channel using the same lines that you used above for
the window except that the pointer is to the channel name PRT:in
[Link] pass the mode "new"(1006) in D2 in the "do_open"routine as
[Link] the handle number that comes back at a label called
"prthandle".
Now you can use the same output routines that you used with the
windows to send text to the [Link] need to put "prthandle"
instead of "conhandle"in the line with the "move.l conhandle,d1"
command.
Actually it would be better to eliminate this line from the
routine [Link] you can use the same routine for window and
printer [Link] calling procedure would then need to put
"conhandle"in D1 for window [Link] would put "prthandle" in D1
for printer [Link] is a very flexible output routine that can
be used for window and printer output [Link] can't accept input
from the printer,because the printer doesn't send [Link] just
accepts it and prints it.

[Link] I/O.
-----------------
Its just as easy to use the serial interface as the [Link]
enter SER:as the [Link] you can use the DOS functions READ
and WRITE just as before to do I/O channels you've just opened.
You can set the parameters for the interface (like Hand shake and
Transfer rate) with the Preferences program.

[Link] Output.
--------------------
The Amiga has a speech synthesizer built [Link] isn't quite as
easy to program as the I/O devices discussed earlier,[Link]
use the "[Link]"to do this.
This device requires several program steps to install it and then
causes it to [Link] need to open the device,start the I/O,etc..
Lets look at how to translate the text into the proper form and
then output the text.
First we need to do some [Link] define the constants
[Link] of them are new.

;***** Narrator Basic Functions 3/87 S.D ***** (6.4.5A)

openlib =-408
closelib =-414
execbase = 4

open =-30 ;open file


close =-36 ;close file
mode_old = 1005 ;old mode

opendevice =-444 ;open device


closedev =-450 ;close device

sendIo =-462 ;start I/O


abortIO =-480 ;abort I/O

translate =-30 ;translate text

;The initialization routine follows:

init: ;initialize and open system

;* open DOS library *

move.l execbase,a6 ;pointer to execbase


lea dosname,a1 ;pointer to DOS name
moveq #0,d0 ;version unimportant
jsr openlib(a6) ;open DOS library
move.l d0,dosbase ;save handle
beq error ;error handle

;* Open [Link] *

lea transname,a1 ;pointer to translator name


clr.l d0
jsr openlib(a6) ;open translator
move.l d0,transbase ;save handle
beq error ;error handling

;* Set up I/O area for Narrator *

lea talkio,a1 ;pointer to I/O area in A1


move.l #nwrrep,14(a1) ;enter port address
move.l #amaps,48+8(a1) ;pointer to audio mask
move #4,48+12(a1) ;number of the mask
move.l #512,36(a1) ;length of the output area
move #3,28(a1) ;command:write
move.l #outtext,40(a1) ;address of output area

;* Open Narrator device *

clr.l d0 ;number 0
clr.l d1 ;no flags
lea nardevice,a0 ;pointer to device name
jsr opendevice(a6) ;open [Link]
tst.l d0 :error?
bne error ;Yes!

;* Open Window *

move.l #consolname,d1 ;console definition


move.l #mode_old,d2 ;old mode
move.l dosbase,a6 ;DOS base address
jsr open(a6) ;open window
tst.l d0 ;error?
beq error ;Yes!
move.l d0,conhandle ;else save handle

After you've done this initialization,you can have the computor


save the text you have prepared for [Link] see what the Amiga is
saying,use the "pmsg"function to have the text written to the
window:

move.l #intext,d2 ;text for the Amiga to say


bsr pmsg ;output in window also

sayit: ;have the text said

;*Translate the text into a form that the computor can use *

lea intext,a0 ;address of the text


move.l #outtext-intext,d0 ;length of the text
lea outtext,a1 ;address of output area
move.l #512,d1 ;length of output area
move.l tranbase,a6 ;translator base address
jsr translate(a6) ;translate text

;* Speech output *

lea talkio,a1 ;address of I/O structure


move.l #512,36(a1) ;length of output area
move.l execbase,a6 ;EXEC base address
jsr sendIO(a6) ;start I/O (speech output)
Once the program ends,the I/O stops as well,so you need to put in
something that keeps the program going [Link]'ll use the
"getchr"function that you programmed earlier to take care of this:

bsr getchr ;wait for keyboard input

The computor waits until the <Return> key is [Link] you can
listen to what the Amiga as to [Link] the <Return> key is
pressed,the program stops.

qu: ; (6.4.5C)
move.l execbase,a6 ;EXEC base address
lea talkio,a1 ;pointer to I/O area
jsr abortio(a6) ;stop the I/O

move.l conhandle,d1
move.l dosbase,a6
jsr close(a6) ;close window

move.l dosbase,d1
move.l execbase,a6
jsr closelib(a6) ;close DOS library

lea talkio,a1
jsr closedev(a6) ;close [Link]

move.l tranbase,a1
jsr closelib(a6) ;close translator library

rts ;* end of program

Now comes the data that you need for the program above:

mytext: dc.b 'This is a test text !',10,13,10,13,0,0


dosmame: dc.b '[Link]',0,0
transname: dc.b "[Link]",0
consolname: dc.b 'RAW:0/100/640/100/** Test window',0
nardevice dc.b '[Link]',0
align
dosbase: dc.l 0
tranbase dc.l 0
amaps: dc.b 3,5,10,12
align
conhandle: dc.l 0
talkio: blk.l 20,0
nwrrep: blk.l 8,0
intext: dc.b 'hello,i am the amiga talking to you',0
align
outtext: blk.b 512,0

This is quite a bit of work,but its worth it because it opens so


many possibilities for [Link] are a lot of variations possible
if you modify [Link] parameters are entries in the I/O
area starting at the "talkio"[Link] area is built as follows:

Offset Length Meaning


----------------------------------------------------------------
** Port Data **
0 L Pointer to next block
4 L Pointer to last block
8 B I/O type
9 B Priority
10 L Pointer to I/O name
14 L Pointer to port
18 W Length
** I/O Data **
20 L Pointer to device
24 L Pointer to device unit
28 W Command word
30 B I/O flags
31 B I/O status
32 L I/O pointer
36 L I/O length
40 L Pointer to Data
44 L I/O offset
** Narrator data items **
48 W Speech speed
50 W Highness of voice
52 W Speech mode
54 W Sex (male/female voice)
56 L Pointer to audio mask
60 W Number of mask
62 W Volume
64 W Read in rate
66 B Flag for producing graphics (0=off)
67 B Actual mask (internal use)
68 B Channel used (internal use)

We would'nt recommend experimenting with the data in the first two


[Link] you do,you can easily cause a system [Link] can use
the last entries of the structure to produce some interesting
effects though.
Heres an overview of the parameters you can use to vary the speech
[Link] value in parenthesis is the standard value,the value
set when [Link] is opened.

Speech speed (150);


You can use this to set the speed of [Link] pitch of the voice
is not affected by this value.

Pitch of voice (110);


You can choose a value between 65 and 320 for the pitch (from
Goofy to Mickey Mouse).

Speech mode (0);


The zero gives half-way naturel speech.A one lets the Amiga speak
in monotone like a robot.

Sex (0);
A zero means masculine and a one means feminine (more or less..)

Volume (64);
The volume can range from 0 to [Link] standard value is the
loudest possible.

Read in rate (22200);


By lowering this value,the voice is [Link] you change this
very much,you'll get some wierd voices!

You can experiment a bit until you find a interesting [Link]


fun!
Here is a complete talking program in AssemPro format:

;***** Speech output S.D. *****

openlib =-30-378
closelib =-414
;execbase =4 ;defined by AssemPro

* calls to Amiga Dos:

open =-30
close =-30-6
opendevice =-444
closedev =-450
addport =-354
remport =-360
;DoIo =-456
sendIo =-462
abortIo =-480
read =-30-12
write =-30-18
;myinput =-30-24
;output =-30-30
;currdir =-30-96
;exit =-30-114
waitforch =-30-174
findtask =-294
translate =-30
mode_old = 1005
;mode_new = 1006
;alloc_abs =-$cc
;free_mem =-$d2

;!!!when>500KB !!! or place in chip memory


;org $40000
;load $40000
;!!!!!!!!!!!!!!!!!!!!!!!

ILABEL AssemPro:includes/Amiga.l ;AssemPro only

INIT_AMIGA ;AssemPro only

run:
bsr init ;initialization
bra test ;system-test

init: ;system initialization and


;open
move.l execbase,a6 ;pointer to exec library
lea dosname(pc),a1 ;pointer to dos name
moveq #0,d0 ;version:not important
jsr openlib(a6) ;open DOS-Library
move.l d0,dosbase ;save handle
beq error ;error routine

;* ;open translator library


move.l execbase,a6 ;pointer to exec library
lea transname,a1 ;pointer to translator library
clr.l d0
jsr openlib(a6) ;open translator
move.l d0,tranbase ;save handle
beq error ;error routine

;* ;set up
sub.l a1,a1
move.l execbase,a6
jsr findtask(a6) ;find task
move.l d0,nwrrep+2

lea nwrrep,a1
jsr addport(a6) ;add port

;* ;open narrator device


lea talkio,a1 ;pointer to I/O area in A1
move.l #nwrrep,14(a1) ;enter port address
clr.l d0 ;number 0
clr.l d1 ;no flags
lea nardevice,a0 ;pointer to device name
jsr opendevice(a6) ;open [Link]
tst.l d0 ;error?
bne error ;Yes!

;* ;set up I/O for narrator


;device

bp:
lea talkio,a1 ;pointer to I/O in A1
move.l #nwrrep,14(a1) ;enter port address
move.l #amaps,48+8(a1) ;pointer to audio mask
move #4,48+12(a1) ;size of mask

lea consolname(pc),a1 ;console-definition


move.l #mode_old,d0
bsr openfile ;console open
beq error
move.l d0,conhandle

rts

test:
move.l #mytext,d0
bsr pmsg ;test-text output

bsr sayit ;say text

bsr readin ;input


move #10,d0
bsr pchar ;LF output
move.l #inline+2,d0
bsr pmsg ;and again
bsr pcrlf
bra qu

error:
move.l #-1,d7 ;flag

qu:
move.l execbase,a6
lea talkio,a1
jsr abortio(a6)

move.l conhandle,d1 ;window close


move.l dosbase,a6
jsr close(a6)

move.l dosbase,a1 ;[Link] close


move.l execbase,a6
jsr closelib(a6)

lea nwrrep,a1
jsr remport(a6) ;remove port
lea talkio,a1
jsr closedev(a6) ;close narrator device
move.l tranbase,a1
jsr closelib(a6) ;close translator library

EXIT_AMIGA ;AssemPro only

openfile: ;open file


move.l a1,d1 ;pointer to I/O definition-
;text
move.l d0,d2
move.l dosbase,a6
jsr open(a6)
tst.l d0
rts

pmsg: ;print message (D0)


movem.l d0-d7/a0-a6,-(sp)
move.l d0,a0
move.l a0,d2
clr.l d3

mess1:
tst.b (a0)+
beq mess2
addq.l #1,d3
bra mess1 ;length calculate

mess2:
move.l conhandle,d1
move.l dosbase,a6
jsr write(a6)
movem.l (sp)+,d0-d7/a0-a6
rts

pcrlf:
move #10,d0
bsr pchar
move #13,d0

pchar: ;output characters in D0


movem.l d0-d7/a0-a6,-(sp) ;save all
move.l conhandle,d1

pch1:
lea chbuff,a1
move.b d0,(a1)
move.l a1,d2
move.l #1,d3 ;1 letter
move.l dosbase,a6
jsr write(a6)
movem.l (sp)+,d0-d7/a0-a6 ;restore all
rts

scankey: ;test key


move.l conhandle,d1
move.l #500,d2 ;wait value
move.l dosbase,a6
jsr waitforch(a6)
tst.l d0
rts

readin: ;input from keyboard


movem.l d0-d7/a0-a6,-(sp) ;save registers
lea inline+2,a2 ;pointer to input buffer
clr.l (a2)

inplop:
bsr getchr
cmp.b #8,d0
beq backspace
cmp.b #127,d0 ;delete?
beq backspace
bsr pchar ;character output
cmp.b #13,d0
beq inputx
move.b d0,(a2)+
bra inplop

inputx:
clr.b (a2)+
sub.l #inline,a2
move a2,inline ;length in lines+1
movem.l (sp)+,d0-d7/a0-a6 ;registers
rts

backspace:
cmp.l #inline,a2 ;at the beginning?
beq inplop ;yes
move.b #8,d0
bsr pchar ;backspace
move #32,d0
bsr pchar ;blank
move #8,d0
bsr pchar ;backspace
clr.b (a2)
subq.l #1,a2
bra inplop

getchr: ;get one character from


;keyboard
move.l #1,d3 ;one character
move.l conhandle,d1
lea inbuff,a1 ;buffer address
move.l a1,d2
move.l dosbase,a6
jsr read(a6)
clr.l d0
move.b inbuff,d0
rts

sayit:
lea intext,a0
move.l #outtext-intext,d0
lea outtext,a1
move.l #512,d1
move.l tranbase,a6
jsr translate(a6)

p:
lea talkio,a1
move #3,28(a1) ;??
move.l #512,36(a1)
move.l #outtext,40(a1)
move.l execbase,a6
jsr sendio(a6)

rts

mytext: dc.b 'This is our Test-Text !',10,13,10,13,0,0

dosname: dc.b '[Link]',0,0

transname: dc.b "[Link]",0


align.w

dosbase: dc.l 0

tranbase: dc.l 0

consolname: dc.b 'CON:0/100/640/100/* Speech-Test S.D.* ',0

nardevice: dc.b '[Link]',0

amaps: dc.b 3,5,10,12,0,0


align.w

conhandle: dc.l 0

inbuff: blk.b 8

inline: blk.b 180,0

chbuff: blk.b 82,0


narread: blk.l 20,0

talkio: blk.l 20,0

nwrrep: blk.l 8,0

intext: dc.b 'hello,i am the amiga computor',0


align.w

outtext: blk.l 128,0

end

[Link] Operations.
--------------------
The most important peripheral device for a computor like the Amiga
is the disk [Link] use it to save data,so that you don't lose
it when you turn off the [Link]'ll look at saving and
retrieving data in this chapter.
Lets first look at the simple disk operations that are used for
data [Link] gain access to a file,you must open it first.
This is done using the OPEN function from the DOS library,a
function that you're already familiar with.I'll assume in the
following examples,that you've already opened the DOS library.

[Link] Files.
-----------------
The open function needs a parameter for the [Link] mode has a
particular [Link] the file is opened for reading,it must
already [Link] mode for the OPEN function must be "old"(1005)
in this case.
If you want to produce a file,you must open it [Link] it does
not exist,you use the "new"(1006) [Link] a file is opened for
writing using this mode even though a file with this name already
exists,the old file with this name is erased and [Link] avoid
loss of data,you should check if a file by that name already
exists and then output an error message if it does.
You're going to start with a subroutine that opens a [Link]
assume that the filename starts at the label "filename",and that
it is closed with a null [Link] just need to pass the mode in
register D2.
The routine puts the file handle number in "filehd"and returns to
the main [Link] the operation with the handle is the last
one performed by the subroutine,the status of the operation can be
evaluated once the return has been [Link] the operation went
smoothly and the file is opened,the handle number has a non-zero
[Link] it is zero and "bsr openfile"is followed by "beq error",
you can branch to an error handling routine when problems occur.

Here is a subroutine for opening and closing a file:

open =-30 ; (6.5.1A)


close =-36
mode_old = 1005
mode_new = 1006
...
openfile: ;*open file,mode in D0
move.l dosbase,a6 ;DOS base address in A6
move.l #filename,d1 ;pointer to filename
jsr open(a6) ;open file
move.l d0,filehd ;save handle
rts

closefile: ;*close file


move.l dosbase,a6 ;DOS base address in A6
move.l filehd,d1 ;file handle in D1
jsr close(a6) ;close file
rts

filehd: dc.l 0 ;storage for file handle


filename: dc.b "filename",0 ;file to be opened
align ;even

To use these subroutines,you must look at how you can load and
save data.

[Link] and Writing Data.


-------------------------------
Lets write a new [Link] start,write the following lines:

move.l #mode_new,d2 ;open new file (6.5.2A)


bsr openfile ;open file
beq error ;did'nt work!

For the filename,write a name like "Testfile"in the line labelled


"filename".After calling the "openfile"routine,a file with this
name is created on the [Link] one existed already,it is erased.

Lets assume you want to write a short text [Link] the example
lets use:

text: dc.b "This is a test text for the Testfile",0


textend:

The "textend"label is used so that you can calculate the number of


data bytes by subtracting "text".
You want to write this text in the [Link] the WRITE function
which needs three parameters:

In D1 the file handle that you got back from the OPEN function.
In D2 a pointer to the data that should be written.
In D3 the number of bytes to be written.

For the example,you'll need another segment of code to put the


pointer to the data in D2 and the number of bytes in D3:

write =-48 ; (6.5.2B)


...
writedata: ;*write data in the file
move.l dosbase,a6 ;DOS base address
move.l filehd,d1 ;file handle in D1
jsr write(a6) ;write data
rts

After opening the file,you can call the subroutine from the main
program with the following lines:
move.l #text,d2 ;pointer to data
move.l #textend-text,d3 ;number of bytes
bsr writedata ;write data in the file

Then close the file with:

bsr closefile ;close file


bra end ;end program

After running the program,look at the directory of the diskette,


you should find the file "testfile".It is just as long as your
[Link] want to read this file in,to make sure it contains the
right data.
You need the DOS function READ,which needs the same parameters as
the WRITE [Link] can use parameters for the number of bytes
to read just part of the [Link] you give a larger number than the
file contains,the whole file is [Link]'ll find the number of
bytes read in D0.
Lets set up a field that as enough space for the data you want to
[Link] can do this with the following line:

field: blk.b 100 ;reserve 100 bytes

For the example data,this is [Link] you want to load another


file,you may need to reserve more space.
Now lets write a subroutine to read the [Link] always want to
load whole [Link] just need to pass the address of the buffer
so the data is loaded into the [Link] the example,its the
address "field".
Heres the subroutine that reads the entire opened file into the
memory area pointed to by D2:

read = -42 ; (6.5.2C)


...
readdata: ;*read file
move.l dosbase,a6 ;DOS base address in A6
move.l filehd,d1 ;file handle in D1
move.l #$ffffff,d3 ;read an arbitrary number of bytes
jsr read(a6) ;read data
rts

To use this routine to load the file into the buffer "field",use
the following main program:

move,l #mode_old,d2 ;old file


bsr openfile ;open file
beq error ;did'nt work!
move.l #field,d2 ;pointer to data buffer
bsr readdata ;read file
move.l d0,d6 ;save number of bytes in D6
bsr closefile ;close file
bra end ;program end

After assembling and starting this program,you can use the


debugger to look at the data buffer that you filled with data from
the [Link] D6,you'll find the number of bytes that were read from
the file.
[Link] Files.
------------------
Once you've experimented enough with the program above,you'll
certainly want to erase the "Testfile"[Link] DELETEFILE function
in the DOS library has an offset of -[Link] only needs 1 parameter.
The parameter is passed in [Link] parameter is a pointer to the
[Link] name must be closed with a null byte.

To erase "Testfile",use the following lines:

deletefile =-72 ; (6.5.3)


...
move.l dosbase,a6 ;DOS base address in A6
move.l #filename,d1 ;pointer to filename in D1
jsr deletefile(a6) ;erase file

The file is [Link] can't save the file with normal methods if
you accidently erase it!You can use a trick that saves the data.
We'll take a look at this trick [Link] used in lots of programs

[Link] Files.
-------------------
When a text editing program writes a text that as be altered back
to the disk,the old file usually isn't [Link] the old file
is [Link] example,it might get the name "Backup".The new file
is written to disk with the old name.
The function in the DOS library that allows you to change the
names of programs is called RENAME and has -78 as an [Link]
need to pass two parameters-D1 as a pointer to the old name and D2
as a pointer to the new name of the file.

To rename "Testfile"as "Backup"(before you erase it),use the


following lines:

rename =-78
...
move.l dosbase,a6 ;DOS base address in A6
move.l #oldname,d1 ;pointer to old name in D1
move.l #newname,d2 ;pointer to new name in D2
jsr rename(a6) ;rename file
...
oldname: dc.b "testfile",0
newname: dc.b "backup",0

[Link] Directory.
--------------------
Lets pretend you've programmed a text editor and started [Link]
you want to load a text from disk and edit it-but whats the name
of that file?
You need a function to read and display the directory of the disk.
There are several ways to do [Link] lets use the easiest
[Link] doesn't require much programming and can be quite
useful.
The trick is to call the Dir or List programs that are in the C
[Link]'ll use the CLI [Link] DOS library contains a
command called "Execute"with offset -222 that allows you to
execute CLI commands.
The function needs three parameters:
In D1 a pointer to a string closed with a zero that contains the
name of the command to be [Link] string must
contain the same command that you would give in the [Link]
can be a null pointer as well.
In D2 the input file is [Link] theres a zero here.
If however,you give the file handle of a text file,though,
this file is read and interpreted as a command [Link]
you define a window as the input medium,you've programmed
a new CLI window!
In D3 the output file is [Link] there a zero here,the
output of the commands (for example,DIR output) is sent to
the standard CLI window.

To try this out,insert this subroutine in a program that has


already opened the DOS library and a window.

execute = -222 ; (6.5.5)


...
dir:
move.l dosbase,a6 ;DOS base address in A6
move.l #command,d1 ;pointer to command line
clr.l d2 ;no input (CLI window)
move.l conhandle,d3 ;output in our window
jsr execute(a6) ;execute command
rts

command:
dc.b "dir",0

This program works with the List command as [Link] disadvantage


of this method is that the disk that the Workbench is loaded from
must be in the drive or the system requests you to put it [Link]
Dir command is just a program,and the Amiga must load it before it
can run.
The disadvantage isn't too [Link] program is short,and it
allows you to use any CLI command in a program.
Here is the complete program in AssemPro format that calls the dir
program:

;***** 6.5.5A [Link] S.D.*****

openlib =-408
closelib =-414
;execbase = 4 ;defined in AssemPro
;macros

*calls to Amiga Dos:

open =-30
close =-36
execute =-222
IoErr =-132
mode_old = 1005
alloc_abs =-$cc

ILABEL AssemPro:includes/Amiga.l ;AssemPro only

INIT_AMIGA ;AssemPro only


run:
bsr init ;initialization
bra test ;system test

init: ;system initialization and


;open
move.l execbase,a6 ;number of execute-library
lea dosname(pc),a1
moveq #0,d0
jsr openlib(a6) ;open DOS-library
move.l d0,dosbase
beq error

lea consolname(pc),a1 ;console definition


move.l #mode_old,d0
bsr openfile ;console open
beq error
move.l d0,conhandle

rts

test:
bsr dir ;do directory
bra qu ;quit and exit

dir:
move.l dosbase,a6 ;DOS base address in A6
move.l #command,d1 ;pointer to command line
clr.l d2 ;no input (CLI window)
move.l conhandle,d3 ;output in our window
jsr execute(a6) ;execute command
rts

error:
move.l dosbase,a6
jsr IoErr(a6)
move.l d0,d5

move.l #-1,d7 ;flag

qu:
move.l conhandle,d1 ;window close
move.l dosbase,a6
jsr close(a6)

move.l dosbase,a1 ;[Link] close


move.l execbase,a6
jsr closelib(a6)

EXIT_AMIGA ;AssemPro only

openfile: ;open file


move.l a1,d1 ;pointer to I/O-Definition-
;text
move.l d0,d2
move.l dosbase,a6
jsr open(a6)
tst.l d0
rts

dosname: dc.b '[Link]',0,0


align.w
dosbase: dc.l 0
consolname: dc.b 'CON:0/100/640/100/** CLI-Test **',0
align.w
conhandle: dc.l 0
command:
dc.b "dir",0

end

[Link] Directory.
---------------------
Now,lets look at another method that doesn't need the [Link] this
way,you can read the directory of any disk without having to play
Disk Jockey.
You need to writ a program that does what CLI's Dir program does.
There are several steps.
First you must give the system a key to the desired [Link]
means you must call DOS'Lock [Link] needs two parameters:

In D1 pass a pointer to a text that contains the name of the


directory you wish to [Link],for example,you want to
read the contents of the RAM disk,the text would be
'RAM:',0.
In D2 put the mode that determines whether to read or [Link]
us use the "Read"(-2) mode.

You call the Lock function (offset -84) and get either a point to
the key or a zero returned to you in the D0 [Link] you get a
zero,the call did'nt work,the file was'nt [Link] function can
be used to find if a file is on the [Link] use this function
with the name and see if D0 comes back [Link] not,the file
exists.
Lets assume the file or path [Link] need to save the value
that came back in [Link]'ll need it for both functions that you'll
call.
The next function you need is called [Link] use it to search
the disk for an acceptable [Link] returns parameters like name,
length and date that correspond to the [Link] need to reserve a
memory block for this information and put the beginning of the
block in D2 before calling the Examine [Link] the key you
got from the Lock function in the D1 register.
The memory area that is filled with information is called a
[Link] 260 bytes long and contains information about
the [Link] name starts in the 9th byte and ends with a null byte
so you can easily print it with our "pmsg"[Link] information
that Examine gives isn't about a particular file,but about the
[Link] name in FileInfoBlock is the disk name.
The Examine function sends the status back in the D0 register.
Since the Lock function already tested if the file existed,evalua-
ting the status really isn't necessary.
Now to the function that you can use to read individual files from
the [Link] function is called ExNext (Examine Next).This
function searches for the next entry that fits the key every time
it is [Link] gets the same parameters as Examine gets.
However,the return parameter in D0 is more important here.
The ExNext function is always called in the same [Link] always
gets the next entry of the [Link] no more entries exist in
the directory,ExNext puts a zero in the D0 register.
You need to continue performing this operation until there aren't
any more [Link] can find this using the IoErr function from
the DOS library.
This function doesn't need any [Link] returns the status of
the last I/O operation that was performed in the D0 [Link]
the last ExNext,this value is 232,which means no_more_Entries.

Heres a complete routine for reading the directory of the disk in


DFO:and displaying the contents in the window.

; [Link]
;***** DOS-Sample function 3/87 S.D. *****

openlib =-30-378
closelib =-414
exbase =4

* calls to amiga dos:

open =-30
close =-30-6
read =-30-12
write =-30-18
myinput =-30-24
output =-30-30
currdir =-30-96
lock =-30-54
examine =-30-72
exnext =-30-78
exit =-30-114
IoErr =-30-102
waitforch =-30-174
mode = 0
mode_old = 1005
mode_new = 1006
alloc_abs =-$cc
free_mem =-$d2

ILABEL AssemPro:includes/Amiga.l ;AssemPro only

INIT_AMIGA ;AssemPro only

run:
bsr init ;initialization
bra test ;system-test

init: ;system initialization and


;open
move.l exbase,a6 ;pointer to [Link]
lea dosname(pc),a1
moveq #0,d0
jsr openlib(a6) ;open dos-library
move.l do,dosbase
beq error

lea consolname(pc),a1 ;console definition


move.l #mode_old,d0
bsr openfile ;console open
beq error
moveq d0,conhandle

rts

test:
move.l #mytext,d0
bsr pmsg ;test-text output

move.l dosbase,a6
move.l #name,d1
move.l #-2,d2
jsr lock(a6)
move.l d0,d5
tst.l d0
beq error
move.l d0,locksav

move.l dosbase,a6
move.l locksav,d1
move.l #fileinfo,d2
jsr examine(a6)
move.l d0,d6
tst.l d0
beq error

loop:
move.l dosbase,a6
move.l locksav,d1
move.l #fileinfo,d2
jsr exnext(a6)
tst.l d0
beq error

move.l #fileinfo+8,d0
bsr pmsg
bsr pcrlf
bra loop

error:
move.l dosbase,a6
jsr ioerr(a6)
move.l d0,d6

move.l #presskey,d0
bsr pmsg
bsr getch
move.l #-1,d7 ;flag

qu:
move.l conhandle,d1 ;window close
move.l dosbase,a6
jsr close(a6)

move.l dosbase,a1 ;[Link] close


move.l exbase,a6
jsr closelib(a6)
EXIT_AMIGA ;AssemPro only

openfile: ;open file


move.l a1,d1 ;pointer to I/O-Definition-
;Text
move.l d0,d2
move.l dosbase,a6
jsr open(a6)
tst.l d0
rts

pmsg: ;print message (D0)


movem.l d0-d7/a0-a6,-(sp)
move.l d0,a0
move.l a0,d2
clr.l d3

mess1:
tst.b (a0)+
beq mess2
addq.l #1,d3
bra mess1

mess2:
move.l conhandle,d1
move.l dosbase,a6
jsr write(a6)
movem.l (sp)+,d0-d7/a0-a6
rts

pcrlf:
move #10,d0
bsr pchar
move #13,d0

pchar: ;character in D0 output


movem.l d0-d7/a0-a6,-(sp) ;save all
move.l conhandle,d1

pch1:
lea chbuff,a1
move.b d0,(a1)
move.l a1,d2
move.l #1,d3
move.l dosbase,a6
jsr write(a6)
movem.l (sp)+,d0-d7/a0-a6 ;restore all
rts

scankey: ;test key


move.l conhandle,d1
move.l #500,d2 ;wait value
move.l dosbase,a6
jsr waitforch(a6)
tst.l d0
rts

readin: ;input from keyboard


movem.l d0-d7/a0-a6,-(sp) ;registers
lea inline+2,a2 ;pointer to input buffer
clr.l (a2)

inplop:
bsr getchr
cmp.b #8,d0
beq backspace
cmp.b #127,d0 ;delete?
beq backspace
bsr pchar ;character output
cmp.b #13,d0
beq inputx
move.b d0,(a2)+
bra inplop

input:
clr.b (a2)+
sub.l #inline,a2
move a2,inline ;length in inline+1
movem.l (sp)+,d0-d7/a0-a6 ;registers
rts

backspace:
cmp.l #inline,a2 ;at beginning?
beq inplop ;yes
move.b #8,d0
bsr pchar ;backspace
move #32,d0
bsr pchar ;blank
move #8,d0
bsr pchar ;backspace
clr.b (a2)
subq.l #1,a2
bra inplop

getchr: ;get 1 character from keyboard


move.l #1,d3 ;1 character
move.l conhandle,d1
lea inbuff,a1 ;buffer-address
move.l a1,d2
move.l dosbase,a6
jsr read(a6)
clr.l d0
move.b inbuff,d0
rts

mytext: dc.b 'Directory of Diskette: DFO:',10,13,10,13,0,0


dosname: dc.b '[Link]',0,0
presskey: dc.b 'Press thr Return key!!',0
align.w
dosbase: dc.l 0
consolname: dc.b 'CON:0/100/640/100/** Directory-Test **',0
name: dc.b 'DFO:',0
align.w
locksav: dc.l 0
fileinfo: ds.l 20
conhandle: dc.l 0
inbuff: DS.B 8
inline: DS.B 180
chbuff DS.B 82

end

The FileInfoBlock contains the following entries:

Offset Name Meaning


----------------------------------------------------------------
0 DiskKey.L Disk Number
4 DieEntryType.L Entry Type (+=Directory,-=File)
8 FileName 108 bytes with the filename
116 Protection.L File Protected?
120 EntryType.L Entry type
124 Size.L Length of file in bytes
128 NumBlocks.L Number of blocks
132 Days.L Creation day
136 Minute.L Creation time
140 Tick.L Creation time
144 Comment 116 bytes with comments

If you want to have the program output the file length as well,you
can read the length with "move.l fileinfo+124,d0"and then use a
conversion routine to produce a decimal [Link] can output this
result with the name.

[Link] Access To Disk.


----------------------------
There isn't a simple function in the library for accessing single
disk [Link],you must work with a device just like you did
with speech [Link] time you'll be working with the trackdisk.
device.
You want to work with this device to directly program the disk
[Link] you've built up the necessary program machinery,you
can experiment with various commands for disk [Link] that
an error can cause the disk to be modified and thus [Link]
sure you're using a non-essential [Link]'t use one which
contains your only copy of something.
The initialization here is similar to that for speech [Link]
is the initialization routine for your program:

;** Direct disk access via [Link] ** (6.5.7)

openlib =-408
closelib =-414
execbase = 4
open =-30
close =-36
opendevice =-444
closedev =-450
sendIo =-462
read =-30-12
write =-30-18
waitforch =-30-174
mode_old = 1005

run:
bsr init ;initialization
bra test ;system-test

init: ;initialize and open system


move.l execbase,a6 ;pointer to [Link]
lea dosname,a1
moveq #0,d0
jsr openlib(a6) ;open [Link]
move.l d0,dosbase
beq error
lea diskio,a1 ;pointer to disk I/O area
move.l #diskrep,14(a1) ;pointer to port
clr.l d0 ;drive 0 (built in)
clr.l d1 ;no flags
lea trddevice,a0 ;pointer to device name
jsr opendevice(a6) ;open [Link]
tst.l d0 ;error?
bne error ;yes!
move.l #consolname(pc),d1 ;console definition
move.l #mode_old,d2 ;old mode
move.l dosbase,a6 ;dos base address
jsr open(a6) ;open window
tst.l d0 ;error?
beq error ;yes!
move.l d0,conhandle ;else save handle
rts ;done

test: ;place for test routine

And now for the functions that take care of the various messages
at the end of the program.

error:
move.l #-1,d7 ;flag for error (for SEKA)

qu:
move.l execbase,a6 ;exec base address
lea diskio,a1 ;pointer to disk I/O
move.l 32(a1),d7 ;IO_ACTUAL in D7 (for testing)
move #9,28(a1) ;command motor on/off
move.l #0,36(a1) ;0=off,1=on,so turn motor
jsr sendio(a6) ;off
move.l conhandle,d1 ;close window
move.l dosbase,a6
jsr close(a6)
move.l dosbase,d1 ;close [Link]
move.l execbase,a6
jsr closelib(a6)
lea diskio,a1
jsr closedev(a6) ;close [Link]
rts

Lets not forget the routine that waits for the user to press
<Return>,so that you can watch the effects of the test function in
peace:

getchr: ;get a character from keyboard


move.l #1,d3 ;1 character
move.l conhandle,d1 ;window handle
move.l #inbuff,d2 ;buffer address
move.l dosbase,a6 ;dos base address
jsr read(a6) ;read character
rts ;thats it

The last thing you need is the section of code that declares the
text and data fields that your program needs:

dosname: dc.b '[Link]',0


align
consolname: dc.b 'RAW:0/100/640/50/** Wait window',0
align
trddevice: dc.b '[Link]',0
align
dosbase: dc.l 0 ;dos base address
conhandle: dc.l 0 ;window handle
inbuff: blk.b 80,0 ;keyboard buffer
diskio: blk.l 20,0 ;I/O structure
diskrep: blk.l 8,0 ;I/O port
diskbuff: blk.b 512*2,0 ;place for 2 sectors

There,now you've done with the set up [Link] look at how you
can give commands to the disk [Link] first and easiest command
is the one for turning the drive motor on and [Link]'ve already
seen this command in the [Link] is command number [Link]
number goes in the command word of the I/O structure (bytes 28 and
29 of the structure).
You need to pass a parameter that lets the computor know whether
to turn the motor off or [Link] information goes in the I/O long
word that starts at byte 36:its zero for off,and one for on.
You already chose the motor that should be turned on or off when
you opened the [Link] put the number of the chosen disk drive
in D0-in your case you put a zero there because you are using the
DFO:disk drive.
Heres an overview of the commands you can use to access
information on the disk:

No Name Function
-----------------------------------------------------------------
2 READ Read one or more sectors
3 WRITE Write sectors
4 UPDATE Update the track buffer
5 CLEAR Erase track buffer
9 MOTOR Turn motor on/off
10 SEEK Search for a track
11 FORMAT Format tracks
12 REMOVE Initialize routine that is called when you
remove the disk
13 CHANGENUM Find out number of disk changes
14 CHANGESTATE Test if disk is in drive
15 PROTSTATUS Test if disk is write protected

You've already learned about command number [Link] look at the


three commands you can use to make [Link] are the last three
[Link] put a return value in the long word that begins in
the 32nd byte in the I/O [Link] value was written in D7 in
the program above for testing [Link] can read its contents
directly if you ran the program with AssemPro.
Here is a simple routine that you can use to run one of these
commands with:

test: ; (6.5.7B)
lea diskio,a1 ;pointer to I/O structure
move #13,28(a1) ;pass command (for example 13)
move.l execbase,a6 ;execbase address in A6
jsr sendio(a6) ;call function

If CHANGENUM (command 13) is executed,in D7 you'll get the number


of times a disk was taken out and put in the [Link] you call the
program,you'll get a value [Link] you take the disk out and put
it back in,the number is two higher the next time you call the
program.
The CHANGESTATE command (command 14) tells whether a disk is in
the drive or [Link] one is,a zero comes [Link],a $FF is
returned.
You get the same values back from the PROTSTATUS function (command
15).Here a zero means that the disk isn't write protected,while
$FF means that it is.
Now lets look at the READ and WRITE [Link] operations
need a few more parameters than the status [Link] need to
pass the following parameters:

The address of the I/O buffer in the data pointer,the number of


bytes to be transfered in I/O length,and the data address on the
disk in I/O offset.

The number of data bytes must be a multiple of 512,since every


sector is 512 bytes,and only whole sectors can be read.

The data address is the number of the first byte in the [Link]
you want to use the first sector,the offset is [Link] the second
sector,its 512,etc...The formula is:

offset = (sector_number -1) *512

Here is a routine that loads the first two sectors of the disk
into the buffer:

test: (6.5.7C)
lea diskio,a1
move #2,28(a1) ;command:READ
move.l #diskbuff,40(a1) ;buffer
move.l #2*512,36(a1) ;length:2 sectors
move.l #0*512,44(a1) ;offset:0 sectors
move.l execbase,a6 ;exec base address
jsr sendio(a6) ;start function

Start the program from the debugger and then look at the buffers
contents after the program [Link] can find out the format of the
disk [Link] you want to read a sector thats being used,change the
0 in the offset definition to 700 and start [Link] highly
probable that theres some data there.
To modify and write back the data that you've read from the disk,
you need command number three,the WRITE [Link] parameters are
the same.
If you've executed the WRITE commandyou're probably wondering why
the disk light did'nt go [Link] because the Amiga writes a track
that as been read into a buffer on its [Link] WRITE's data there
as [Link] won't write the data to disk until another track is
accessed.
You can have the data updated directly as well using command four,
the UPDATE command.
Command 11,the FORMAT command,is also quite [Link]
command needs a data field that is 11*512=5632 bytes long-the
length of a [Link] offset must be a multiple of this number so
that you start at the beginning of a track.
The length must be a multiple of 5632 as a [Link] several
tracks are formatted,each track is filled with the same data.
You can use this function to easy write a disk copy [Link]
READ the source disk and then FORMAT the corresponding track on
the destination [Link] how the DiskCopy program works-it
reformats the destination disk.
Command ten,the SEEK command,just needs the [Link] moves the
Read/Write head of the drive to the position specified without
making a disk access or testing if its at the right position.
Command 12,the REMOVE command,is used to install an interrupt
routine that is called when the disk is removed from the disk
[Link] address of the interrupt structure is passed in the data
pointer of the I/O [Link] theres a zero here,the interrupt
routine is turned off.

Heres a complete example program in AssemPro format:

;***** Track disk-Basic function 10/86 S.D. *****

ILABEL ASSEMPRO:includes/Amiga.l :AssemPro only

openlib =-30-378
closelib =-414
;execbase = 4 ;defined in INIT_AMIGA

* calls to amiga dos:

open =-30
close =-30-6
opendevice =-444
closedev =-450
sendIo =-462
read =-30-12
write =-30-18
waitforch =-30-174
mode_old = 1005

INIT_AMIGA ;AssemPro only

run:
bsr init ;initialization
bra test ;system test

init: ;system initialization and


;open
move.l execbase,a6 ;pointer to exec-library
lea dosname,a1
moveq #0,d0
jsr openlib(a6) ;open dos-library
move.l d0,dosbase
beq error

lea diskio,a1
move.l #diskrep,14(a1)
clr.l d0
clr.l d1
lea trddevice,a0
jsr opendevice(a6) ;open [Link]
tst.l d0
bne error

bp:
lea consolname(pc),a1 ;console-definition
move.l #mode_old,d0
bsr openfile ;console open
beq error
move.l d0,conhandle

rts

test:
bsr accdisk

bsr getchr ;wait for character


bra qu

error:
move.l #-1,d7 ;flag

qu:
move.l execbase,a6
lea diskio,a1
move #9,28(a1)
move.l #0,36(a1)
jsr sendio(a6)

move.l conhandle,d1 ;window close


move.l dosbase,a6
jsr close(a6)

move.l dosbase,a1 ;[Link] close


move.l execbase,a6
jsr closelib(a6)

lea diskio,a1
move.l 32(a1),d7
jsr closedev(a6)

EXIT_AMIGA ;AssemPro only

openfile: ;open file


move.l a1,d1 ;pointer to the I/O-definition
;text
move.l d0,d2
move.l dosbase,a6
jsr open(a6)
tst.l d0
rts

scankey: ;test for key


move.l conhandle,d1
move.l #500,d2 ;wait value
move.l dosbase,a6
jsr waitforch(a6)
tst.l d0
rts

getchr: ;get one character from


;keyboard
move.l #1,d3 ;1 character
move.l conhandle,d1
lea inbuff,a1 ;buffer-address
move.l a1,d2
move.l dosbase,a6
jsr read(a6)
clr.l d0
move.b inbuff,d0
rts

accdisk:
lea diskio,a1
move #2,28(a1) ;command:READ
move.l #diskbuff,40(a1) ;buffer
move.l #2*512,36(a1) ;length:2 sectors
move.l #20*512,44(a1) ;offset: n sectors
move.l execbase,a6
jsr sendio(a6)
rts

dosname: dc.b '[Link]',0,0


align.w
dosbase: dc.l 0
consolname: dc.b 'RAW:0/100/640/100/** Test-Window S.D.V0.1',0
trddevice: dc.b '[Link]',0
align.w
conhandle dc.l 0
inbuff: ds.b 8
diskio: ds.l 20,0
diskrep: ds.l 8,0
diskbuff: ds.b 512*2,0

end

Chapter 7.
----------
[Link] With Intuition.
-------------------------
Now that you've learned so much about machine language,lets look
at the special features of the [Link] look at the operating
system Intuition that is in charge of windows,screens,the mouse
and lots of other [Link] a look at these beautiful
features,theres some bad news.
First,though,lets here the good [Link] Intuition has so many
functions,it allows you to be very creative in programming your
[Link] disadvantage is that the flexibility means that you have
to use a lot of parameters,and that makes for a lot of tedious
work.
However,this is no grounds for [Link] you've built up the
necessary routines,the programming and experimentation becomes
increasingly [Link] you try out new program variations
you should save your source code to disk,because Intuition gets
fairly upset about bad parameters and often responds by crashing
the system.
Now lets get to [Link] start working with Intuition,you need the
Intuition [Link] can load it with the OpenLibrary function
from the EXEC [Link] the subroutine that takes care of
initialization.

openlib =-408
execbase = 4

run:
bsr openint ;load intuition library
...

openint: ;*initialize and open system


move.l execbase,a6 ;exec base address
lea intname,a1 ;name of intuition library
jsr openlib(a6) ;open intuition
move.l d0,intbase ;save intuition base address
rts

intname: dc.b "[Link]",0


align
intbase: dc.l 0 ;base address of intuition

When your program is finished,you need to close the screens,the


window and the [Link] do this,use the CloseLibrary function
from the EXEC [Link] has an offset of -414.
Heres the subroutine:

closelibrary =-414
...
closeint: ;*close intuition
move.l execbase,a6 ;exec base address in A6
move.l intbase,a1 ;intuition base address in A1
jsr closelibrary(a6) ;close intuition
rts ;done

Now that you've got that taken care of,you can finally start
working with Intuition.

[Link] Screen.
----------------
Intuition is a graphics operating [Link] this reason,you'll be
working with the [Link] even more interesting to work with
several screens at the same [Link],you only have one monitor
on the Amiga.
You can open as many screens as you like (at least,as long as
theres some memory available).You can open a window,display menus
and do I/O's [Link] individual screens are fully independant.
You can work with all of them simultaneously on the monitor.
You can move individual screens forward and back to your hearts
[Link] can also press the left <Amiga> key and then an "m"to
return to the workbench screen after getting into the different
screens.
You want to begin programming Intuition by setting up a [Link]
have already loaded the Intuition library,so you can use the Open-
Screen function.
Wait a minute!What should the screen look like,where should it go,
and what form should it have?You need to look at the options for
the form of the screen you have available.
The input to the screen is in the form of a table that has 13
[Link] take a look at the parameters that you need for our
screen.
You'll start the table with the label "screen_defs"which must be
at an even address:

align
screen_defs: ;The screen table begins here

The first bit of information that the screen needs is the position
and [Link] have it start in the upper left corner and fill the
entire [Link]'ll use the positions X=0 and Y=0,the width 320
and the height [Link] means that your screen is the maximum
size.

x_pos: dc.w 0 ;X-Position


y_pos: dc.w 0 ;Y-Position
width: dc.w 320 ;width
height: dc.w 200 ;height

Next you need to decide which colors should be [Link]


depends on the number of bitplanes,on the [Link] choose two.
That means you have 2^2 (4) colours [Link] choose two,
since four colours is usually plenty.

depth: dc.w 2 ;number of bitplanes

Next you need to choose the colour of the title line and the
function [Link] the number of the colour register:

detail_pen: dc.b 0 ;colour of text,etc...

Now for the colour of the text background:

block_pen dc.b 1 ;background colour

Make sure that these two inputs fit in a [Link] colours are
normally the following (if the standard values have'nt been
changed).You'll notice that the number of colours depends on the
number of bit maps.

Pen Colour
---------------------------------------------------------
0 Background (blue)
1 White
for two bit planes
2 Black
3 Red
for three bit planes
4 Blue
5 Violet
6 Turquoise
7 White
for four bit planes
8 Black
9 Red
10 Green
11 Brown
12 Blue
13 Blue
14 Green
15 Green

The next word contains the bits that describe the appearance of
the [Link] bits are:

Bit Value Name Meaning


---------------------------------------------------------------
1 2 GENLOCK_VIDEO
2 4 INTERLACE Puts the screen in Interlace
[Link] resolution and thus the
maximum screen size are doubled.
6 $40 PFBA
7 $80 EXTRA_HALFBRITE
8 $100 GENLOCL_AUDIO
10 $400 DBLPF Divides the screen into a border
and character area.
11 $800 HOLDNMODIFY Turns on Hold-and-Modify mode.
13 $2000 VP_HIDE
14 $4000 SPRITES Allows sprites to be used.
15 $8000 MODE_640 Turns on the highest resolution
graphics for the screen(640x400).

Choose the value two (normal) for your example screen:

view_modes: dc.w 2 ;representation mode

The following word is constructed in such away that each bit as


its own [Link] this to set what sort of screen it [Link]
15 so the screen is a "Custom screen",which allows you all of the
options.

screen_type: dc.w 15 ;screen type:custom screen

Next theres a pointer to the character set to be used for all


output to the [Link] you don't want to install your own
character set,just put a zero here,and the standard character set
is used.

font: dc.l 0 ;character set:standard

Next theres a pointer to the text thats used as the name of the
[Link] text ends with a zero,just like window names must.

title: dc.l name ;pointer to title text

Next comes a long word that defines the [Link] gadgets


represent the functions,like "Bring forward",that can be accessed
via a mouse click in the [Link] long word in this table is a
pointer to a list which specifies the [Link] aren't the
system [Link],you're only using system gadgets here,so
put a zero here.

gadgets: dc.l 0 ;no gadgets

Finally theres a long word that you only need if you want to use
the special bitmap just for your [Link] this isn't the case,
just put a zero here.

bitmap: dc.l 0 ;no bitmap

Thats it for the list entries that you need to define the screen.
You still need the text for the name of the [Link] the
following:

sname: dc.b 'Our Screen',0 ;screen title

Heres a quick overview of the list:

align
screen_defs: ;*The screen ta
x_pos: dc.w 0 ;X-position
y_pos: dc.w 0 ;Y-position
width: dc.w 320 ;width
height: dc.w 200 ;height
depth: dc.w 2 ;number of bitplanes
detail_pen: dc.b 0 ;colour of the text,etc...
block_pen: dc.b 1 ;background colour
view_modes: dc.w 2 ;representation mode
screen_type: dc.w 15 ;screen type:custom screen
font: dc.l 0 ;character set:standard
title: dc.l sname ;pointer to title text
gadgets: dc.l 0 ;no gadgets
bitmap: dc.l 0 ;no bit map
sname: dc.b 'Our Screen',0 ;screen title

Once you've decided on the parameters,its very easy to open the


[Link] need Intuitions OpenScreen [Link] offset is -198
and it only needs one parameter,the address of the parameter
[Link] program fragment looks like this:

openscreen =-198
bsr openint ;open intuition
bsr scropen ;open screen
...
scropen: ;*open screen
move.l intbase,a6 ;intuition base address in A6
lea screen_defs,a0 ;pointer to table
jsr openscreen(a6) ;and open
move.l d0,screenhd ;save screen handle
rts ;return to main program
...
screen_defs: ;table info follows

Now the Amigas Workbench screen is covered by your [Link] you


can do what you want with it until the program is [Link],
the screen must be closed again,so that you can see the Workbench
screen again.
Use the CloseScreen function (offset -66) to do [Link] only
parameter it needs is the pointer to the screen structure you got
back from the OpenScreen function.

closescreen =-66
...
scrclose: ;* close screen
move.l intbase,a6 ;intuition base address in A6
move.l screenhd,a0 ;screen handle in A0
jsr closescreen(a6) ;clos screen
rts ;done

The long word that OpenScreen returned to you is a pointer to a


screen structure that contains all the needed data about the
[Link] the data which was given,there is a pointer in the
screen area for individual bit planes,etc...
The form of this structure is fairly complicated and contains some
data that you can't [Link] of the parameters are interesting,
[Link] a selection of usable parameters:

No Name Function
------------------------------------------------------------------
0 (NextScreen.L) Pointer to next screen.
4 (FirstWindow) Pointer to first window structure
8 (LeftEdge.W)
$A (TopEdge.W) Position of screen
$C (Width.W) Width
$E (Height.W) Height
$10 (MouseY.W)
$12 (MouseX.W) Mouse position in the screen
$14 (Flags.W) Screen flags
$16 (Title.L) Pointer to title text
$1A (DefaultTitle) Pointer to normal title
$28 (Font.L) Pointer to character set
$C0 (Plane0.L) Pointer to bitplane 0
$C4 (Plane1.L) Pointer to bitplane 1
$C8 (Plane2.L) Pointer to bitplane 2
$CC (Plane3.L) Pointer to bitplane 3

An example of an application for the plane pointer is writing and


using your own character [Link] you want to move the address
of the plane into an address register as follows:

move.l screenhd,a5 ;screen pointer in A5


move.l $c0(a5),a5 ;bitplane 0-pointer in A5

If you want to try this,do the following:

move.l screenhd,a5 ;screen pointer in A5


move.l $c0(a5),a5 ;bitplane 0-pointer in A5
move #$20,d0 ;Counter D0=$20

lop1:
move d0,(a5) ;write counter bits in picture
add.l #80,a5 ;address+80,next line
dbra d0,lop1 ;continue until D0 < 0

This program draws a white,square pattern that corresponds to the


bit pattern for the numbers $20 to [Link] isn't a particularly
useful program,but it shows how easy it is to write from a machine
language program directly to the [Link] you change the offset
in the second line to $C4,the pattern is read.
You can move the entire screen with the normal technique of moving
the mouse pointer into the upper border and moving it up and down
with the left mouse key [Link] can do the same with a
program.
Lets move the screen without the [Link] the joystick for
demonstration [Link] the joystick in port [Link] you saw in
the chapter on the hardware register,you can read memory location
$DFF00C to find information about the [Link] can find the
direction the screen should be moved here.
Moving the screen requires another Intuition [Link] use the
MoveScreen function which as an offset of -162 and needs three
parameters to do [Link] parameters are:

In A0 the pointer to the screen structure that you got back in


D0 when you opened the screen.(You saved it in "screenhd")
In D1 the desired movement in the Y-direction,the vertical
direction.
In D0 the horizontal movement in the [Link] varient
doesn't work so you can only move the screen vertically.

Insert the following lines in your program:

MoveScreen =-162
...
scrmove: ;*move screen D0 to the right
;and D1 down
move.l intbase,a6 ;intuition base address in A6
move.l screenhd,a0 ;screen handle in A0
clr.l d0 ;no horizontal movement
jsr movescreen(a6) ;move screen
rts ;done

Now your looking at a complete program that goes through the


following steps:

1. Opens the Intuition library


2. Opens the screen
3. Moves the screen in the direction specified by the joystick in
port two
4. Closes the screen when the fire button is hit
5. Closes the Intuition library
6. Ends

Here is the complete program including the subroutines,so you'll


have it all in one spot:

;** Demo program to open and move a screen **

movescreen =-162
openscreen =-198
closescreen =-66
closelibrary =-414
openlib =-408 ;open library
execbase = 4 ;exec base address
joy2 =$dff00c ;joystick 2 data
fire =$bfe001 ;firebutton 2:bit 7

run:
bsr openint ;open intuition
bsr scropen ;open screen
move joy2,d6 ;save joystick info

loop:
tst.b fire ;test fire button
bpl ende ;pressed down:done
move joy2,d0 ;basic info in D0
sub d6,d0 ;subtract new data
cmp #$0100,d0 ;up?
bne noup ;no
move.l #-1,d1 ;dy=-1 direction y
bsr scrmove ;move up
bra loop

noup:
cmp #$0001,d0 ;down?
bne loop ;no
move.l #1,d1 ;dy=1
bsr scrmove ;move down
bra loop

ende:
bsr scrclose ;close screen
bsr closeint ;close intuition
rts ;done!

openint: ;*initialize and open system


move.l execbase,a6 ;exec base address
lea intname,a1 ;name of intuition library
jsr openlib(a6) ;open intuition
move.l d0,intbase ;save intuition base address
rts

closeint: ;*close intuition


move.l execbase,a6 ;exec base address in A6
move.l intbase,a1 ;intuition base address in A1
jsr closelibrary(a6) ;close intuition
rts ;done

scropen: ;*open screen


move.l intbase,a6 ;intuition base address in A6
lea screen_defs,a0 ;pointer to table
jsr openscreen(a6) ;open
move.l d0,screenhd ;save screen handle
rts ;return to main program

scrclose: ;*close screen


move.l intbase,a6 ;intuition base address in A6
move.l screenhd,a0 ;screen handle in A0
jsr closescreen(a6) ;close screen
rts ;done

scrmove: ;move screen D0 right/D1 down


move.l intbase,a6 ;intuition base address in A6
move.l screenhd,a0 ;screen handle in A0
clr.l d0 ;no horizontal movement
jsr movescreen(a6) ;and move
rts ;done
align

screen_defs: ;*screen table begins here


x_pos: dc.w 0 ;X-position
y_pos: dc.w 0 ;Y-position
width: dc.w 320 ;width
height: dc.w 200 ;height
depth: dc.w 2 ;number of bitplanes
detail_pen: dc.b 1 ;Text colour=white
block_pen: dc.b 3 ;background colour=red
view_modes: dc.w 2 ;representation mode
screen_type dc.w 15 ;screen type:custom screen
font: dc.l 0 ;standard character set
title: dc.l sname ;pointer to title text
gadgets: dc.l 0 ;no gadgets
bitmap: dc.l 0 ;no bit map
intbase: dc.l 0 ;base address of intuition
screenhd: dc.l 0 ;screen handle
intname: dc.b '[Link]',0
align
sname: dc.b 'Our Screen',0 ;Screen title
align
end

From this example,you can see how easy scrolling actually is.
Another easy thing to do is to use the DisplayBeep [Link] as
an offset -96;the only parameter it needs is the screen pointer
that you stored in the "screenhd"memory [Link] function covers
the screen with an orange colour for a short [Link] screen is
not [Link] beep function can be used as follows:

DisplayBeep: =-96
...
move.l intbase,a6 ;intuition base address in A6
move.l screenhd,a0 ;screen pointer in A0
jsr displaybeep(a6) ;light up screen

If you put a zero instead of a screen pointer in A0,the whole


screen blinks.
Good,now you have your own screen that you can move up and down.
What good is it if you can't put anything on it?Lets open a window
on the screen!

[Link] Window.
----------------
As you saw in the chapter on program initialization,its easy to
open a window with the DOS [Link] can't use this method on
your own screen [Link] need to use another method that can
open any window on any screen.
Intuition has a function called OpenWindow which handles this sort
of [Link] has an offset of -204 and needs only one parameter,a
pointer to a window definition [Link] pointer goes in register
A0.
This table is very similar to the one used to define the screen.
The first four values specify the X-and Y-positions,the width,and
the height of the window to be [Link] an example:

align
window_defs:
dc.w 10 ;x-position
dc.w 20 ;y-position
dc.w 300 ;width
dc.w 150 ;height

Next come two bytes that define the colour of the letters on the
background:

dc.b 1 ;white letter colour


dc.b 3 ;on a red background

The next long word contains the IDCMP flags in its [Link] bits
determine the circumstances under which Intuition sends a message
to the [Link] bits have the following meanings:

Bit Value Name Meaning


-----------------------------------------------------------------
0 $000001 SIZEVERIFY
1 $000002 NEWSIZE Window size changed
2 $000004 REFRESHWINDOW
3 $000008 MOUSEBUTTONS Mouse key hit
4 $000010 MOUSEMOVE Mouse moved
5 $000020 GADGETDOWN A special gadget chosen
6 $000040 GADGETUP Same as above
7 $000080 REQSET
8 $000100 MENUPICK A menu item chosen
9 $000200 CLOSEWINDOW A window closed
10 $000400 RAWKEY A key pressed
11 $000800 REQVERIFY
12 $001000 REQCLEAR
13 $002000 MENUVERIFY
14 $004000 NEWPREFS Preferences modified
15 $008000 DISKINSERTED A disk put in
16 $010000 DISKREMOVED A disk taken out
17 $020000 WBENCHMESSAGE
18 $040000 ACTIVEWINDOW A window activated
19 $080000 INACTIVEWINDOW A window deactivated
20 $100000 DELTAMOVE Report relative mouse movement

If you want your first window to respond only by clicking on the


close symbol,write the following:

dc.l $200 ;IDCMP flags:CLOSEWINDOW

Next comes a long word whose bits determine the windows [Link]
can use this to construct a window to your exact specifications.
This is quite different from windows opened with the DOS function.
The bits mean:

Bit Value Name Meaning


------------------------------------------------------------------
0 $0000001 WINDOWSIZING Window size is changeable
1 $0000002 WINDOWDRAG Window is moveable
2 $0000004 WINDOWDEPTH Window covering is posible
3 $0000008 WINDOWCLOSE Window close symbol
4 $0000010 SIZEBRIGHT
5 $0000020 SIZEBOTTOM
6 $0000040 SIMPLE_REFRESH New drawing manuel
7 $0000080 SUPER_BITMAP Save the windows contents
8 $0000100 BACKDROP Move window back
9 $0000200 REPORTMOUSE Report mouse co-ordinates
10 $0000400 GIMMEZEROZERO
11 $0000800 BORDERLESS Window without border
12 $0001000 ACTIVATE Window active
13 $0002000 WINDOWACTIVATE
14 $0004000 INREQUEST
15 $0008000 MENUSTATE
16 $0010000 RMBTRAP Right mouse key:no menu
17 $0020000 NOCAREREFRESH No refresh message
24 $1000000 WINDOWREFRESH
25 $2000000 WBENCHWINDOW

To refresh is to rebuild the window contents when necessary,for


instance when the windows size is [Link] none of the refresh
bits are set,you're in [Link] this case,Intuition
takes care of refreshing the [Link] is the easiest method.
If you choose the value $100F as the type for your example window,
the window is active once its opened,and it has all the system
gadgets:

dc.l $100F ;ACTIVATE and all gadgets

The next long word in the list allows you to use your own gadgets
in the [Link] long word is a pointer to the structure of a
your [Link] you don't want this,just put a zero here.

dc.l 0 ;first gadget:no gadgets of our own

The next long word is a pointer to a graphics structure so you can


design your own symbol for checking menu [Link] a zero here.
You'll use the standard sign:

dc.l windowname ;pointer to window name

The next long word is a pointer to the screen structure that you
got back after calling the OpenScreen [Link] easiest way to
do this is to save the pointer to this location in the buffer:

screenhd: dc.l 0 ;screen pointer

The next long word is a pointer to a bit map if you want one of
your own for the [Link] you don't want one,put a zero here.

dc.l 0 ;no bit map of our own

Next come four values that set the maximum and minimum width and
height of the window:

dc.w 150 ;smallest width


dc.w 50 ;smallest height
dc.w 320 ;maximum width
dc.w 200 ;maximum height

The last value in the list is the screen type of the screen the
window is located [Link] a 15 [Link]'re using our screen as a
custom screen:

dc.w 15 ;screen type:custom screen


Heres a quick overview of the whole list:

align
window_prefs:
dc.w 10 ;X-position
dc.w 20 ;Y-position
dc.w 300 ;width
dc.w 150 ;height
dc.b 1 ;white print colour
dc.b 3 ;on red background
dc.l $200 ;IDCMP flags:CLOSEWINDOW
dc.l $100f ;ACTIVATE and all gadgets
dc.l 0 ;first gadget:no gadgets of
;our own
dc.l 0 ;checkmark:standard
dc.l windowname ;pointer to window name
screenhd: dc.l 0 ;screen pointer
dc.l 0 ;no bitmap of our own
dc.w 150 ;smallest width
dc.w 50 ;smallest height
dc.w 320 ;maximum width
dc.w 200 ;maximum height
dc.w 15 ;screen type:custom screen

;and here comes the window name:


windowname: dc.b 'Our Window',0
align

Insert these lines in the program you listed [Link] are two
subroutines for opening and closing the window:

openwindow =-204
closewindow =-72
...
windopen:
move.l intbase,a6 ;intuition base address in A6
lea windowdef,a0 ;pointer to window definition
jsr openwindow(a6) ;open window
move.l d0,windowhd ;save window handle
rts

windclose:
move.l intbase,a6 ;intuition base address in A6
move.l windowhd,a0 ;window handle
jsr closewindow(a6) ;close window
rts
...
windowhd: dc.l 0 ;window handle

Now you can insert a "bsr windowopen"after the "bsr scropen"and a


"bsr windclose"before the "bsr scrclose"[Link] you've
started the program,move the window around in the [Link]'ll
find that you can't move the window out of the screen with the
mouse.
The window in the example has the close gadget in the upper left
[Link] if you click it,the window is [Link] clicking
[Link]'ll find that nothing happens.
The display of this and all other gadgets,as well as other events
must be programmed in,since Intuition doesn't know which action
causes which [Link]'ll take a look at how to handle this in the
next chapter.

[Link].
---------------
If you only have one disk drive,you've certainly seen the Amiga
message,"Please insert xxx in unit 0",a [Link] window is another
that has two fields for [Link] sort of message with a
choice of options is called a requester.
You want to take a look at how to program a [Link],you
need a window for the requester to appear [Link] opened a window
of this sort in the example program.
To display a requester,use the Intuition function AutoRequest
(offset -348).It takes care of drawing and managing the requester.
This function needs the following parameters:

In A0 The pointer to the window structure that you put in


"windowhd".
In A1 A pointer to the text structure that should stand over the
choice buttons.
In A2 Same as above for the text of the left button.
In A3 Same as above for the right button.
In D0 The IDCMP flag which lets you know what event should go
with the clicking of the left button.
In D1 Same as above for the right button.
In D2 The width of the whole requester.
In D3 The height of the requester.

Insert the following lines in your program:

autorequest =-348
...
request:
move.l windowhd,a0 ;pointer to window structure
lea btext,a1
lea ltext,a2 ;pointer to text structure
lea rtext,a3
move.l #0,d0 ;left activates by clicking
move.l #0,d1 ;right activates by clicking
move.l #180,d2 ;width and
move.l #80,d3 ;height of requester
move.l intbase,a6 ;intuition base address
jsr autorequest(a6) ;display requester
rts

The flags passed in D0 and D1 offer some interesting posibilites.


The system messages that tells you to enter a particular disk are
overlooked when the DISKINSERTED flag is [Link] a disk in
brings about the same responce as clicking the "Retry"button.
Whats new is the use of a text [Link] three of [Link]
structures are lists that contain entries for the text that you
need.
These lists begin with two bytes that are used to define the
[Link] first byte is the colour of the [Link] second is for
the background [Link] this doesn't have any meaning.

btext:
dc.b 2 ;black text colour
dc.b 0 ;background colour

The next byte specifies the character mode.A zero means that the
text is output normally.A four means the text is output inverted.

dc.b 0 ;normal text representation

The next entries are [Link] this reason the addresses must be
even,so you need to either insert another byte or use the "align"
[Link] following words are the X-and Y-position of the text
relative to the upper left corner of the requester.

dc.w 10 ;X-position
dc.w 5 ;Y-position relative to upper
;left corner

Next,theres a pointer to the character set that is [Link] a zero


here to use the standard set.

dc.l 0 ;standard character set

Next you need to give the address of the text that should be
[Link] text must be closed with a null byte.

dc.l text ;pointer to text

You need a long word at the end of the list that is either a
pointer to another text or a zero if no more text is needed.

dc.l 0 ;no more text

Here are the three text structures that you need for the example:

btext: ;text structure for the title


dc.b 0,1 ;colour
dc.b 0 ;mode
align
dc.w 10,10 ;text position
dc.l 0 ;standard font
dc.l bodytxt ;pointer to text
dc.l 0 ;no more text

bodytxt:
dc.b "Requester Text",0
align
ltext: ;text structure of left button
dc.b 0,1 ;colour
dc.b 0 ;mode
align
dc.w 5,3 ;text position
dc.l 0 ;standard font
dc.l lefttext ;pointer to text
dc.l 0 ;no more text

lefttext:
dc.b "left",0
align

rtext:
dc.b 0,1 ;colour
dc.b 0 ;mode
align
dc.w 5,3 ;text position
dc.l 0 ;standard font
dc.l righttext ;pointer to text
dc.l 0 ;no more text

righttext:
dc.b "right",0
align

After calling the requester,D0 contains the information about


which of the buttons were pressed,and in which button the event
took [Link] D0 is zero,it was the right [Link] it is one,it
was the left button.

[Link] Handling.
-------------------
Pretend you've opened a window that as a close symbol,and you want
the program to react to this symbol being [Link] need a
signal from Intuition that lets you know that an event as taken
[Link] signal is called a message.
The IDCMP flag of the window specifies which events should cause
Intuition to send a [Link] setting the bits for WINDOWCLOSE,
you can allow a message to be sent when the close symbol is
clicked.
To get the message,you can use the EXEC function GetMsg (offset
-372).It needs the source address of the event as a [Link]
the source is the User port (which doesn't have anything to do
with the User port on old Commodore computors).
The User port contains a table which has entrieswhich specify the
events that have taken place and related things like mouse
position and time.
How do you find the User port?Use the pointer to the window
structure that you got back from the OpenWindow function and
stored in the "windowhd"memory block.
This pointer points to the window structure of this [Link]
structure consists of a number of [Link] are copies of the
parameters from our window definition [Link] won't cover all the
entries,because most won't be interesting to [Link]'re more
interested in the pointer to the User [Link] in the window
structure.
You can find this in the long word that begins in the 86th byte of
the [Link] can get this long word with the following lines
of code:

move.l windowhd,a0 ;pointer to structure in A0


move.l 86(a0),a0 ;user port pointer in A0

You can call the GetMsg function with this pointer in A0 by using
the following lines of code in your program:

GetMsg = -372
...
move.l windowhd,a0 ;pointer to structure in A0
move.l 86(a0),a0 ;user port pointer in A0
move.l execbase,a6 ;exec base address in A6
jsr getmsg(a6) ;get message
This function returns a value in the D0 [Link] value is a
pointer to another structure,the Intuition Message [Link]
theres a zero in D0,no event as taken place.
The long word that starts at the 20th byte in this structure
contains the information about which event took [Link]
the information is easy,since the bits of this long word have the
same meaning as the IDCMP flag that you described when you looked
at opening windows.
Put the lines above after "loop"and then insert the following:

move.l d0,a0 ;message pointer in A0


move.l 20(a0),d6 ;save event in D6
tst.l d0 ;did the event take place?
bne end ;yes!

Now you can end this program by clicking the close [Link] way
you can find out if an event as taken [Link] can use D6 to
determine what event took [Link] the example,D6 contains the
number $00000200,which means that the close symbol was clicked.
To see if this works with other events,change the $200 IDCMP flag
to $10200 in the window definition [Link] you've assembled and
started this version,take the disk out of the drive-the program
terminates.
The IDCMP flags that you've got now cause the clicking of the
close symbol and the taking out of the disk (DISKREMOVED) to be
[Link] you want to find out which of the events took place,
you can look in [Link] has a $200 in it if the window is closed,a
$10000 if the disk was removed.

[Link] Programming.
---------------------
Now lets look at one of Intuitions more interesting capabillities:
menu [Link] using menus,you can make your programs very
user friendly.
There are a lot of ways for you to use [Link] can make menu
points unusable,output sub-menus,choose the type of menu entries
(allow text or pictures to be output),etc..To have lots of options
you need some parameters.
Lets produce a menu with the SetMenuStrip function (offset -264)
of [Link] function only needs two parameters,a pointer to
the menu structure of the window to be drawn and a pointer to the
window structure of the window in which the menu is to function.
Each window can have its own menu that is active when the window
is activated.
Heres the subroutine to set up the menu:

SetMenuStrip =-264
...
setmenu: ;* Initialize a menu
move.l intbase,a6 ;intuition base address in A6
move.l windowhd,a0 ;pointer to window structure
lea menu,a1 ;pointer to menu structure
jsr setmenustrip(a6) ;call function
rts

Heres a routine to erase the menu:

ClearMenuStrip =-54
...
clearmenu:
move.l intbase,a6 ;intuition base address in A6
move.l windowhd,a0 ;pointer to window structure
jsr clearmenustrip(a6)
rts

You've already got the pointer to the window [Link] look


at the menu structure you need for the [Link] need to build a
structure like this for each menu--for each menu title that
appears when you press the right mouse key.
This structure is a table with the following form:

First there is a long word that points to the menu structure of


the next [Link] the current menu is the last one,a zero goes
here.

align
menu:
dc.l menu1 ;pointer to the next menu

Next come two words which contain tha X- and Y-position of the
menu title:

dc.w 20 ;X-position
dc.w 0 ;Y-position

Next,use two words to store the menu titles width and height in
pixels:

dc.w 50 ;width
dc.w 10 ;height of menu title

The next word contains the flag bit that determines whether the
menu is available or [Link] unavailable menu either as grey
entries or they are drawn [Link] the flag bit,bit 0,is set the
menu is [Link],it is not.

dc.w 1 ;menu available

Now comes a long word which functions as a pointer to the text


which is used as the menu [Link] sure the length isn't larger
than the width entry allows!Otherwise unpleasent things will
happen.

dc.l menutext ;pointer to title text

Next comes a long word which functions as a pointer to the


structure of the first menu entry of this [Link] menu entry
needs its own structure.

dc.l menuitem01 ;pointer to the first menu item

The last entries in the table are four words that are reserved for
internal [Link] must be here.

dc.w 0,0,0,0 ;reserved words

Thats the structure of the first [Link] structures first long


word points to the next structure which has the same [Link]
pointer is set to zero in the last menu.
You still need the structure of the menu [Link] structure
tables have the following form:

They start with a pointer to the next menu [Link] pointer is


set to zero for the last entry.

align
menuitem01:
dc.l menuitem02 ;pointer to next menu item

Next comes the four words:the X- and Y-position,the width and the
height of the box the menu entry goes [Link] size becomes obvious
when the item is chosen by having the right mouse key clicked on
[Link] the box becomes [Link] you can see,the next word is
determined in the [Link] lets set the position and size of
the menu point,though:

dc.w 0 ;X-position of entry


dc.w 0 ;Y-position
dc.w 90 ;width in pixels
dc.w 10 ;height in pixels

The position entries are relative to the upper left corner of the
menu that is pulled down.
The following word was described above:it contains flags for
entries to this menu [Link] are several interesting variations
[Link] following flag bits are contained in this word:

Bit Value Name Meaning When Set


------------------------------------------------------------------
0 $0001 CHECKIT Point is checked when chosen
1 $0002 ITEMTEXT Text menu item
2 $0004 COMMSEQ Choice can be made with keys as well
3 $0008 MENUTOGGLE Check turned on and off
4 $0010 ITEMENABLED Menu item available
6 $0040 HIGHCOMP Item inverted when chosen
7 $0080 HIGHBOX Iten framed when chosen
8 $0100 CHECKED Item is checked

Heres a description of the bits:

Name Description
------------------------------------------------------------------
CHECKIT If this bit is set,a check or a user-defined
drawing is put in front of the text when the item
is [Link] text should begin with two blanks.

ITEMTEXT The menu item is a normal text if this bit is set.


Otherwise a drawing is output.

COMMSEQ By setting this bit and entering a character,this


menu point can be chosen by pressing the right
<Amiga> key and the key that was [Link] input
character is then displayed in the menu with the
Amiga [Link] needs to be space available for
this.
MENUTOGGLE If this bit is set and checking is allowed (bit 0),
the second time this point is chosen the check is
erased,the next time it is displayed again,etc...

ITEMENABLED Erasing this bit makes the menu item available.

HIGHCOMP If this bit is set,the box you've defined is


inverted when this menu item is chosen by the mouse
pointer.

HIGHBOX In this mode,the box is framed whin its chosen.

The two previous bits determine the mode of the chosen menu item.
The following combinations are possible:

HIGHIMAGE If both bits are cleared,choosing the bit causes a


self-defined drawing to be output.

HIGHNONE When both bits are set,there isn't any reaction to


choosing this item.

CHECKED This bit can be set by either the program or


[Link] lets you know if the menu text has a
check next to it or [Link] can use this to find
out if the item was checked by testing but [Link]
its set,the item was [Link] can also use it to
cause the item to be checked.

You're choosing the mode CHECKIT,ITEMTEXT,COMMSEQ,MENUTOGGLE,ITEM-


ENABLED and HIGHBOX for the example:

dc.w $10011111 ;mode flag

Lets get back to the structure of the menu [Link] the flag
word,there is a long word whose flag bits determine whether this
menu point can be turn off another [Link] this to zero:

dc.l 0 ;no connection

Now comes the pointer to the structure of the text that should be
[Link] the ITEMTEXT bit isn't set,this pointer must point to
the structure of the [Link] nothing should be shown,you can
set this to [Link] a text in the example and write the
following:

dc.l menu01text ;pointer to menu text structure

The following long word only has a meaning if the HIGHIMAGE flag
is [Link] this long word points to the text or the drawing that
should be displayed when the menu items box is [Link]
the long word is ignored,so insert a zero:

dc.l 0 ;no drawing when clicked

The next entry is a byte that is used for input of keyboard


characters,which together with the right <Amiga> key can be used
to choose the menu [Link] only works if the COMMSEQ bit is set.
Place a character here:
dc.b 'A' ;choose item using <Amiga>/'A'

Since the next item is a long word,you need an "align"peudo-op


[Link] comes the long word that points to the menu item
structure or a [Link] submenu is automatically shown when
this menu item is [Link] can't nest them any deeper,however,
so this long word is ignored for submenus.
If you don't want a submenu to this item,put a zero here:

align
dc.l 0 ;no submenu

The next and final long word is written to by Intuition if you


choose several menu [Link] this case,the menu number of the next
menu item chosen goes here:

dc.l 0 ;preparation

Thats the structure for a menu [Link] still need the text
structure for the text of the [Link] isn't complicated,but it
makes you get into fine details about the form of the [Link]'ve
already learned about this text structure when you looked at
requesters,so we'll skip an explanation.
Heres the complete structure of an example [Link] can use two
menus,each with two [Link] second menu point of the left
menu has a submenu with two [Link] ought to type this program
in,so that you can experiment with [Link] can also use this
example to evaluate the clicked menu item.

;**Complete menu structure foe example menu **


menu:
dc.l menu1 ;no next menu
dc.w 10,30 ;X/Y
dc.w 50,10 ;width/height
dc.w 1 ;menu enabled
dc.l menuname ;menu title
dc.l menuitem01 ;menu entry
menuname:
dc.b "Menu 1",0 ;first menu name
align
menu1:
dc.l 0 ;no further menu
dc.w 80,0 ;see above
dc.w 50,10
dc.w 1
dc.l menuname1
dc.l menuitem11
dc.w 0,0,0,0
menuname1:
dc.b "Menu 2",0 ;second menu name
align
menuitem01: ;first menu item
dc.l menuitem02 ;pointer to next entry
dc.w 0,0 ;X/Y
dc.w 130,12 ;width/height
dc.w $9f ;flags
dc.l 0 ;exclude
dc.l text01 ;pointer to text structure
dc.l 0 ;select fill
dc.b "1" ;command
align
dc.l 0 ;subitem:none
dc.w 0 ;next select:no
text01:
dc.b 0,1 ;colours
dc.b 0 ;mode:overwrite
align
dc.w 5,3 ;X/Y position
dc.l 0 ;standard character set
dc.l text01txt ;pointer to text
dc.l 0 ;no more text
text01txt:
dc.b "Point 0.1",0
align
menuitem02: ;second menu item
dc.l 0
dc.w 0,10
dc.w 130,12
dc.w $57
dc.l 0
dc.l text02
dc.l 0
dc.b "2" ;activate with <Amiga>/'2'
align
dc.l 0
dc.w 0
text02:
dc.b 0,1
dc.b 0
align
dc.w 5,3
dc.l 0
dc.l text02txt
dc.l 0
text02txt:
dc.b "Point 0.2",0
align
menuitem11: ;first menu point of the second menu
dc.l menuitem12 ;pointer to second menu point
dc.w 0,0
dc.w 90,12
dc.w $52
dc.l 0
dc.l text11
dc.l 0
dc.b 0
align
dc.l 0
dc.w 0
text11:
dc.b 0,1
dc.b 0
align
dc.w 5,3
dc.l 0
dc.l text11txt
dc.l 0
text11txt:
dc.b "Point 1.1",0
align
menuitem12: ;second menu item of second menu
dc.l 0 ;no more items
dc.w 0,10
dc.w 90,12
dc.w $92
dc.l 0
dc.l text12
dc.l 0
dc.b 0
align
dc.l submenu0 ;pointer to submenu
dc.w 0
text12:
dc.b 0,1
dc.b 0
align
dc.w 5,3
dc.l 0
dc.l text12txt
dc.l 0
text12txt:
dc.b "Point 1.2",0
align
submenu0: ;first point of submenu
dc.l submenu1 ;pointer to next point
dc.w 80,5
dc.w 90,12
dc.w $52
dc.l 0
dc.l texts0
dc.l 0
dc.b 0
align
dc.l 0
dc.w 0
texts0:
dc.b 0,1
dc.b 0
align
dc.w 5,3
dc.l 0,texts0txt,0
texts0txt:
dc.b "S Point 1",0
align
submenu1: ;submenu,second item
dc.l 0
dc.w 80,15
dc.w 90,12
dc.w $52
dc.l 0
dc.l texts1
dc.l 0
dc.b 0
align
dc.l 0
dc.w 0
texts1:
dc.b 0,1
dc.b 0
align
dc.w 5,3
dc.l 0
dc.l texts1txt
dc.l 0
texts1txt:
dc.b "S Point 2",0
align

The menu items in this example have the following properties as a


result of their flags:

Menu 1;
The first item,"Point 0.1",can be chosen using the right <Amiga>
key and the "1" [Link] point alternates between checked and not
checked,which can easily be used to check out the key [Link]
the item is checked and you hit both keys,the check disappears and
vice [Link] box at this point is framed when the mouse pointer
clicks on it.
The second item,"Point 0.2",can be chosen using the right <Amiga>
key and the "2"[Link] item is checked the first time it is
[Link],in contrast to the item above,it can't be erased.
The box of this item is inverted when clicked.

Menu 2;
These two points can't be chosen using [Link] box of the upper
item is inverted when clicked on:the lower one is [Link] you
click the second item,"Point 1.2",a submenu with two entries is
displayed.

Experiment with this structure a little [Link] some values and


see what [Link] you can see,menu programming isn't as bad as
you thought,and it offers a lot of options (but you'll have to do
lots of typing!).
When you've done experimenting,you'll want to produce your own
program with [Link] does the program find whether a menu item
in a menu has been clicked on?
You already looked at one way to find out the menus [Link] can
test the CHECKED bit in the flag word of a menu [Link] this is
set,the user clicked on this item with the mouse.
This only works if checking is allowed for the item being tested.
You could allow all the menu items to be checked,but this still
isn't a good solution--it requires testing all the flag bits of
all the menus one after the [Link] makes very boring
programming.
You've already learned about finding about events from Intuition.
You've moved the message about which event took place into D6,and
you can look at it to find out what happend.
If you set the eight bit,the MENUPICK bit,of the IDCMP flag long
word in the window definition,the choice of the menu point is
[Link] the following lines in your loop in the main program.

loop:
move.l execbase,a6 ;exec base address in A6
move.l windowhd,a0 ;window structure pointer
move.l 86(a0),a0 ;user point pointer in A0
jsr getmsg(a6) ;get message
tst,l d0 ;whay happend?
beq loop ;nothing happend
move.l d0,a0 ;message pointer in A0
move.l $14(a0),d6 ;event in D6

If the program makes it out of the loop,an event as taken place.


You have the events flag in the D6 [Link] can evaluate the
event using CMP or BTST to find out which flag bits are [Link]
can then execute the function corresponding to the set [Link] can
use lines like the following ones:

cmp #$200,d6 ;WINDOWCLOSE?


beq ende ;yes:program end

These lines terminate the program when the window is closed.

If the user chose a menu item,there is a $100 in the D6 register.


You now need to determine which item it was.
You can find this information in a word that comes right after the
long word with the event flags in the message [Link]:

move $18(a0),d7

You now have the code for the clicked menu item in the D7
[Link] the user just pressed the right key and let it go
without choosing a menu item,you'll find a $FFFF [Link] word
doesn't contain just one,but three pieces of information:

Which menu was the item chosen from?


Which menu item?
Which submenu?

The information is divided in three bit [Link] division is as


follows:

Bits 0-4 Menu title number


Bits 5-10 Menu item number
Bits 11-15 Submenu item number

The numbering begins with zero-ie the first menu point of the
first menu has the numbers 0 and 0.

To try this out insert the following lines:

move d7,d6 ;move code into D6


lsr #8,d7 ;shift right 11 times
lsr #3,d7 ;submenu item now in D7
clr.l d5
roxr #1,d6 ;bit 0 in X-flag
roxl #1,d5 ;menu number now in D5
and.l #$7f,d6 ;issolate lower bits
cmp #$7f,d6 ;no menu item?
beq loop ;no:continue
lsr #4,d6 ;else menu item in D6
ende

By making a test run with AssemPro,you can easily see if this


works right-just look at the registers after the program is over.
If you,for example,want to write a program with four menus with 10
menu items each,this sort of method is too much work-there are 44
[Link] this reason,lets look at a short program that takes
care of the necessary structure table itself.
The menu structure is built very simply-it doesn't offer submenus
or the option of choosing items via the [Link] you want these
extras,you can still use this program,but you'll have to use MOVE
commands to insert the desired flags and pointers.
The input that this program needs is a list of the menu names and
the items in each [Link] addresses of the menu texts go in a
table with the following simple form:

dc.l Menu title 1


dc.l Point1,Point2,Point3,...,0
dc.l Menu title 2
dc.l Point1,Point2,Point3,...,0
dc.l Menu title 3 oder 0

This program is set up in such a way that up to four menus can lie
next to each other (in normal screen resolution),which is often
[Link] table above ends by putting a zero instead of a pointer
to the nxt menu [Link] you can see,its pretty simple.
This program is inserted in your big program right behind the
"setmenu"[Link] the "bsr setmenu"command is executed,the menu
structure is built and initialized at the same [Link] don't need
to change the rest of the program,it'll be shorter that way.

Heres the program fragment for the complete "setmenu"routine:

setmenu: ;*initialize menu structure


lea mentab,a0 ;pointer to text pointer in A0
lea menu,a1 ;pointer to menu field in A1
move #10,d1 ;horizontal menu position=10

menuloop:
clr.l d2 ;vertical menu position=0
move.l a1,a2 ;save address of pointer
tst.l (a0) ;another menu there?
beq setmenu1 ;no:quit
clr.l (a1)+ ;"no more menus"preperations
move d1,(a1)+ ;set X-position
add.l #70,d1 ;and increment
move.l #50,(a1)+ ;Y-position and width
move.l #$a0001,(a1)+ ;height and flag
move.l (a0)+,(a1)+ ;menu title
lea 12(a1),a3
move.l a3,(a1)+ ;pointer to menu item
clr.l (a1)+ ;reserved words
clr.l (a1)+

itemloop:
tst.l (a0) ;last entry?
beq menuend ;yes:menu done
lea 54(a1),a3
move.l a3,(a1)+ ;pointer to next item
move.l d2,(a1)+ ;X- and Y-positions
add #10,d2 ;Y-position+10
move.l #$5a000a,(A1)+ ;WIDTH/HEIGHT
move #$52,(a1)+ ;flag:normal
clr.l (a1)+ ;no connection
lea 16(a1),a3
move.l a3,(a1)+ ;text structure pointer
clr.l (a1)+ ;no fill structure
clr.l (a1)+ ;no command,no submenu
clr.l (a1)+ ;and no continuation
move #$1,(a1)+ ;set text structure:colour
clr.l (a1)+ ;mode 0
move.l #$50003,(a1)+ ;X- and Y-position
clr.l (a1)+ ;standard character set
move.l (a0)+,(a1)+ ;text pointer
clr.l (a1)+ ;no continuation
bra itemloop ;next item...

menuend: ;eventual transfer to next menu


clr.l -54(a1) ;erase pointer to next item
tst.l (a0)+ ;increment table pointer
tst.l (a0) ;another menu there?
beq setmenu1 ;no:done
move.l a1,(a2) ;pointer to next menu
bra menuloop ;and continue
setmenu1: ;*initialize menu (like before)
move.l intbase,a6 ;intuition base address in A6
move,l windowhd,a0 ;window structure in A0
lea menu,a1 ;pointer to menu structure
jsr setmenustrip(a6)
rts

You need three things yet for this program:the memory to be used
for the structure,the table of text pointers and the [Link] an
example:

mentab:
dc.l menu1 ;first menu title
dc.l mp11,mp12,mp13 ;menu items
dc.l 0 ;end of menu 1
dc.l menu2 ;second menu title
dc.l mp21,mp22,mp23 ;menu items
dc.l 0 ;end of menu 2
dc,l 0 ;you're out of menus!

;** Menu Text **


menu1: dc.b "Menu 1",0
mp11: dc.b "Point11",0
mp12: dc.b "Point12",0
mp13: dc.b "Point13",0
menu2: dc.b "Menu 2",0
mp21: dc.b "Point21",0
mp22: dc.b "Point22",0
mp23: dc.b "Point23",0
align
;** Storage space for menu structure **
menu: blk.w 500

Make sure that the memory area reserved for the menu structure is
big enough and change the entry "blk.w 500"to the calculated
value.
If you use this program,and want to build some special features
into the menu (for instance key commands),you can make entries in
the menu structure table while the program is [Link] can find
the word (or byte or long word) that interests you in the table as
follows:

For example,to find the keyboard command byte of the second entry
in the first menu,calculate as follows:

Address = Start_address+Menu*30+(entry-1)*54+26

which in the example comes to:

Address = menu+30+54+26
= menu+110

The 26 is the distance from the beginning of the MenuItem


structure to the desired byte,the command [Link] this way,you can
calculate the addresses and use MOVE commands to modify the menu
to fit your [Link] the way,in the example above,the correspond-
ing flag bit must be set as well,so that the keyboard command is
recognized.
Now lets get back to the [Link] nice to have a window that you
can change and close,but you really want to be able to output text
in a window!

[Link] Output.
----------------
Its very easy to use Intuition's text output [Link] the
PrintIText function (offset -216).It needs four parameters.

In A0 A pointer to the RastPort of the [Link] can find this


in the window structure.
In A1 A pointer to the text structure of the text that should
be output.
In D0 The X-position.
In D1 The Y-position of the text in the window.

Its very easy to enter the X- and [Link]'ve already used


the text structure twice (for requesters and menus).
Whats new is accessing the windows [Link] RastPort is a
structure that describes the [Link] address is needed by
several Intuition functions.
The pointer to the RastPort starts at the 50th byte in the window
[Link] can access it as follows:

move.l windowhd,a0 ;address of window structure


move.l 50(a0),a0 ;RastPort address in A0

Now you've got the address of the [Link] write a routine


that prints a [Link] X- and Y-positions are in D0 and D1
respectively and the address of the text structure in A1 before
the routine is called:

PrintIText = -216
...
print:
move.l intbase,a6 ;intuition base address in A6
move.l windowhd,a0 ;address of window structure
move.l 50(a0),a0 ;rastport address in A0
jsr printitext(a6) ;call function
rts

You can try out this routine by using the requesters text that is
still in a structure of the [Link] the following lines
before the "loop"label:

lea btext,a1 ;pointer to text structure in A1


move.l #10,d0 ;X-position
move.l #30,d1 ;Y-position of text
bsr print ;output text

Start the program and the text appears in the middle of the window
If this doesn't happen,check the colour of the text in the text
[Link] probably [Link] change it to three,and the text
appears in red the next time you start the program.

[Link].
-----------
An image is a drawing that goes in a rectangular field and is
defined [Link] disk symbol of the Intuition screen and the
system gadgets in the screen and window borders are examples of
such Images.
The rectangle that the drawing goes in can be arbitrarily large,
but each pixel in the rectangle needs its own bit,so programming
screen-sized Images isn't [Link]'ll stick to an Image that
requires about 32x16 bits-an Image thats about 3x1cm.
You can make all sorts of images as you've seen looking at window
[Link] is an Intuition functionthat draws an Image:It is
the DrawImage function (offset -114) and it needs 4 parameters:

In A0 The address of the rastport image is drawn [Link]'ve


already learned how to access this address in the section
on the text function.
In A1 The structure address of the image to be drawn.
In D0 The relative X-position
In D1 The relative Y-position of the drawing.

Lets draw this picture in your [Link] justs takes a simple


[Link] just need to put the address of the image structure in
A1 and the position of the image in D0 and D1 before you call it.

DrawImage =-114
...
draw: ;*draw image
move.l intbase,a6 ;intuition base address in A6
move.l windowhd,a0 ;pointer to window structure
move.l 50(a0),a0 ;now,rastport address in A0
jsr drawimage(a6) ;draw image
rts

Now you need the structure of the [Link] structure contains


nine entries which have the following meanings:

The first two entries are words which specify the distance in the
X- and Y-direction from the co-ordinates that were given to tell
where the image should be [Link]'ll just put two zeros here:

image:
dc.w 0,0 ;X- and Y-position
Next come two words which specify the width and height of the
image in [Link] draw a 32x13 point [Link]:

dc.w 32,13 ;width and height of image

The next word in the list specifies the number of planes in the
[Link] its a simple image that only uses two colours,just
enter a [Link] more colours,you'll need a correspondingly bigger
[Link] more colurs are worked with,the bit pattern of the
image must have more [Link] just have one bit plane:

dc.w 1 ;one bitplane:2^1=2 colours

Next comes a long word that points to the data of the image:

dc.l imgdata ;pointer to image data

The next two bytes are very [Link] first byte,the


PlanePick byte,tells which plane of the window or screen the image
data should be written [Link] you only have one plane,you need
to enter the bit plane of the [Link] information is found in
the bits of the byte-bit0 stands for plane 0,bit 1 for plane 1,etc
..You also define the colour of the image with this [Link] you
enter a two,every set bit of your image represents a red point.

dc.b 2 ;drawing red:plane 1

The second byte,the PlaneOnOff byte,is an interesting enhancement.


Each bit of the window bit plane corresponds to a whole number
[Link] only bytes that are interesting though are the ones that
are cleared in the PlanePick [Link] the bit is set in PlaneOnOff,
evert bit of the image in the corresponding plane is [Link]
they are [Link] make sure that each bit of the image that
isn't set appears white,enter a [Link] the bits of the image that
aren't set,are set in Plane 1 and appear white.

dc.b 1 ;background:white

The last entry of the structure is a lobg word that points to


another [Link] don't need this,so set the long word to zero:

dc.l 0 ;no more images

Heres a quick overview of the image structure:

image:
dc.w 0,0 ;X- and Y-positions
dc.w 32,13 ;width and height of image
dc.w 1 ;one bitplane:2^1=2 colours
dc.l imgdata ;pointer to image data
dc.b 2 ;drawing red:plane 1
dc.b 1 ;background:white
dc.l 0 ;no more images

Now lets produce the image [Link] image row uses a word,long
word,or several of these represent the [Link] set points of
the image correspond to the set [Link] is repeated as often as
the height of the image [Link] data on each line must begin
on a word border,on a even address.
For the example,its easy to decide on the data,since you're going
32 points across-that corresponds to exacty one long [Link]
easiest to program the image using the binary representation of
the data.
Lets use,as an example,an image that represents a switch in "OFF"
[Link] form is chosen for a good reason,so you should type it
[Link] the chapter on gadgets thats coming up,we'll show you how to
turn the switch [Link] is the example data for the switch image:

imgdata: ;Data for switch in "OFF" mode


dc.l %00000000000000000000000000000000
dc.l %00000000000000000000111000000000
dc.l %00011101110111000001111100000000
dc.l %00010101000100000001111100000000
dc.l %00010101100110000001111000000000
dc.l %00011101000100000011100000000000
dc.l %00000000000000000111000000000000
dc.l %00000000000000001110000000000000
dc.l %00000000000111111111100000000000
dc.l %00000000001111111111110000000000
dc.l %00000000001111111111110000000000
dc.l %00000000000110000001100000000000
dc.l %00000000000000000000000000000000

Once you've typed in this data,you can experiment with displaying


it on the [Link] the following lines before the "loop"label:

move.l image,a1 ;pointer to image structure


move #30,d0 ;X-postion in window
move #50,d1 ;Y-position
bsr draw ;draw image

How do you like the image on the screen?You'll run into this
switch again when we talk about putting the switch in the "ON"
state when discussing [Link] need to look at other methods of
drawing in the window first,though.

[Link].
------------
A border is a collection of lines that are [Link] can be
of any length or at any [Link] lets you draw borders to
do things like put frames around windows and [Link] are used
to put borders around pictures or text,especially for use with
string [Link]'ll talk about that later,though.
Its easy to draw [Link] use the Intuition function
DrawBorder (offset -108) which needs four parameters:

In A0 The rastport address of the output medium the lines should


be drawn [Link] your window.
In A1 The address of the border [Link]'ll look at the form
of this structure shortly.
In D0 The relative X-co-ordinate which is used with the X- and Y
co-ordinate list to calulate the actual line co-ordinates.
In D1 The relative [Link],here too,means that
this is relative to the upper left corner of the screen.

Lets write a short routine that is called with three parameters.


The structure address in A1 and the X and Y co-ordinates are in D0
and D1 respectively when the routine is [Link] border is drawn
in the window whose structure address is in "windowhd".

DrawBorder =-108
...
borderdraw: ;* draw several lines
move.l inbase,a6 ;intuition base address in A6
move.l windowhd,a0 ;pointer to window structure
move.l 50(a0),a0 ;now rastport address in A0
jsr drawborder(a6) ;draw lines
rts

Now lets look at the border [Link] list needs the eight
following parameters:

First,you need two words for the vertical and horizontal distance
from the co-ordinates given in the function [Link] avoid losing
sight of some of the many distance entries,put two zeros here:

border:
dc.w 0 ;horizontal distance
dc.w 0 ;vertical distance

Next come two bytes that determine the [Link] a red frame:

dc.b 3 ;red frame


dc.b 0 ;background (unused)

As you can see,the background colour isn't [Link] have two modes
to choose between for drawing the [Link] following mode
determines the mode that is [Link] it is zero,each line is drawn
in the colour chosen,no matter what was done [Link] is the
JAM1 [Link] other mode is the XOR mode which ignores both colour
[Link] this mode,all the points that lie under the line have
their colour value [Link] a result,a white point becomes
black,and a blue one becomes [Link] is mode [Link] use the
JAM1 mode for the example:

dc.b 0 ;mode:JAM1 (2=XOR)

The next entry specifies how many co-ordinate pairs there are in
the [Link] this word must be on an even address,you need to
use the "align"peudo-op [Link] enter the number of pairs.
Remember that you need three points to draw two lines:beginning,
corner and end [Link] draw a rectangular frame,you need five
pairs:

dc.b 5 ;5 X,Y pairs used together

The next item is a pointer to the co-ordinate table that contains


a list of points to be connected:

dc.l coord ;pointer to cordinate table

The border structures final entry is a long word that can point to
another border [Link] you don't have any more structures to
be pointed to,just enter a zero [Link] pointer is useful for
connecting two independant border structures-for example,to
produce a two coloured frame that really stands [Link] don't need
this pointer in the example,though:

dc.l 0 ;no more structures

Thats the border [Link] lets look at the co-ordinate list.


For the example,it consists of five pairs of numbers which
represent a rectangle.I recommend entering these values,because
you'll use them in example programs further down the line.

coord: ;coordinates for rectangle frame


dc.w -2,-2
dc.w 80,-2
dc.w 80,9
dc.w -2,9
dc.w -2,-2

Heres a quick overview of the border structure:

border:
dc.w 0 ;horizontal distance
dc.w 0 ;vertical distance
dc.b 3 ;red frame
dc.b 0 ;background (unused)
dc.b 0 ;mode:JAM1 (2=XOR)
dc.b 5 ;5 X,Y pairs used together
dc.l coord ;pointer to cordinate table
dc.l 0 ;no more structures
coord: ;coordinates for rectangle frame
dc.w -2,-2
dc.w 80,-2
dc.w 80,9
dc.w -2,9
dc.w -2,-2

Once you've typed this in,you can try the whole thing [Link] the
following lines before the "loop"label in the program:

lea border,a1 ;address of the border structure


move #20,d0 ;X base position
move #80,d1 ;Y base position
bsr drawborder ;draw frame

As you can see,using enough X and Y co-ordinates,you can draw the


Eiffel [Link] enough about simple [Link] want to put
some life into your drawings and [Link] manipulate them with
the mouse!

[Link].
------------
We already talked a bit about gadgets when you looked at screen
[Link] at system gadgets like the window close
symbol,you can activate by clicking and causes a program function
to be executed.
You can make your own gadgets as [Link] allows you a lot
of interesting possibilities.

There are four types of gadgets:

Boolean gadgets are used in Yes/No [Link] can click and


activate it (Yes) or deactivate it (No).

String gadgets are used to accept input of text of a specified


length.

Integer gadgets are a special sort of string gadgets which accept


the input of a decimal [Link] converts the value into a
long word and sends it to the program.

Proportional gadgets let you choose an analog value with the mouse
You can move these around with the mouse.

[Link] Gadgets.
----------------------
Lets start with the simplest type,the boolean [Link] example of
this sort of gadget is the close symbol of the [Link] only
status it differenciates between are clicked and not [Link]
develop a gadget of this type step by [Link] flags and other
parameters are similar for the other gadgets.
Each gadget needs a structure containing fifteen [Link] is
a pointer to this structure in window,screen or requester that the
gadget is to appear [Link] always a long word available for
this [Link] to this point,you've just put a zero [Link]
there is an address of a gadget structure there,the gadget or
gadgets are displayed when the window is opened.

A gadget structure as the following entries:

The first long word is a pointer to the next gadget to be


[Link] gadgets are displayed in a row,like pearls on a
[Link] pointer is the first gadget in this linked list of
[Link] you just want one gadget in your window,put a zero
here:

gadget1:
dc.l 0 ;no more gadgets

The next two words determine the position of the gadget in the
[Link] are several ways to determine the [Link] flags
to access the various [Link] start with a gadget that
stays in one spot:

dc.w 40 ;X and
dc.w 50 ;Y position of the gadget

The next two words determine the size of the gadgets Hit [Link]
box isn't the visible size of the gadget (that depends on the
image data).It is the size of the rectangle that Intuition should
[Link] the mouse pointer is moved into this box and the left
button pressed,the gadget is [Link] on parts of the
gadget that are outside this box have no effect!

dc.w 32 ;width and


dc.w 13 ;height of the hit box

Next comes the word whose bits determine the properties of the
[Link] 0 and 1 determine what should happen when this objects
hit box is clicked [Link] meanings of the various values of these
bits go as follows:
Bit 0 1 Value Name Meaning
------------------------------------------------------------------
0 0 0 GADGHCOMP The gadget inverted
0 1 1 GADGHBOX The gadget framed
1 0 2 GADGHIMAGE Another image appears
1 1 3 GADGHNONE No reaction

Bit 2 determines whether the gadget should consist of a drawing or


a [Link] it is set(Value+4),it is treated as an image;otherwise
its treated like a border.
The next bit determines if the gadget should appear in the upper
or lower border of the [Link] it is set(Value+8).the position is
relative to the lower border;otherwise it is relative to the upper
[Link] next bit as the same meaning for the horizontal
[Link] set(Value+$10),it is a relative [Link],
it is an absolute positioning.
Notice that when you define a gadget to be relative,you must have
a negative value in the position input in the first word of the
[Link] the desired position isn't under,but its over this
position!
In this way,you can choose either absolute or relative positioning
of the [Link] example of a gadget that is positioned absolutely
is the system gadget,close [Link] example of a relative gadget
is the symbol for changing the size.
The width and height of the gadgets hit box can also be relative
to the window [Link] this by using bit 5 for width (Value +
$20)and bit 6 for the height (Value +$40).A set bit mens a
relative size.
Bit 7 (Value+$80)makes the object active as soon as the window is
opened.
Bit 8 (Value+$100)determines whether the gadget can be used or not
If this bit is set,the gadget can't be activated.
For the example,you'll use absolute positioning and size,the
inverted appearance for the activated gadget,and the
representation of the object as an [Link] means you must use
the value four:

dc.w 4 ;flags:image,invert

Next comes a word whose bits are used as [Link] flag is called
the Activation [Link] determines the functions of the [Link]
bits,their values and meanings follow:

Bit Value Name Meaning


------------------------------------------------------------------
0 1 RELVERIFY Causes the gadget to be activated
only when the left mouse key is let
loose over the gadget.
1 2 GADGIMMEDIATE Lets the gadget be active as soon as
there is a click.
2 4 ENDGADGET Lets you choose to end this choice
and have it disappear if this is a
requester gadget.
3 8 FOLLOWMOUSE Lets the gadget know the mouse
position at regular intervals from
the time it is selected until the
time it is [Link] can use
this to move the gadget with the
mouse when you want to change the
gadget position.
4 $10 RIGHTBORDER This makes sure thay when borders
are used that the page is adjusted
to the size of the gadget so that it
fits in the border.
5 $20 LEFTBORDER
6 $40 TOPBORDER
7 $80 BOTTOMBORDER
8 $100 TOGGLESELECT Allows the objects state to change
every time it is [Link]
activated,it becomes deactivated and
vice versa.
9 $200 STRINGCENTRE For a string gadget,these two bits
determine whether the string should
appear centred or right [Link]
neither is set,the string is output
left justified.
10 $400 STRINGRIGHT
11 $800 LONGINT Turns a string gadget into a Integer
gadget (explanation later).
12 $1000 ALTKEYMAP Causes another ketboard placement to
be in effect for string gadget input

Thats it for the activation [Link] choose the TOGGLESELECT and


GADGETIMMEDIATED flags for example:

dc.w $102 ;activation

The next word of the gadget structure determines the gadget type.
Heres the meaning of the individual bits:

Bit Value Name Meaning(report what circumstances)


----------------------------------------------------------------
0 1 BOOLGADGET This is a boolean gadget
1 2 GADGET002
2 4 STRGADGET String order Integer gadget
0+1 3 PROPGADGET Proportional gadget

System gadgets:
4 $10 SIZING Size changing gadget
5 $20 WDRAGGING Moving gadget for window
4+5 $30 SDRAGGING Same for screen
6 $40 WUPFRONT Gadget to move window forward
6+4 $50 SUPFRONT Gadget to move screen forward
6+5 $60 WDOWNBACK Move window back
6+5+4 $70 SDOWNBACK Move screen back
7 $80 CLOSE Window close gadget

Type definitions:
12 $1000 REQGADGET Requester gadget
13 $2000 GZZGADGET Border gadget in GIMMEZEROZERO
window
14 $4000 SCRGADGET Screen gadget when set
15 $8000 SYSGADGET System gadget when set

You want to use a simple boolean gadget for your example,so enter:

dc.w 1 ;gadget type:boolean


Next comes a pointer to the gadget [Link] first pointer
contains the address of the image or border structure which should
be used to represent the [Link] no representation is needed,put
a zero [Link] want to represent the gadget as an image,so put a
pointer to the image structure that you produced in the chapter
about images:

dc.l image ;gadget image

The next pointer is only used if the GADGHIMAGE flag in the flag
word of the structure is [Link] is a pointer to another
structure that should be put on the screen when the object is
[Link] a border structure is used for the gadget represent-
ation,this must be a border structure as [Link] won't use a
second image,so put a zero here:

dc.l 0 ;no new gadget displayed

The next pointer is to the text structure that should be output by


the [Link] no text is needed,just put a zero [Link] want to
use some text,however:

dc.l ggtext ;gadget text

Now comes a long word that determines which gadgets are


deactivated when this is [Link] function still doesn't
work right so put a zero here:

dc.l 0 ;no exclude

You'll set the next pointer to zero as well,because it is only


used for String and Proportional [Link] these gadgets,this is
a special structure to describe the characteristics of the gadget.
Its called SpecialInfo.

dc.l 0 ;no SpecialInfo

The next word contains the Gadget Identification (ID) number:

dc.w 1 ;gadget ID

Finally there is a long word that doesn't have any function,so put
a zero here:

dc.l 0 ;user data (ignore)

Thats [Link] a quick overview of the gadget structure:

gadget1:
dc.l 0 ;no more gadgets
dc.w 40 ;X and
dc.w 50 ;Y position of gadget
dc.w 32 ;width and
dc.w 13 ;height of hit box
dc.w 4 ;flags:image,invert
dc.w $102 ;activation flags
dc.w 1 ;gadget type:boolean
dc.l image ;gadget image
dc.l 0 ;no new gadget displayed
dc.l ggtext ;gadget text
dc.l 0 ;no exclude
dc.l 0 ;no SpecialInfo
dc.w 1 ;gadget ID
dc.l 0 ;user data (ignore)

You've already prepared a structure that you can use for this
[Link] you need the text that appears under the gadget.
Since the gadget looks like a switch,label it "switch".The text
structure looks like this:

ggtext:
dc.b 1,0 ;colours
dc.b 1 ;mode
align
dc.w -8,14 ;X and Y position
dc.l 0 ;standard font
dc.l swtext ;pointer to text
dc.l 0 ;no more text
swtext:
dc.b "switch",0
align

Once you've typed this in,save it,assemble it and start [Link]


can click the switch and cause it to be [Link] it again,
and it appears normal.
Now you can experriment with the [Link] you change the flag
from four to five,you can cause the gadget to be framed when it is
[Link] the RELVERIFY bit(bit0:+1)in the Activation Flag
[Link] you can move the mouse pointer onto the object and press
the [Link] is [Link] the mouse button pressed down and
move the [Link] you leave the hit box,the activation disapears
This way,you can avoid accidently activating a gadget.
Now you want to display the switch in an on [Link] is [Link]
you need to do is produce another image structure,one for the on
[Link] put this pointer in the long word right after the
pointer to the normal image [Link] can change the flag word
to six which causes a second image to be displayed when the gadget
is activated.
Here is the image structure for the switch in the one state.

image2:
dc.w 0,0 ;no offset
dc.w 32,13 ;32x13 pixels
dc.w 1 ;mode 1
dc.l imgdata2 ;pointer to the data
dc.b 2,1 ;same colours as before
dc.l 0 ;nothing else

imgdata2: ;data for switch in the On state


dc.l %00000000000000000000000000000000
dc.l %00000000011100000000000000000000
dc.l %00000000111110000011101001000000
dc.l %00000000111110000010101101000000
dc.l %00000000011110000010101011000000
dc.l %00000000000111000011101001000000
dc.l %00000000000011100000000000000000
dc.l %00000000000001110000000000000000
dc.l %00000000000111111111100000000000
dc.l %00000000001111111111110000000000
dc.l %00000000001111111111110000000000
dc.l %00000000000110000001100000000000
dc.l %00000000000000000000000000000000

Now the state of the object can be determined by looking at the


[Link] the gadget is activated,the switch is [Link] not,the
switch is off.
Thats it for boolean [Link] can learn about the things you
did'nt touch with some [Link] want to get to the
string gadgets that also do some interesting things.

[Link] Gadgets.
---------------------
Lets pretend you want a program to load data from the [Link] get
the user to enter the filename,you need to output text telling the
user to enter the [Link] you need to call an input routine to
evaluate the keyboard input.
Its easier and more elegant to use a String [Link] function
allows for easy input and/or editingof short [Link] have the
option of having the text [Link] Undo function can be used by
pressing the right <Amiga> key and a "Q",and the old contents of
the gadget,the old text are restored.
You can also vary the size of the text and the input [Link] the
text is longer than the input field is wide,the text is moved back
and forth through the visible area when you move the cursor keys
or the normal input to the border.
You can also restrict input to just [Link] makes it posible
to accept numeric [Link] even converts the digit string
into a binary [Link] saves the machine language programmer
some work.A specialized String gadget of this sort is called a
Integer gadget.
The structure is similar to the Boolean gadgets [Link]
are only two major differences:

The type word of the structure must be a four to declare that this
is a String gadget (STRGADGET).

The pointer to the SpecialInfo structure is [Link] a pointer


to the StringInfo structure that you are going to design later
here.

The width and height entries in the gadget structure have a


different meaning than they had [Link] do declare the
area in which you can bring the mouse pointer to activate the
String [Link],it is also used for representation of text.
These values determine the size of the box in which the text is
[Link] should surround the box with a border using the Border
function,so that the user can see where it is.
If the text is longer than the box,only a portion of it is seen on
the [Link] can move through the area by entering text or using
the left/right cursor keys to move through the [Link] characters
that are entered are inserted at the cursor position,so the rest
of the text is shifted by one character when you are on the right
edge of the input [Link] following functions can be used for
editing this text:

Cursor key left/right


Moves the cursor over the text thats already on [Link]
the text through the Container.

Cursor keys with <Shift>


Puts the cursor on the beginning or the end of the text.

<Del> Deletes the character under the cursor.

<Backspace>
Deletes the character to the left of the cursor.

<Return>
Ends text input.

<Amiga>right+"Q"
This is the Undo [Link] replaces the text with the
original contents.

The StringInfo structure only has a few entries:

First theres a pointer to the memory area that is used to store


the text that is [Link] memory buffer must be big enough to
handle all the text entered.

strinfo:
dc.l strpuffer ;pointer to text buffer

Next comes the pointer to the Undo [Link] pointer and this
buffer are only needed if you want the Undo [Link] you do,you
must have a buffer that is at least as big as your text buffer.
Every time the string gadget function is called,the text buffers
contents are copied into this [Link] get the old contents back,
just press the right <Amiga>key and the "Q"[Link] contents of the
Undo buffer are copied back to the text [Link] you use several
string gadgets in a program,you can use the same Undo buffer for
all of them,since only one string gadget is used at one time.

dc.l undo ;pointer to undo buffer

The following word contains the cursor position in the [Link]


should set this word to zero,so that the user can see the
beginning of the text when the string gadget appears.

dc.w 0 ;cursor position

The next word contains the maximum number of characters that can
be [Link] you type one more than this number of characters,the
screen blinks,to show that you can't enter a longer input string.
The number of characters and the reserved space for the input
field don't have to agree,since text can be scrolled by typing.

dc.w 10 ;maximum # of characters

The following word tells at which character of text in the buffer,


the output to the box should [Link] should put a zero here,so
that the user can see the beginning of the text.

dc.w 0 ;output text from this character


The next five words are used by Intuition,so you don't have to
initialize [Link] put zeros [Link] words contain the
following information:

dc.w 0 ;character position in undo buffer


dc.w 0 ;number of chars in text buffer
dc.w 0 ;number of chars visible in box
dc.w 0 ;horizontal box offset
dc.w 0 ;vertical box offset

The next two long words are initialized by Intuition as well:

dc.l 0 ;pointer to rastport


dc.l 0 ;long word with value of the input
; ;(for integer gadgets)

The final entry is a pointer to the keyboard table that is used if


the ALTKEYMAP flag of the gadget is set.

dc.l 0 ;standard keyboard table

Heres a quick overview of the StringInfo structure:

strinfo:
dc.l strpuffer ;pointer to text buffer
dc.l undo ;pointer to undo buffer
dc.w 0 ;cursor position
dc.w 10 ;maximum # of characters
dc.w 0 ;output text from this character
dc.w 0 ;character position in undo buffer
dc.w 0 ;number of chars in text buffer
dc.w 0 ;number of chars visible in box
dc.w 0 ;horizontal box offset
dc.w 0 ;vertical box offset
dc.l 0 ;pointer to rastport
dc.l 0 ;long word with value of input
; ;(for integer gadgets)
dc.l 0 ;standard keyboard table

Here are the text and undo buffers:

strpuffer:
dc.b "Hello!",0,0,0

undo:
dc.l 0,0,0,0
align

Once you've entered these lines,you can either alter the old
gadget structure or build a new [Link]'d recommend building
another gadget structure so that you can have the switch and use
it [Link] the first pointer in the old structure from zero
to "gadget1"and insert this new [Link] is an example
strucure for the string [Link] as the following entries:

gadget1: ;*structure for string gadget


dc.l 0 ;no more gadgets
dc.w 20,80 ;position
dc.w 80,10 ;width and height of box
dc.w 0 ;flags:normal
dc.w 2 ;activation($802 for long int)
dc.w 4 ;type:string gadget
dc.l border ;pointer to border
dc.l 0 ;no drawing selected
dc.l 0 ;no text
dc.l 0 ;no exclude
dc.l strinfo ;pointer to stringinfo structure
dc.w 2 ;gadget ID
dc.l 0 ;no user data

border: ;*border for box frame


dc.w 0,0 ;no offset
dc.b 3,3 ;red colour
dc.b 0 ;mode:JAM1
dc.b 5 ;5 X,Y pairs
dc.l coord ;pointer to coordinates table
dc.l 0 ;no more structures

coord: ;*coordinates for frame


dc.w -2,-2 ;start in upper left corner
dc.w 80,-2 ;upper right
dc.w 80,9 ;lower right
dc.w -2,9 ;lower left
dc.w -2,-2 ;back to beginning

This data causes a red rectangle,the border,to appear around the


"Hello!"[Link] can change the text by clicking in the field and
editing once the cursor [Link] you type something wrong,you
can use the undo function(the right <Amiga> key and the Q key),to
get "Hello!"back.
Once you've done some typing and deactivated the gadget by
pressing <Return> or by clicking outside the field (cursors
disapear),you can terminate the program.
Change the activation flag to $802 and the "strbuffer"to "dc.l
0,0,0,0",assemble,and then start the [Link] can type in the
string gadget once it has been activated,but you can only enter
[Link] screen blinks if you enter letters.
Enter a number,and then end the program after deactivating the
[Link] you look at the stringinfo structure you can look at the
value of the number you input(in hex)in the eight long word.
After looking at boolean,text and numeric input to gadgets,lets
look at Proportional gadgets which allow the user to enter analog
values by moving a symbol.

[Link] Gadgets.
---------------------------
You've seen the advantages of slider devices over knobs that you
turn,maybe on a hifi,maybe on a toaster,but certainly someplace.
Its easier to tell the state the item is in with a slider,
especially if several such devices are next to each other(for
example graphic equalizers).You can represent sliders on the
Amigas screen and work with them with the [Link] offers a nice
way to represent information graphically in your programs.
You can do this with [Link] Proportional gadgets,you can
put a symbol in a frame and move horzontally and/or [Link]
size of the frame and the slider can be variable size,so that the
frame size is relative to the screen size so when the window
changes size,it will [Link] slider can be set up so that its
size in the grows or shrinks.
These are best seen via example and experimentation.(The
posibilities mentioned do not form a complete list by any stretch
of the imagination.)You want to set up a simple Proportional
gadget that can be moved horizontally.
You need a gadget structure that as the same form as [Link]
show the differences,heres a complete example structure for your
[Link] can connect this gadget to the other one,by changing
the first long word in the last structure to "dc.l gadget2".

gadget2: ;*structure for Proportional gadget


dc.l 0 ;no more gadgets
dc.w 150,30 ;position
dc.w 100,10 ;width and height of frame
dc.w 4 ;flags:GADGIMAGE
dc.w 2 ;activation:GADGIMMEDIATE
dc.w 3 ;type:proportional gadget
dc.l mover ;pointer to slider data
dc.l 0 ;no select structure
dc.l 0 ;no text
dc.l 0 ;no exclude
dc.l propinfo ;pointer to propinfo structure
dc.w 3 ;gadget ID
dc.l 0 ;no user data

You see two special [Link] an image structure for the mover
and put a pointer to another structure in the spot for the Special
Info pointer.
First,lets look at the "mover"structure,the sliders image
[Link] an example of this structure:

mover: ;*structure for slider image


dc.w 0,0 ;no offset
dc.w 16,7 ;16x7 pixels big
dc.w 1 ;one bit plane
dc.l moverdata ;pointer to image data
dc.b 1,0 ;colour:white
dc.l 0 ;don't continue

moverdata: ;*image data for mover


dc.w %0111111111111110
dc.w %0101111111111010
dc.w %0101011111101010
dc.w %0101010110101010
dc.w %0101011111101010
dc.w %0101111111111010
dc.w %0111111111111110

Up till now,there was'nt anything [Link] lets look at the


PropInfo structure that describes the properties of the
Proportional gadget.

The structure starts with a flag word that contains the following
bits:

Bits Value Name Meaning


-----------------------------------------------------------------
0 1 AUTOKNOB Mover is set up automatically
1 2 FREEHORIZ Allows horizontal movement
2 4 FREEVERT Allows vertical movement
3 8 PROPBORDERLESS Turns off automatic framing
8 $100 KNOBHIT Set when the mover is touched

You can set the first four bits to get the representation that you
[Link] 8 is set by Intuition when the mover is clicked with the
mouse pointer.
Bit 0,AUTOKNOB,allos for the simplest sort of Proportional gadget.
If this bit is set,no move data are used for the mover image.
Instead,a white mover is generated that is adjusted to the size of
the box and the values to be [Link] you use this slider
to represent the displayed lines in a long text of a program,the
displayed lines are a percentage of the total [Link]
relationship between the total number of lines and the lines shown
is represented by an AUTOKNOB as the relationship between the
frame and the [Link] bigger the percentage,the bigger the
slider [Link] don't want to work with this though,even though it
is simple and interesting,because a simple white button isn't
particularly [Link] you experiment with it,make sure that
the pointer to the image data points to a four word long buffer
that Intuition can use to store [Link] buffer is of the
following form:

buffer:
dc.w 0 ;X position of the slider in the box
dc.w 0 ;Y position in the box
dc.w 0 ;width of slider
dc.w 0 ;height of slider

Leys look at the PropInfo [Link] you're not using


AUTOKNOB and wish to allow horizontal movement only,put two in as
a flag:

propinfo:
dc.w 2 ;flags:FREEHORIZ

In the next two words of the structure,the horizontal (HorizPot)


and vertical (VertPot) position of sliders are stored.A value of
zero means left or upper,while the value $FFFF means right or
[Link] value that results from movement is in this [Link]
set these values to zero at the start of the [Link] moving
the mouse,there is different values here.

dc.w 0,0 ;X and Y position of the slider

Next come two words which determine the size of the AUTOKNOB or
the step size of the slider(this determines how far the slider
moves when you click in the box next to the slider).These words
are called HorizBody (horizontal movement) and VertBody (vertical
movement).

dc.w $ffff/16 ;horizontal step size:1/16


dc.w 0 ;no vertical movement
;The next six words are initialized by Intuition.
dc.w 0 ;box width
dc.w 0 ;box height
dc.w 0 ;absolute step size horizontal
dc.w 0 ;and vertical
dc.w 0 ;left border of box
dc.w 0 ;upper border of box

Thats [Link] a quick overview of the PropInfo structure:

prpoinfo:
dc.w 2 ;flags:FREEHORIZ
dc.w 0,0 ;X and Y position of slider
dc.w $ffff/16 ;horizontal step size:1/16
dc.w 0 ;no vertical movement
dc.w 0 ;box width
dc.w 0 ;box height
dc.w 0 ;absolute step size horizontal
dc.w 0 ;and vertical
dc.w 0 ;left border of box
dc.w 0 ;upper border of box

Once you've typed this in,you can start the program and try it
out.
You can also try vertical movement by setting the flag word equal
to six,the vertical step size to $FFFF/10,and the height of the
gadget to 80,for the [Link] try out the AUTOKNOBs,change the
flag value to seven.

[Link] Program.
---------------------
Here is a complete example program using what you have learned in
this chapter:

;7_Intuition.asm
;** Demo-Program for working with Intuition **

movescreen =-162
openscreen =-198
closescreen =-66
openwindow =-204
closewindow =-72
autorequest =-348
setmenustrip =-264
clearmenustrip=-54
printitext =-216
drawimage =-144
drawborder =-108
displaybeep =-96
closelibrary =-414
openlib =-408
execbase = 4
getmsg =-372

joy2 =$dff0c
fire =$bfe001

;!!!when > 500kb !!!


;org $40000
;load $40000
; or use AssemPro to place in CHIP RAM
;!!!!!!!!!!!!!!!!!!!!!!!

run:
bsr openint
bsr scropen
bsr windopen
bsr setmenu
bsr print

lea border,a1
move #22,d0
move #30,d1
bsr borderdraw

bsr draw

bsr request

loop:
move.l execbase,a6
move.l windowhd,a0
move.l 86(a0),a0 ;user port
jsr getmsg(a6)
tst.l d0
beq loop ;no event
move.l d0,a0
move.l $16(a0),msg ;event:LO=item,HI=Event
move.l msg,d6 ;to test
move.l d6,d7
lsr #8,d7
lsr #3,d7 ;sub menu point in D7
clr.l d5
roxr #1,d6
roxl #1,d5 ;menu number in D5
and.l #$7f,d6
cmp #$7f,d6 ;no menu point?
beq loop ;no:continue
lsr #4,d6 ;menu point in D6
cmp #1,d6 ;point 2?
bne no1
move,l intbase,a6
move.l screenhd,a0
jsr displaybeep(a6)

no1:
cmp #0,d6
bne loop

ende:
bsr clearmenu
bsr windclose
bsr scrclose
bsr closeint
rts

openint:
move.l execbase,a6
lea intname,a1
jsr openlib(a6)
move.l d0,intbase
rts

closeint:
move.l execbase,a6
move.l intbase,a1
jsr closelibrary(a6)
rts

scropen:
move.l inbase,a6
lea screen_defs,a0
jsr openscreen(a6)
move.l d0,screenhd

scrclose:
move.l inbase,a6
move.l screenhd,a0
jsr closescreen(a6)
rts

scrmove:
move.l intbase,a6
move,l screenhd,a0
jsr movescreen(a6)
rts

windopen:
move.l intbase,a6
lea windowdef,a0
jsr openwindow(a6)
move.l d0,windowhd
rts

windclose:
move.l intbase,a6
move.l windowhd,a0
jsr closewindow(a6)
rts

request:
move.l windowhd,a0
lea btext,a1
lea ltext,a2
lea rtext,a3
move.l #0,d0
move.l #0,d1
move.l #180,d2
move.l #80,d3
move.l intbase,a6
jsr autorequest(a6)
rts

setmenu:
lea mentab,a0 ;pointer to text pointer in A0
lea menu,a1 ;pointer to menu field in A1
move #10,d1 ;menu position = 10

menuloop:
clr.l d2 ;menu point-Y=0
move.l a1,a2 ;save pointer
tst.l (a0)
beq setmenu1 ;end
clr.l (a1)+
move d1,(a1)+
add.l #70,d1
move.l #50,(a1)+
move.l #$a0001,(a1)+
move.l (a0)+,(a1)+ ;menu title
lea 12(a1),a3
move.l a3,(a1)+ ;menu point
clr.l (a1)+
clr.l (a1)+

itemloop:
tst.l (a0) ;last one?
beq menuend ;yes
lea 54(a1),a3
move.l a3,(a1)+ ;pointer to next point
move.l d2,(a1)+ ;X/Y
add #10,d2
move.l #$5a000a,(a1)+ ;width/height
move #$52,(a1)+
clr.l (a1)+
lea 16(a1),a3
move.l a3,(a1)+ ;text structor-pointer
clr.l (a1)+
clr.l (a1)+
clr.l (a1)+

move #$1,(a1)+ ;text-structor set


clr (a1)+
move.l #$50003,(a1)+
clr.l (a1)+
move.l (a0)+,(a1)+ ;text pointer
clr.l (a1)+

bra itemloop ;next point...

menuend:
clr.l -54(a1)
tst.l (a0)+
tst.l (a0) ;still in menu?
beq setmenu1 ;no:ready
move.l a1,(a2) ;pointer to next menu
bra menuloop ;and continue

setmenu1:
move.l intbase,a6
move.l windowhd,a0
lea menu,a1
jsr setmenustrip(a6)
rts

clearmenu:
move.l intbase,a6
move.l windowhd,a0
jsr clearmenustrip(a6)
rts

print:
move.l intbase,a6
move.l windowhd,a0
move.l 50(a0),a0
lea ggtext,a1
move.l #30,d0 ;X
move.l #16,d1 ;Y
jsr printitext(a6)
rts

draw:
move.l intbase,a6
move.l windowhd,a0
move.l 50(a0),a0
lea image,a1
move.l #200,d0
move.l #100,d1
jsr drawimage(a6)
rts

borderdraw:
move.l intbase,a6
move.l windowhd,a0
move.l 50(a0),a0
jsr drawborder(a6)
rts

screen_defs:
dc.w 0,0
dc.w 640,200
dc.w 4
dc.b 0
dc.b 1
dc.w $800
dc.w 15
dc.l 0
dc.l tite1
dc.l 0
dc.l 0

windowdef:
dc.w 10,20
dc.w 300,150
dc.b 0,1
dc.l $300
dc.l $100f
dc.l gadget
dc.l 0
dc.l windname

screenhd:
dc.l 0
dc.l 0
dc.w 200,40,600,200
dc.w $f

btext:
dc.b 3,3
dc.b 0
align
dc.w 10,10
dc.l 0
dc.l bodytxt
dc.l 0

bodytxt:dc.b "Requester-Text",0
align

ltext:
dc.b 3,1
dc.b 0
align dc.w 5,3
dc.l 0
dc.l lefttext
dc.l 0

lefttext: dc.b "left",0


align

rtext:
dc.b 0,1
dc.b 0
align dc.w 5,3
dc.l 0
dc.l righttext
dc.l 0

righttext: dc.b "right",0


align
tite1: dc.b "User Screen",0
windname: dc.b "Window-Title",0
align windowhd: dc.l 0

intbase:dc.l 0
intname:dc.b "[Link]",0
align msg:dc.l 0

mentab:
dc.l menu1
dc.l mp11,np12,mp13,mp14,mp15,mp16,mp17,mp18,mp19,0
dc.l menu2
dc.l mp21,mp22,mp23,0
dc.l menu3
dc.l mp31,mp32,0
dc.l menu4,mp41,0
dc.l 0

menu1: dc.b "Menu 1",0


mp11: dc.b "Point 11",0
mp12: dc.b "Point 12",0
mp13: dc.b "Point 13",0
mp14: dc.b "Point 14",0
mp15: dc.b "Point 15",0
mp16: dc.b "Point 16",0
mp17: dc.b "Point 17",0
mp18: dc.b "Point 18",0
mp19: dc.b "Point 19",0

menu2: dc.b "Menu 2",0


mp21: dc.b "End!",0
mp22: dc.b "Beep",0
mp23: dc.b "Point 23",0

menu3: dc.b "Menu 3",0


mp31: dc.b "Point 31",0
mp32: dc.b "Point 32",0

menu4: dc.b "Menu 4",0


mp41: dc.b "Point 41",0
align

gadget:
dc.l gadget1
dc.w 20,80,80,10
dc.w 0
dc.w $2 ;activation,$802 for longint
dc.w 4
dc.l border
dc.l 0
dc.l 0
dc.l 0
dc.l strinfo
dc.w 2
dc.l 0

border:
dc.w 0,0
dc.b 1,0,0
dc.d 5 ;XY-pair
dc.l koord
dc.l 0

koord:
dc.w -2,-2,80,-2,80,9,-2,9,-2,-2

strinfo:
dc.l strpuffer
dc.l undo
dc.w 0 ;cursor position
dc.w 10 ;[Link]
dc.w 0
dc.w 0,0,0,0,0
dc.l 0,0,0

strpuffer:
dc.b "Hello!",0,0,0

undo: dc.l 0,0,0


align

gadget1:
dc.l gadget2 ;more gadget
dc.w 40,50,32,13
dc.w $6 ;flags:invert
dc.w $103 ;activate
dc.w 1 ;gadget type
dc.l image ;gadget image
dc.l image2 ;select gadget
dc.l ggtext ;gadget text
dc.l 0 ;no exclude
dc.l 0 ;special info
dc.w 1 ;ID
dc.l 0 ;user data

ggtext:
dc.b 1,0,1
align
dc.w -8,14
dc.l 0
dc.l swtext
dc,l 0

swtext:
dc.b "Switch",0
align

image:
dc.w 0,0
dc.w 32,13
dc.w 1
dc.l imgdata
dc.b 2,1
dc.l 0

image2:
dc.w 0,0
dc.w 32,13
dc.w 1
dc.l imgdata2
dc.b 2,1
dc.l 0

imgdata:
dc.l 0
dc.l %00000000011100000000000000000000
dc.l %00000000111110000011101001000000
dc.l %00000000111110000010101101000000
dc.l %00000000011110000010101011000000
dc.l %00000000000111000011101001000000
dc.l %00000000000011100000000000000000
dc.l %00000000000001110000000000000000
dc.l %00000000000111111111100000000000
dc.l %00000000001111111111110000000000
dc.l %00000000001111111111110000000000
dc.l %00000000000110000001100000000000
dc.l 0

imgdata2:
dc.l 0
dc.l %00000000000000000000111000000000
dc.l %00011101110111000001111100000000
dc.l %00010101000100000001111100000000
dc.l %00010101100110000001111000000000
dc.l %00011101000100000011100000000000
dc.l %00000000000000000111000000000000
dc.l %00000000000000001110000000000000
dc.l %00000000000111111111100000000000
dc.l %00000000001111111111110000000000
dc.l %00000000001111111111110000000000
dc.l %00000000000110000001100000000000
dc.l 0

gadget2:
dc.l 0
dc.w 150,30,100,50
dc.w 5
dc.w 2
dc.w 3 ;[Link]
dc.l mover ;border
dc.l 0,0,0
dc.l specinfo
dc.w 3
dc.l 0

specinfo:
dc.w 6 ;flags:free horiz
dc.w 0,0
dc.w $ffff/10,$ffff/5
dc.w 0,0,0,0,0,0

mover:
dc.w 0,0,16,7
dc.w 1
dc.l moverdata
dc.b 1,0
dc.l 0

moverdata:
dc.w %0111111111111110
dc.w %0101111111111010
dc.w %0101011111101010
dc.w %0101010110101010
dc.w %0101011111101010
dc.w %0101111111111010
dc.w %0111111111111110

menu:blk.w 500

end

Chapter 8.
----------
[Link] Programming.
-----------------------
You've learned a lot about machine language programming on the
[Link] you need yet are a few routines that can be used as
programming [Link]'ll work on that right [Link]'ll be easy to
use in your own [Link] sky's the limit now!

[Link] Mode.
--------------------
As mentioned in the chapter on the MC68000 processor,there are two
operating modes:the User and the Supervisor [Link] is often
necessary to move between the two [Link],this isn't a
simple process.
The reason you want to do this,is that in User mode,you can't
access the Status [Link] you write to one of them,an
Exception is executed which crashes the program.

How can you get in Supervisor mode?

No [Link] operating system of the Amiga contains a function


in the EXEC library that lets you get into supervisor [Link]
called SuperState and it doesn't need any [Link] 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
[Link] 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 [Link]'ll talk about interrupts in a bit.

After this call,you'll use the user stack instead of the


supervisor [Link] this way,you can access the old user [Link]
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 [Link] need to return to user mode [Link] a
function for this in the exec library as [Link] is called the
UserState [Link] 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 [Link] user stack point(USP)is the
same as [Link] can write functions that need to be run from
the supervisor mode as [Link] you call superstate,save
the return value,execute the desired function,call userstate,and
end with a RTS [Link] the USP was changed,the RTS command
would'nt work right,and the computor would jump who knows where
and perhaps [Link] 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 [Link]


causes an Exception to occur and a routine is called whose address
begins at the long word starting at $[Link] is the Exception Vector
for Privilege [Link] routine that it branches to is called
in supervisor [Link] it tests where this exception came [Link]
the routine finds that the exception comes from the superstate
routine whose address it knows,the matter is [Link] just
branches to the routine without turning off the user [Link]
all there is to it.

[Link] Programming.
--------------------------
The exceptions described in the processor chapter offer you a lot
of oppertunities to control the Amiga's [Link] 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 [Link] 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
[Link] the command TRAP #0 is executed,the processor (in
supervisor mode)branches to the routine whose address lies at $80
in [Link] 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'[Link] are
put on the stack,and then a TRAP command is [Link] advantage
is that you don't have to know any of the operating systems
[Link] the Amiga you must know the addresses(Execbase=4).

Lets write your own TRAP routine to demonstrate the use of the
TRAP [Link]'ll need three program sections:

[Link] initialization of the TRAP vector.


[Link] 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 [Link] use the example from
the hardware chapter that produced a beep.
Lets write this routine using as little effort as [Link]
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 [Link] 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,


[Link] 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!
Appendices.
-----------
Overview of Library Functions.
------------------------------
The following table gives you an overview of the available
libraries and their [Link] sublist of functions is
preceded by the name of the library it is found in.
These functions are listed with their negative offset in hex and
[Link] name and their parameters are also [Link]
parameter names are in parenthesis behind the function [Link]
second set of parenthesis includes a list of registers that
correspond to the parameter [Link] no parameters are needed,we
put () to let you know.

[Link]
-$001E -30 InitCLPool (cLPool,size) (A0,D0)
-$0024 -36 AllocCList (cLPool) (A1)
-$002A -42 FreeCList (cList) (A0)
-$0030 -48 FlushCList (cList) (A0)
-$0036 -54 SizeCList (cList) (A0)
-$003C -60 PutCLChar (cList,byte) (A0,D0)
-$0042 -66 GetCLChar (cList) (A0)
-$0048 -72 UnGetCLChar (cList,byte) (A0,D0)
-$004E -78 UpPutCLChar (cList) (A0)
-$0054 -84 PutCLWord (cList,word) (A0,D0)
-$005A -90 GetCLWord (cList) (A0)
-$0060 -96 UnGetCLWord (cList,word) (A0,D0)
-$0066 -102 UnPutCLWord (cList) (A0)
-$006C -108 PutCLBuf (cList,buffer,length) (A0,A1,D1)
-$0072 -114 GetCLBuf (cList,buffer,maxLength) (A0,A1,D1)
-$0078 -120 MarkCList (cList,offset) (A0,D0)
-$007E -126 IncrCLMark (cList) (A0)
-$0084 -132 PeekCLMark (cList) (A0)
-$008A -138 SplitCList (cList) (A0)
-$0090 -144 CopyCList (cList) (A0)
-$0096 -150 SubCList (cList,index,length) (A0,D0.D1)
-$009C -156 ConcatCList (sourceCList,destCList) (A0,A1)

[Link]
-$002A -42 CDInputHandler (events,device) (A0,A1)
-$0030 -48 RawKeyConvert (events,buffer,length,keyMap)
(A0,A1,D1,A2)
[Link]
-$001E -30 OpenDiskFont (textAttr) (A0)
-$0024 -36 AvailFonts (buffer,bufBytes,flags) (A0,D0,D1)

[Link]
-$001e -30 Open (name,access mode)(d1,d2)
-$0024 -36 Close (file)(d1)
-$002a -42 Read (file,buffer,length)(d1,d2,d3)
-$0030 -48 Write (file,buffer,length)(d1,d2,d3)
-$0036 -54 Input()
-$003c -60 Output()
-$0042 -66 Seek(file,position,offset)(d1,d2,d3)
-$0048 -72 DeleteFile (name)(d1)
-$004e -78 Rename(oldname,newname)(d1,d2)
-$0054 -84 Lock(name,type)(d1,d2)
-$005a -90 UnLock(lock)(d1)
-$0060 -96 DupLock(lock)(d1)
-$0066 -102 Examine(lock,fileinfoblock)(d1,d2)
-$006c -108 ExNext(lock,fileinfoblock)(d1,d2)
-$0072 -114 Info(lock,parameterblock)(d1,d2)
-$0078 -120 CreateDir(name)(d1)
-$007e -126 CurrentDir(lock)(d1)
-$0084 -132 IoErr()
-$008a -138 CreateProc(name,pri,seglist,stacksize)(d1,d2,d3,d4)
-$0090 -144 Exit(returncode)(d1)
-$0096 -150 LoadSeg(filename)(d1)
-$009c -156 UnLoadSeg(segment)(d1)
-$00a2 -162 Getpacket(wait)(d1)
-$00a8 -168 Queuepacket(packet)(d1)
-$00ae -174 DeviceProc(name)(d1)
-$00be -180 SetComment(name,comment)(d1,d2)
-$ooba -186 SetProtection(name,mask)(d1,d2)
-$00c0 -192 DateStamp(date)(d1)
-$00c6 -198 Delay(timeout)(d1)
-$00cc -204 WaitForChar(file,timeout)(d1,d2)
-$00d2 -210 ParentDir(lock)(d1)
-$00d8 -216 IsInteractive(file)(d1)
-$00de -222 Execute(string,file,file)(d1,d2,d3)

[Link]
-$001e -30 Supervisor()
-$0024 -36 ExitIntr()
-$002a -42 Schedule()
-$0030 -48 Reschedule()
-$0036 -54 Switch()
-$003c -60 Dispatch()
-$0042 -66 Exception()
-$0048 -72 InitCode(startclass,version)(d0,d1)
-$004e -78 InitStruct(inittable,memory,size)(a1,a2,d0)
-$0054 -84 MakeLibrary(funcinit,structinit,libinit,datasize,
codesize)(a0,a1,a2,d0,d1)
-$005a -90 MakeFunctions(target,functionarray,funcdispbase)
(a0,a1,a2)
-$0060 -96 FindResident(name)(a1)
-$0066 -102 InitResident(resident,seglist)(a1,d1)
-$006c -108 Alert(alertnum,parameters)(d7,a5)
-$0072 -114 Debug()
-$0078 -120 Disable()
-$007e -126 Enable()
-$0084 -132 Forbid()
-$008a -138 Permit()
-$0090 -144 SetSR(newsr,mask)(d0,d1)
-$0096 -150 SuperState()
-$009c -156 UserState(sysstack)(d0)
-$00a2 -162 setIntVector(intnumber,interrupt)(d0,d1)
-$00a8 -168 AddIntServer(intnumber,interrupt)(d0,d1)
-$00ae -174 RemIntServer(intnumber,interrupt)(d0,d1)
-$00b4 -180 Cause(interrup)(a1)
-$00ba -186 Allocate(freelist,bytesize)(a0,d0)
-$00c0 -192 Deallocate(freelist,memoryblock,bytesize)(a0,a1,d0)
-$00c6 -198 AllocMem(bytesize,requirements)(d0,d1)
-$00cc -204 AlloAbs(bytesize,location)(d0,a1)
-$00d2 -210 FreeMem(memoryblock,bytesize)(a1,d0)
-$00d8 -216 AvailMem(requirements)(d1)
-$00de -222 AllocEntry(entry)(a0)
-$00e4 -228 FreeEntry(entry)(a0)
-$00ea -234 Insert(list,node,pred)(a0,a1,a2)
-$00f0 -240 AddHead(list,node)(a0,a1)
-$00f6 -246 AddTail(list,node)(a0,a1)
-$00fc -252 Remove(node)(a1)
-$0102 -258 RemHead(list)(a0)
-$0108 -264 RemTail(list)(a0)
-$010e -270 Enqueue(list,node)(a0,a1)
-$0114 -276 FindName(list,name)(a0,a1)
-$011a -282 AddTask(task,initpc,finalpc)(a1,a2,a3)
-$0120 -288 RemTask(task)(a1)
-$0126 -294 FindTask(name)(a1)
-$012c -300 SetTaskPri(task,prority)(a1,d0)
-$0132 -306 SetSignal(newsignals,signelset)(d0,d1)
-$0138 -312 SetExcept(newsignals,signalset)(d0,d1)
-$013e -318 Wait(signalset)(d0)
-$0144 -324 Signal(task,signalset)(a1,d0)
-$014a -330 AllocSignal(signalnum)(d0)
-$0150 -336 FreeSignal(signalnum)(d0)
-$0156 -342 AllocTrap(trapnum)(d0)
-$015c -348 FreeTrap(trapnum)(d0)
-$0162 -354 AddPort(port)(a1)
-$0168 -360 RemPort(port)(a1)
-$016e -366 PutMsg(port,message)(a0,a1)
-$0174 -372 GetMsg(port)(a0)
-$017a -378 ReplyMsg(message)(a1)
-$0180 -384 WaitPort(port)(a0)
-$0186 -390 FindPort(name)(a1)
-$018c -396 AddLibrary(library)(a1)
-$0192 -402 RemLibrary(library)(a1)
-$0198 -408 OldOpenLibrary(libname)(a1)
-$019e -414 CloseLibrary(library)(a1)
-$01a4 -420 Setfunction(library,funcoffset,funcentry)(a1,a0,d0)
-$01aa -426 SumLibrary(library)(a1)
-$01b0 -432 AddDevice(device)(a1)
-$01b6 -438 RemDevice(device)(a1)
-$01bc -444 OpenDevice(devname,unit,iorequest,flags)(a0,d0,a1
,d1)
-$01c2 -450 CloseDevice(iorequest)(a1)
-$01c8 -456 DoIO(iorequest)(a1)
-$01ce -462 SendIO(iorequest)(a1)
-$01d4 -468 CheckIO(iorequest)(a1)
-$01da -474 WaitIO(iorequest)(a1)
-$01e0 -480 AbortIO(iorequest)(a1)
-$01e6 -486 AddResource(resource)(a1)
-$01ec -492 RemResource(resource)(a1)
-$01f2 -498 OpenResource(resname,version)(a1,d0)
-$01f8 -504 RawIOInit()
-$01fe -510 RawMayGetChar()
-$0204 -516 RawPutChar(char)(d0)
-$020a -522 RawDoFmt()(a0,a1,a2,a3)
-$0210 -528 GetCC()
-$0216 -534 TypeOfMem(address)(a1)
-$021c -540 Procedure(semaport,bidmsg)(a0,a1)
-$0222 -546 Vacate(semaport)(a0)
-$0228 -552 OpenLibrary(libname,version)(a1,d0)
[Link]
-$001e -30 BltBitMap(scrbitmap,scrx,scry,destbitmap,destx,
desty,sizex,sizey,minterm,mask,tempa)
(a0,d0,d1,a1,d2,d3,d4,d5,d6,d7,a2)
-$0024 -36 BltTemplate(source,scrx,scrmod,destrastport,destx,
desty,sixex,sizey)(a0,d0,d1,a1,d2,d3,d4,d5)
-$002a -42 ClearEOL(rastport)(a1)
-$0030 -48 ClearScreen(rastport)(a1)
-$0036 -54 TextLength(rastport,string,count)(a1,a0,d0)
-$003c -60 Text(rastport,string,count)(a1,a0,d0)
-$0042 -66 SetFont(rastportid,textfont)(a1,a0)
-$0048 -72 OpenFont(textattr)(a0)
-$004e -78 CloseFont(textfont)(a1)
-$0054 -84 AskSoftStyle(rastport)(a1)
-$005a -90 SetSoftStyle(rastport,style,enable)(a1,d0,d1)
-$0060 -96 AddBob(bob,rastport)(a0,a1)
-$0066 -102 AddVSprite(vsprite,rastport)(a0,a1)
-$006c -108 DoCollision(rastport)(a1)
-$0072 -114 DrawGList(rastport,viewport)(a1,a0)
-$0078 -120 InitGels(dummyhead,dummytail,gelsinfo)(a0,a1,a2)
-$007e -126 InitMasks(vsprite)(a0)
-$0084 -132 RemIBob(bob,rastport,viewport)(a0,a1,a2)
-$008a -138 RemVSprite(vsprite)(a0)
-$0090 -144 SetCollision(type,routine,gelsinfo)(d0,a0,a1)
-$0096 -150 SortGList(rastport)(a1)
-$009c -156 AddAnimObj(obj,animationkey,rastport)(a0,a1,a2)
-$00a2 -162 Animate(animationkey,rastport)(a0,a1)
-$00a8 -168 etGBuffers(animationobj,rastport,doublebuffer)(a0,
a1,d0)
-$00ae -174 InitGMasks(animationobj)(a0)
-$00b4 -180 GelsFuncE()
-$00ba -186 GelsFuncF()
-$00c0 -192 LoadRGB4(viewport,colurs,count)(a0,a1,d0)
-$00c6 -198 InitRastPort(rastport)(a1)
-$00cc -204 InitVPort(viewport)(a0)
-$00d2 -210 MrgCop(view)(a1)
-$00D8 -216 MakeVPort (view,viewPort) (A0,A1)
-$00DE -222 LoadView (view) (A1)
-$00E4 -228 WaitBlit ()
-$00EA -234 SetRast (rastPort,color) (A1,D0)
-$00F0 -240 Move (rastPort,x,y) (A1,D0,D1)
-$00F6 -246 Draw (rastPort,x,y) (A1,D0,D1)
-$00FC -252 AreaMove (rastPort,x,y) (A1,D0,D1)
-$0102 -258 AreaDraw (rastPort,x,y) (A1,D0,D1)
-$0108 -264 AreaEnd (rastPort) (A1)
-$010E -270 WaitTOF ()
-$0114 -276 QBlit (blit) (A1)
-$011A -282 InitArea (areaInfo,vectorTable,vectorTableSize)
(A0,A1,D0)
-$0120 -288 SetRGB4 (viewPort,index,r,g,b) (A0,D0,D1,D2,D3)
-$0126 -294 QBSBlit (blit) (A1)
-$012C -300 BltClear (memory,size,flags) (A1,D0,D1)
-$0132 -306 RectFill (rastPort,xl,yl,xu,yu)
(A1,D0,D1,D2,D3)
-$0138 -312 BltPattern (rastPort,ras,xl,yl,maxX,maxY,
fillBytes) (A1,A0,D0,D1,D2,D3,D4)
-$013E -318 ReadPixel (rastPort,x,y) (A1,D0,D1)
-$0144 -324 WritePixel (rastPort,x,y) (A1,D0,D1)
-$014A -330 Flood (rastPort,mode,x,y) (A1,D2,D0,D1)
-$0150 -336 PolyDraw (rastPort,count,polyTable) (A1,D0,A0)
-$0156 -342 SetAPen (rastPort,pen) (A1,D0)
-$015C -348 SetBPen (rastPort,pen) (A1,D0)
-$0162 -354 SetDrMd (rastPort,drawMode) (A1,D0)
-$0168 -360 InitView (view) (A1)
-$016E -366 CBump (copperList) (A1)
-$0174 -372 CMove (copperList,destination,data) (A1,D0,D1)
-$017A -378 CWait (copperList,x,y) (A1,D0,D10
-$0180 -384 VBeamPos ()
-$0186 -390 InitBitMap (bitMap,depth,width,height)
(A0,D0,D1,D2)
-$018C -396 ScrollRaster (rastPort,dX,dY,minx,miny,maxx,
maxy) (A1,D0,D1,D2,D3,D4,D5)
-$0192 -402 WaitBOVP (viewPort) (A0)
-$0198 -408 GetSprite (simpleSprite,num) (A0,D0)
-$019E -414 FreeSprite (num) (D0)
-$01A4 -420 ChangeSprite (vp,simpleSprite,data) (A0,A1,A2)
-$01AA -426 MoveSprite (viewPort,simpleSprite,x,y)
(A0,A1,D0,D1)
-$01B0 -432 LockLayerRom (layer) (A5)
-$01B6 -438 UnlockLayerRom (layer) (A5)
-$01BC -444 SyncSBitMap (1) (A0)
-$01C2 -450 CopySBitMap (11,12) (A0,A1)
-$01C8 -456 OwnBlitter ()
-$01CE -462 DisownBlitter ()
-$01D4 -468 InitTmpRas (tmpras,buff,size) (A0,A1,D0)
-$01DA -474 AskFont (rastPort,textAttr) (A1,A0)
-$01E0 -480 AddFont (textFont) (A1)
-$01E6 -486 RemFont (textFont) (A1)
-$01EC -492 AllocRaster (width,height) (D0,D1)
-$01F2 -498 FreeRaster (planeptr,width,height) (A0,D0,D1)
-$01F8 -504 AndRectRegion (rgn,rect) (A0,A1)
-$01FE -510 OrRectRegion (rgn,rect) (A0,A1)
-$0204 -516 NewRegion ()
-$020A -522 ** reserved **
-$0210 -528 ClearRegion (rgn) (A0)
-$0216 -534 DisposeRegion (rgn) (A0)
-$021C -540 FreeVPortCopLists (viewPort) (A0)
-$0222 -546 FreeCopList (coplist) (A0)
-$0228 -552 ClipBlit (srcrp,srcX,srcY,destrp,destX,destY,
sizeX,sizeY,minterm) (A0,D0,D1,A1,D2,D3,D4,D5,D6)
-$022E -558 XorRectRegion (rgn,rect) (A0,A1)
-$0234 -564 FreeCprList (cprlist) (A0)
-$023A -570 GetColorMap (entries) (D0)
-$0240 -576 FreeColorMap (colormap) (A0)
-$0246 -582 GetRGB4 (colormap,entry) (A0,D0)
-$024C -588 ScrollVPort (vp) (A0)
-$0252 -594 UCopperListInit (copperlist,num) (A0,D0)
-$0258 -600 FreeGBuffers (animationObj,rastPort,
doubleBuffer) (A0,A1,D0)
-$025E -606 BltBitMapRastPort (srcbm,srcx,srcy,destrp,
destX,destY,sizeX,sizeY,minter)
(A0,D0,D1,A1,D2,D3,D4,D5,D6)

[Link]
-$001E -30 GetWBObject (name) (A0)
-$0024 -36 PutWBObject (name,object) (A0,A1)
-$002A -42 GetIcon (name,icon,freelist) (A0,A1,A2)
-$0030 -48 PutIcon (name,icon) (A0,A1)
-$0036 -54 FreeFreeList (freelist) (A0)
-$003C -60 FreeWBOject (WBOject) (A0)
-$0042 -66 AllocWBOject ()
-$0048 -72 AddFreeList (freelist,mem,size) (A0,A1,A2)
-$004E -78 GetDiskObject (name) (A0)
-$0054 -84 PutDiskObject (name,diskobj) (A0,A1)
-$005A -90 FreeDiskObj (diskobj) (A0)
-$0060 -96 FindToolType (toolTypeArray,typeName) (A0.A1)
-$0066 -102 MatchToolValue (typeString,value) (A0,A1)
-$006C -108 BumbRevision (newname,oldname) (A0,A1)

[Link]
-$001E -30 OpenIntuition ()
-$0024 -36 Intuition (ievent) (A0)
-$002A -42 AddGadget (AddPtr,Gadget,Position) (A0,A1,D0)
-$0030 -48 ClearDMRequest (Window) (A0)
-$0036 -54 ClearMenuStrip (Window) (A0)
-$003C -60 ClearPointer (Window) (A0)
-$0042 -66 CloseScreen (Screen) (A0)
-$0048 -72 CloseWindow (Window) (A0)
-$004E -78 CloseWorkbench ()
-$0054 -84 CurrentTime (Seconds,Micros) (A0,A1)
-$005A -90 DisplayAlert (AlertNumber,String,Height)
(D0,A0,D1)
-$0060 -96 DiplayBeep (Screen) (A0)
-$0066 -102 DoubleClick (sseconds,smicros,cseconds,
cmicros) (D0,D1,D2,D3)
-$006C -108 DrawBorder (Rport,Border,LeftOffset,TopOffset)
(A0,A1,D0,D1)
-$0072 -114 DrawImage (RPort,Image,LeftOffset,TopOffset)
(A0,A1,D0,D1)
-$0078 -120 EndRequest (requester,window) (A0,A1)
-$007E -126 GetDefPref (preferences,size) (A0,D0)
-$0084 -132 GetPrefs (preferences,size) (A0,D0)
-$008A -138 InitRequester (req) (A0)
-$0090 -144 ItemAddress (MenuStrip,MenuNumber) (A0,D0)
-$0096 -150 ModifyIDCMP (Window,Flags) (A0,D0)
-$009C -156 ModifyProp (Gadget,Ptr,Reg,Flags,HPos,VPos,
HBody,VBody) (A0,A1,A2,D0,D1,D2,D3,D4)
-$00A2 -162 MoveScreen (Screen,dx,dy) (A0,D0,D1)
-$00A8 -168 MoveWindow (Window,dx,dy) (A0,D0,D1)
-$00AE -174 OffGadget (Gadget,Ptr,Req) (A0,A1,A2)
-$00B4 -180 OffMenu (Window,MenuNumber) (A0,D0)
-$00BA -186 OnGadget (Gadget,Ptr,Req) (A0,A1,A2)
-$00C0 -192 OnMenu (Window,MenuNumber) (A0,D0)
-$00C6 -198 OpenScreen (OSArgs) (A0)
-$00CC -204 OpenWindow (OWArgs) (A0)
-$00D2 -210 OpenWorkBench ()
-$00D8 -216 PrintIText (rp,itext,left,top) (A0,A1,D0,D1)
-$00DE -222 RefreshGadgets (Gadgets,Ptr,Req) (A0,A1,A2)
-$00E4 -228 RemoveGadgets (RemPtr,Gadget) (A0,A1)
-$00EA -234 ReportMouse (Window,Boolean) (A0,D0)
-$00F0 -240 Request (Requester,Window) (A0,A1)
-$00F6 -246 ScreenToBack (Screen) (A0)
-$00FC -252 SCreenToFront (Screen) (A0)
-$0102 -258 SetDMRequest (Window,req) (A0,A1)
-$0108 -264 SetMenuStrip (Window,Menu) (A0,A1)
-$010E -270 SetPointer (Window,Pointer,Height,Width,
XOFFset, YOFFset) (A0,A1,D0,D1,D2,D3)
-$0114 -276 SetWindowTitles (Window,windowTitle,
screenTitle) (A0,A1,A2)
-$011A -282 ShowTitle (Screen,ShowIt) (A0,D0)
-$0120 -288 SizeWindow (Windowmdx,dy) (A0,D0,D1)
-$0126 -294 ViewAddress ()
-$012C -300 ViewPortAddress (Window) (A0)
-$0132 -306 WindowToBack (Window) (A0)
-$0138 -312 WindowToFront (Window) (A0)
-$013E -318 WindowLimits (Window,minwidth,minheight,
maxwidth, maxheight) (A0,D0,D1,D2,D3)
-$0144 -324 SetPrefs (preferences,size,flag) (A0,D0,D1)
-$014A -330 IntuiTextLength (itext) (A0)
-$0150 -336 WBenchToBack ()
-$0156 -342 WBenchToFront ()
-$015C -348 AutoRequest (Window,Body,PText,NText,PFlag,
NFlag,W,H) (A0,A1,A2,A3,D0,D1,D2,D3)
-$0162 -354 BeginRefresh (Window) (A0)
-$0168 -360 BuildSysRequest (Window,Body,PosText,NegText,
Flags,W,H) (A0,A1,A2,A3,D0,D1,D2)
-$016E -366 EndRefresh (Window,Complete) (A0,D0)
-$0174 -372 FreeSysRequest (Window) (A0)
-$017A -378 MakeScreen (Screen) (A0)
-$0180 -384 RemakeDisplay ()
-$0186 -390 RethinkDisplay ()
-$018C -396 AllocRemember (RememberKey,Size,Flags) (A0,D0,D1)
-$0192 -402 AlohaWorkBench (wbport) (A0)
-$0198 -408 FreeRemember (RememberKey,ReallyForgot) (A0,D0)
-$019E -414 LockIBase (dontknow) (D0)
-$01A4 -420 UnlockIBase (IBLock) (A0)

[Link]
-$001E -30 InitLayers (li) (A0)
-$0024 -36 CreateUpfrontLayer (li,bm,x0,y0,xl,yl,flags,
bm2) A0,A1,D0,D1,D2,D3,D4,A2)
-$002A -42 CreateBehindLayer (li,bm,x0,y0,xl,yl,flags,
bm2) (A0,A1,D0,D1,D2,D3,D3,A2)
-$0030 -48 UpfrontLayer (li,layer) (A0,A1)
-$0036 -54 BehindLayer (li,layer) (A0,A1)
-$003C -60 MoveLayer (li,layer,dx,dy) (A0,A1,D0,D1)
-$0042 -66 SizeLayer (li,layer,dx,dy) (A0,A1,D0,D1)
-$0048 -72 ScrollLayer (li,layer,dx,dy) (A0,A1,D0,D1)
-$004E -78 BeginUpdate (layer) (A0)
-$0054 -84 EndUpdate (layer) (A0)
-$005A -90 DeleteLayer (li,layer) (A0,A1)
-$0060 -96 LockLayer (li,layer) (A0,A1)
-$0066 -102 UnlockLayer (li,layer) (A0,A1)
-$006C -108 LockLayers (li) (A0)
-$0072 -114 UnlockLayers (li) (A0)
-$0078 -120 LockLayerInfo (li) (A0)
-$007E -126 SwapBitRastPortClipRect (rp,cr) (A0,A1)
-$0084 -132 WhichLayer (li,x,y) (A0,D0,D1)
-$008A -138 UnlockLayerInfo (li) (A0)
-$0090 -144 NewLayerInfo ()
-$0096 -150 DisposeLayerInfo (li) (A0)
-$009C -156 FattenLayerInfo (li) (A0)
-$00A2 -162 ThinLayerInfo (li) (A0)
-$00A8 -168 MoveLayerInfrontOf (layer_to_move,
layer_to_be_in_front_of) (A0,A1)
[Link]
-$001E -30 SPFix (float) (D0)
-$0024 -36 SPFit (integer) (D0)
-$002A -42 SPCmp (leftFloat,right,Float) (D1,D0)
-$0030 -48 SPTst (float) (D1)
-$0036 -54 SPAbs (float) (D0)
-$003C -60 SPNeg (float) (D0)
-$0042 -66 SPAdd (leftFloat,rightFloat) (D1,D0)
-$0048 -72 SPSub (leftFloat,rightFloat) (D1,D0)
-$004E -78 SPMul (leftFloat,rightFloat) (D1,D0)
-$0054 -84 SPDiv (leftFloat,rightFloat) (D1,D0)

[Link]
-$001E -30 IEEEDPFix (integer,integer) (D0,D1)
-$0024 -36 IEEEDPFit (integer) (D0)
-$002A -42 IEEEDPCamp (integer,integer,integer,integer)
(D0,D1,D2,D3)
-$0030 -48 IEEEDPTst (integer,integer) (D0,D1)
-$0036 -54 IEEEDPAbs (integer,integer) (D0,D1)
-$003C -60 IEEEDPNeg (integer,integer) (D0,D1)
-$0042 -66 IEEEDPAdd (integer,integer,integer,integer)
(D0,D1,D2,D3)
-$0048 -72 IEEEDPSub (integer,integer,integer,integer)
(D0,D1,D2,D3)
-$004E -78 IEEEDPMul (integer,integer,integer,integer)
(D0,D1,D2,D3)
-$0054 -84 IEEEDPDiv (integer,integer,integer,integer)
(D0,D1,D2,D3)

[Link]
-$001E -30 SPAtan (float) (D0)
-$0024 -36 SPSin (float) (D0)
-$002A -42 SPCos (float) (D0)
-$0030 -48 SPTan (float) (D0)
-$0036 -54 SPSincos (leftFloat,rightFloat) (D1,D0)
-$003C -60 SPSinh (float) (D0)
-$0042 -66 SPCosh (float) (D0)
-$0048 -72 SPTanh (float) (D0)
-$004E -78 SPExp (float) (D0)
-$0054 -84 SPLog (float) (D0)
-$005A -90 SPPow (leftFloat,rightFloat) (D1,D0)
-$0060 -96 SPSqrt (float) (D0)
-$0066 -102 SPTieee (float) (D0)
-$006C -108 SPFieee (float) (D0)
-$0072 -114 SPAsin (float) (D0)
-$0078 -120 SPAcos (float) (D0)
-$007E -126 SPLog10 (float) (D0)

[Link]
-$0006 -6 AllocPotBits (bits) (D0)
-$000C -12 FreePotBits (bits) (D0)
-$0012 -18 WritePotgo (word,mask) (D0,D1)

[Link]
-$002A -42 AddTime (dest,src) (A0,A1)
-$0030 -48 SubTime (dest,src) (A0,A1)
-$0036 -54 CmpTime (dest,src) (A0,A1)
[Link]
-$001E -30 Translate (inputString,inputLength,
outputBuffer,bufferSize) (A0,D0,A1,D1)

Abbreviations (symbols) used:

label A label or address


reg Register
an Address register n
dn Data register n
source source operand
dest destination operand
<ea> address of register
#n direct value

GENERAL INSTRUCTIONS

BCC label Conditional branch, depends on condition.


BRA label Unconditional branch (Similar to JMP).
BSR label Branch to subprogram. Return address is
deposited on the stack, RTS causes return to
that address.
CHK <ea>,dx Check data register for limits, activate the
CHK instruction exception.
DBCC reg,label Check condition, decrement on branch.
JMP label Jump to address (Similar to BRA).
JSR label Jump to a subroutine. Return address is deposited
on stack, RTS causes return to that address.
NOP No operation.
RESET Reset peripherals (Caution!).
RTE Return from exception.
RTR Return with loading of flags.
RTS Return from subroutine (After BSR or JSR).
SCC <ea> Set a byte to -1 when condition is met.
STOP Stop processing (Caution!).
TRAP #n Jump to an exception.
TRAPV Check overflow flag, then TRAPV exception.

ARITHMETIC OPERATIONS WITH WHOLE NUMBERS

ADD source,dest Binary addition.


ADDA source,an Binary addition to an address register.
ADDI #n,<ea> Addition with a constant.
ADDQ #n,<ea> Fast addition of a constant which can be only
from 1 to 8.
ADDX source,dest Addition with transfer in X flag.
CLR <ea> Clear an operand.
CMP source,dest Comparison of two operands.
CMPA <ea>,an Comparison with an address register.
CMPI #n,<ea> Comparison with a constant.
CMPM source,dest Comparison of two memory operands.
DIVS source,dest Sign-true division of a 32 bit destination by
a 16 bit source operand. The result of the
division is stored in the LO word of the
destination, the remainder in the HI word.
DIVU source,dest Division without regard to sign, similar to DIVS.
EXT dn Sign-true expansion to twice original size
(width) data unit.
MULS source,dest Sign-true multiplication of two words into one
word.
MULU source,dest Multiplication without regard to sign, similar
to MULS.
NEG <ea> Negation of an operand (twos complement).
SUB source,dest Binary subtraction.
SUBA <ea>,an Binary subtraction from an address register.
SUBI #n,<ea> Subtraction of a constant.
SUBQ #n,<ea> Fast subtraction of a three bit constant.
SUBX source,dest Subtraction with transfer in X flag.
TST <ea> Test operand and set N and Z flag.

BINARY CODED DECIMAL NUMBERS

ABCD source,dest Addition of two binary coded decimal numbers.


NBCD source,dest Negation of a binary coded decimal number
(nine complement).
SBCD source,dest Subtraction of two binary coded decimal numbers.

LOGICAL OPERATIONS

AND source,dest Logic AND.


ANDI #n,<ea> Logic AND with a constant.
EOR source,dest Exclusive OR.
EORI #n,<ea> Exclusive OR with a constant.
NOT <ea> Inversion of an operand.
OR source,dest Logic OR.
ORI #n,<ea> Logic OR with a constant.
TAS <ea> Check a byte and set bit 7.

SINGLE BIT MANIPULATION

BCHG #n,<ea> Change bit n(0 is changed to 1 and vice versa).


BCLR #n,<ea> Clear bit n.
BSET #n,<ea> Set bit n.
BTST #n,<ea> Test bit n, result is desplayed in Z flag.

SHIFT AND ROTATE OPERANDS

NOTE: n indicates a register, # indicates a direct value which


specifies the number of shiftings.

AS n,<ea> Arithmetic shift to the left (*2^n)


ASR n,<ea> Arithmetic shift to the right (/2^n)
LSL n,<ea> Logic shift to the left.
LSR n,<ea> Logic shift to the right.
ROL n,<ea> Rotation left.
ROR n,<ea> Rotation right.
ROXL n,<ea> Rotation left with transfer in X flag.
ROXR n,<ea> Rotation right with transfer in X flag.

MOVE DATA INSTRUCTIONS


EXG rn,rn Exchange two register contents (don't confuse
with swap!).
LEA <ea>,an Load an effective address in address register an.
LINK an,#n Build stack range.
MOVE source,dest Carry value over from source to destination.
MOVE SR,<ea> Transfer the status register contents.
MOVE <ea>,SR Transfer the status register contents.
MOVE USP,<ea> Transfer the user stack pointer.
MOVE <ea>,USP Transfer the user stack pointer.
MOVEA <ea>,an Transfer a value to the address register an.
MOVEM regs,<ea> Transfer several registers at once.
MOVEM <ea>,regs Transfer several registers at once.
MOVEP source,dest Transfer data to peripherals.
MOVEQ #n,dn Quickly transfer an eight bit constant to the
data register dn.
PEA <ea> Deposit an address on the stack.
SWAP dn Swap the halves of the register (the upper 16 bit
with the lower).
UNLK an Unlink the stack.

You might also like