
Initiation in Saturn
First of all, download: ADS
v5.2 if you have Hp48gx. If not, install a fast editor: Eden
v2.0 and Asm
v1.0
Introduction
SATURN is the name of the microprocessor
of the HP48. This chip is used in many HP models. The
SATURN is very powerful. To compare with your video game console, although the SATURN
is a 4 bit chip, it is sometimes even possible to work with 64 bits!
To compare with your personal computer, the SATURN chip has an
internal clock of 2 MHz for the HP48S(X), and 4 MHz for the HP48G(X), which makes
it possible to create fast and powerful programs! But before
jumping ahead into programming in assembler, it is necessary for
us to study the working procedure of the SATURN chip.
Operation
The SATURN is a whole microprocessor. Like
most microprocessors, it knows only 0's and
1's. That's called the binary system. In binary, only 0 and 1 are used.
It is inconceivable to program in binary, so one has to resort
to the hexadecimal system. In hexadecimal, there are 16 digits at our disposal,
(0123456789ABCDEF) contrary to the binary's two digits,
(01) and the decimal system, with 10 of them (0123456789). The
use of the Hexadecimal base is not an imagination of the programmers, but
allows better reading from these 0's and 1's. Indeed, four binary digits,
(ex: # 0101b) can be shown in only one hexadecimal figure, (ex # 5h).
A binary digit (0 or 1) is also called a bit. A succession of 4 bits is
called a four-bit nybble (sometimes nibble), with a byte being a succession of 8 bits.
To
summarize
A fragment of program in binary will resemble:
00110101011100101111010101001100
Let us cut out it in 8 four-bit bytes: 0011 0101
0111 0010 1111 0101 0100 1100
Let us transpose these 8 four-bit bytes in 8 Hexadecimal
digits: C A E 4 F A 2 3
What gives us: CAE4FA23
What
is more readable all the same, but still incomprehensible!
|
An instruction of the SATURN corresponds to a succession
of some hexadecimal figures. For example, the instruction which extinguishes
the screen of the HP is coded by: 8FDBB10. The assembler was born when
one said oneself that it would be more convenient to associate a name of
function with each instruction of the SATURN. Out of assembler, one glad
to write the name of the function (also called: mnemonics) in our program.
Tool called: ASSEMBLER makes it possible to replace these names of function
by the corresponding hexadecimal codes. Thus the language of assembler
was born. It should be noted that there is a table or are indexed all the
functions of the SATURN, as well as the corresponding codes, one calls
this table: Count of the mnemonic ones.
But let us take a simple example: The name of the instruction
which makes it possible to extinguish the screen is: GOSBVL 01BBD What
corresponds in fact to 8FDBB10 in machine language, or rather with: 1000111111011011101100010000
into binary. It will be noticed that the mnemonic ones are very useful
all the same! Thus a program out of assembler is nothing different but
a continuation mnemonic, which one must assemble using tool called 'assembler'
to be able to carry out this program. But let us see all the functions
which can fulfill the SATURN.
Registers of the SATURN
The SATURN calculation into hexadecimal, i.e. following
a base of 16 digits which are: 0123456789ABCDEF. Thus, to write #14d in
a program, we will have to write: # Eh. Here the table of correspondence
between these two bases:
Base 10
|
Base 16
|
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
100
255
..
|
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
10
64
FF
..
|
One gathers specifications of the SATURN according
to several registers. The concept of registers will be employed with many
recoveries, thus are attentive.
There are several kinds
of registers:
Registers of calculation: A,B,C,D
Registers of backup: R0,R1,R2,R3,R4
Pointer registers: D0,D1
The instruction counter: PC
Inputs and outputs: OUT/IN
The pile of the returns: RSTK
Flags: ST, HST
The pointer of fields: P |
Let us analyze each one of these registers
in detail:
Registers of calculation:
Fields:
There are 4 registers of calculations: A,B,C and D. If
it can appear similar, know that registers: A and C are most important.
All calculations of your HP pass by these registers. It is thus necessary
to include/understand their operation well. These registers can accomodate
64 bits, that is to say 16 four-bit bytes. One is useful oneself of registers
A and C for reading and writing in memory. Only the contents of registers
A,B,C and D can be the subject of a processing. One of the assets major
of the SATURN authorizes us to limit this processing to a portion given
of this register of processing, and this according to the following table:
Have well this table with the spirit, it
will be very useful thereafter for you:
Division in fields of the 16 four-bit bytes of a working register
(A,B,C and D)
|
15
|
14
|
13
|
12
|
11
|
10
|
9
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
W
|
S
|
M
|
X
|
|
A
|
|
XS
|
B
|
The field W:
It applies to all the four-bit bytes (64 bits), and thus
extends from four-bit byte 0 to four-bit byte 15. This field is very useful
when one wants to display an image with the screen quickly, or to make
a fast exchange between two storage areas.
The field S:
It includes/understands only four-bit byte 15. It
is used rather little.
The field M:
This field includes/understands only 12 four-bit bytes,
and extends from four-bit byte 3 with the four-bit byte 14. It is used
rather little.
Field X:
This field includes/understands only 3 four-bit bytes.
It is very useful, in particular during a test of the keyboard, or during
the activation of the buzzer. This field extends from four-bit byte 0 with
four-bit byte 2.
Field XS:
Field XS is a portion of field X; who includes/understands
only four-bit byte 2. It is used very little.
Field B:
The field B includes/understands 2 four-bit bytes which
extend from four-bit byte 0 to the four-bit byte 1. It is very useful when
meters are used, or displays of sprites. But it is primarily used to manage
the characters.
Field A:
The field A includes/understands 5 four-bit bytes which
extends from four-bit byte 0 to four-bit byte 4. It is the field more employed
and by far, indeed, it is primarily used during the reading or the pointing
of addresses in memory. An address is coded on 5 four-bit bytes.
The field P:
This field is worth a four-bit byte, which corresponds
to the value of P.
Field WP:
This field is worth P four-bit bytes.
Attention not to confuse the fields A and B,
with the registers of calculation A and B!! |
What can one make with these working registers?
Assignment of a value
To charge a value in one with registers A or C
LC 01235
LA 14
It should be noted that one can charge only 16 four-bit
bytes maximum, and that these numbers are hexadecimal numbers. (# 12d =
# Ch).
Ex: LC 0123456789ABCDEF
To put at zero the field of a working register
The field will have to be specified by 'fs'. The contents
of the field of the register are replaced by 0. To put at 0 the whole of
the register, it is necessary to specify the field W (16 four-bit bytes).
Mnemonic
|
A=0 fs
B=0 fs
C=0 fs
D=0 fs
|
To handle an insulated bit
One can arm (to light) or disarm (to extinguish) a bit
(or pixel) of a working register, with instruction ABIT and CBIT. ABIT
relates to register A, CBIT the register C.
Example:
ABIT=1 4 % One arms bit 4 of the register A
CBIT=0 6 % One disarms bit 6 of the register C
Only the first 16 bits can be changed.
Mnemonic
|
ABIT=0 n
ABIT=1 n
CBIT=0 n
CBIT=1 n
|
To carry out an exchange of the fields between
2 registers
You specify the fields concerned with this exchange with:
'fs'. to exchange the totality of two registers, it is necessary to employ
the field W.
Example:
ABEX A % the contents of fields A of registers A and B
are exchanged
Mnemonic
|
ABEX fs
BCEX fs
CAEX fs
DCEX fs
|
Copy between two registers
The copy of a field between 2 registers relates to only
one of the two registers, contrary to the exchange, or the 2 registers
are concerned. To copy the whole of a register towards another, should
be employed the field W.
Example:
A=C A % field A of the register C is copied from field
A of register A
The copy is always carried out line on the left.
Mnemonic
|
A=B fs
B=A fs
B=C fs
C=B fs
C=A fs
A=C fs
D=C fs
C=D fs
|
Operations of the
registers of calculation
The registers of calculation A,B,C and D enable us to
carry out simple operations, like additions, subtractions, logical operations
like "&" and "!" logic.
Additions:
It is possible for us to add two registers between them
and to add an unspecified value to a register.
Addition of the field of two registers
(the field will have to be specified by: 'fs')
Example:
A=A+C A % the fields A of registers A and C are added
% the result is copied in field A of register A
Mnemonic
|
A=A+B fs
B=A+B fs
B=B+C fs
C=B+C fs
C=C+A fs
A=C+A fs
D=D+C fs
C=D+C fs
|
The mnemonic following ones make it possible to double
(* 2) the values of the fields of the registers.
Mnemonic
|
A=A+A fs
B=B+B fs
C=C+C fs
D=D+D fs
|
Addition of a constant to a field of a register
It is possible for us to add a value ranging between
0 and 17 (0<n<17) to a field specified by 'fs' of a register.
Example:
A=A+16 A % One adds 16 to field A of register A
Mnemonic
|
A=A+n fs
B=B+n fs
C=C+n fs
D=D+n fs
|
Subtractions
It is possible for us to withdraw two registers
between them and to withdraw an unspecified value from a register.
Subtraction of the field of two registers
(the field will have to be specified by: 'fs')
Example:
A=A-C A % the fields A of registers A and C are withdrawn
% the result is copied in field A of register A
Mnemonic
|
A=A-B fs
B=B-C fs
C=C-A fs
D=D-C fs
B=B-A fs
C=C-B fs
A=A-C fs
C=C-D fs
A=B-A fs
B=C-B fs
C=A-C fs
D=C-D fs
|
Subtraction of a constant to a field of a register
It is possible for us to withdraw a value ranging between
0 and 17 (0<n<17) from a field specified by 'fs' of a register.
Example:
A=A-16 A % One withdraws 16 from field A of register A
Mnemonic
|
A=A-n fs
B=B-n fs
C=C-n fs
D=D-n fs
|
Complement with 2
Mnemonic
|
A=-A fs
B=-B fs
C=-C fs
D=-D fs
|
Complement with 1
The complement with 1 is used to reverse the contents
of a field of a register.
Example:
A=-A A % One reverses the value contained in field A of
register A
Mnemonic
|
A=-A-1 fs
B=-B-1 fs
C=-C-1 fs
D=-D-1 fs
|
Logical operations:
"!" logic
Representation of "or" logic:
n1 |
n2 |
result |
0
0
1
1 |
0
1
0
1 |
0
1
1
1 |
One uses much this method known as of "or" logical when
one displays a sprite by transparence. We will study this method later.
Mnemonic
|
A=A!B fs
B=B!C fs
C=C!A fs
D=D!C fs
B=A!B fs
C=B!C fs
A=C!A fs
C=D!C fs
|
"&" logic
Representation of "and" logic:
n1 |
n2 |
result |
0
0
1
1 |
0
1
0
1 |
0
0
0
1 |
One employment generally this method known as of "and"
logical when one tests a key of the keyboard. We will study that later.
Mnemonics
|
A=A&B fs
B=B&C fs
C=C&A fs
D=D&C fs
B=A&B fs
C=B&C fs
A=C&A fs
C=D&C fs
|
Rotations and shifts
Shift of a four-bit byte to the right and to the
left
One specifies the field concerned with: 'fs'.
Example:
ASL A % One shifts field A of register A of a four-bit
byte towards the left
CSR W % One shifts the field W of the register C of a
four-bit byte towards the right
Mnemonic
|
ASL fs
BSL fs
CSL fs
DSL fs
ASR fs
BSR fs
CSR fs
DSR fs
|
During a shift on the left, the four-bit byte on the
left of the specified field is lost, the four-bit byte on the right becomes
0.
During a shift on the right, the four-bit byte on the
right of the specified field is lost, the four-bit byte on the left becomes
0.
Rotation of a four-bit byte to the right or to the
left
All the four-bit bytes are concerned with rotation.
Mnemonic
|
ASLC
BSLC
CSLC
DSLC
ASRC
BSRC
CSRC
DSRC
|
During a shift to the right, the four-bit byte on the
right takes the place of the four-bit byte lost on the left.
During a shift on the left, the four-bit byte on the left
takes the place of the four-bit byte lost on the right.
Shift of a bit towards the right
All the bits of the register are concerned.
Example:
ASRB % One shifts all the bits of register A towards the
right
Mnemonic
|
ASRB
BSRB
CSRB
DSRB
|
During a shift to the right, the bit on the right disappears,
the bit on the left becomes 0.
Shift of a bit towards the right limited to a field
One specifies the field concerned with: 'fs'.
Mnemonic |
ASRB.F fs
BSRB.F fs
CSRB.F fs
DSRB.F fs |
Shift of a bit towards the left
There is not similar instruction to shift a bit towards
the left, but one can employ the instruction: A=A+A CH to carry out this
shift on the left.
Ex: C=C+C W
(one shifts all the bits of the register C towards the
left)
Mnemonic |
A=A+A fs
B=B+B fs
C=C+C fs
D=D+D fs |
Registers of backup:
There are 5 registers of backup which are respectively:
R0,R1,R2,R3 and R4. These registers are identical and make it possible
to save the contents of the working registers A and C.
Copy of a working register towards a register of backup
All the fields are concerned with this operation.
Mnemonic
|
R0=A
R1=A
R2=A
R3=A
R4=A
R0=C
R1=C
R2=C
R3=C
R4=C
|
Copy of a register of backup towards a working register
All the fields are concerned with this operation.
Mnemonic
|
A=R0
A=R1
A=R2
A=R3
A=R4
C=R0
C=R1
C=R2
C=R3
C=R4
|
Copy of a field of a working register towards a register
of backup
This operation concerns that the field specified (fs)
and does not have any effect on the other fields.
Mnemonic
|
R0=A.F fs
R1=A.F fs
R2=A.F fs
R3=A.F fs
R4=A.F fs
R0=C.F fs
R1=C.F fs
R2=C.F fs
R3=C.F fs
R4=C.F fs
|
Copy of a field of a register of backup towards the field
of a working register
This operation concerns that the field specified (CH)
and does not have any effect on the other fields.
Mnemonic
|
A=R0.F fs
A=R0.F fs
A=R2.F fs
A=R3.F fs
A=R4.F fs
C=R0.F fs
C=R1.F fs
C=R2.F fs
C=R3.F fs
C=R4.F fs
|
Exchange of the contents of a working register with the
contents of a register of backup
This operation relates to all the fields.
Mnemonic
|
AR0EX
AR1EX
AR2EX
AR3EX
AR4EX
CR0EX
CR1EX
CR2EX
CR3EX
CR4EX
|
It should be noted that the instruction: AR0EX is the
same one as this one: R0AEX, which is practically not employed by programmers.
Exchange of a field of a working register with the same
field of a register of backup
This operation relates to only the field specified by
'fs'.
Mnemonic
|
AR0EX.F fs
AR1EX.F fs
AR2EX.F fs
AR3EX.F fs
AR4EX.F fs
CR0EX.F fs
CR1EX.F fs
CR2EX.F fs
CR3EX.F fs
CR4EX.F fs
|
Pointer
registers
There are 2 identical registers called 'pointer' on HP48.
They are: D0 and D1. These registers fulfill several major functions:
They are able to read from and write to memory, to exchange
their information with the working registers: A and C, to move of a value
ranging between 0 and 17 (0<n<17).
Pointing and reading at an address in memory
There are two methods to point to memory. The first consists
of directly specifying the address, the second method consists of pointing
on field A (A as addresses!) of a working register containing this address.
By specifying the address directly
One points in memory while pointing on an address noted
on 2,4 or 5 four-bit bytes.
Ex: D0 = 8068D
(one points on the address of the screen)
One reads from memory by recopying the address pointed
in register A or C.
Ex: A=DAT0 A
(field A of register A contains the address pointed by
D0)
Mnemonic
|
A=DAT0 fs
C=DAT0 fs
A=DAT1 fs
C=DAT1 fs
|
While pointing on a register containing the address
Field A of the register concerned will have to contain
the address to which one wants to point.
Ex:
D0 = 8068D
A=DAT0 A
(field A of register A contains the address of the screen)
D1=A
(D1 points on the beginning of the screen, with the address
contained in field A of the register A).
Note that 'n' corresponds to an address of 2,4 or 5 four-bit
bytes.
Mnemonic |
Mnemonic |
D0 = n
D1 = n |
D0=A
D0=C
D1=A
D1=C |
One reads from memory by recopying the data pointed by
D1 in a working register.
Ex: A=DAT1 W
(the field W of register A contains the first 16 four-bit
bytes of the screen).
Mnemonic
|
A=DAT0 fs
C=DAT0 fs
A=DAT1 fs
C=DAT1 fs
|
One can also indicate to the place of the noted field:
'fs', the number of four-bit bytes which one wishes right.
Ex: A=DAT1 4
(one reads only the first 4 four-bit bytes).
Mnemonic
|
A=DAT0 N
C=DAT0 N
A=DAT1 N
C=DAT1 N
|
Displacement
to the left and to the right of a pointer
One can move a pointer register on the left or on the
right of a value of n ranging between 0 and 17 (0<n<17). It is very
useful to traverse a storage area, or to display given to the screen.
Example:
D1 = 8068D % One points at an unspecified address
D1=D1+ 16 % One moves of 16 four-bit bytes towards the
right
Mnemonic
|
D0=D0+ n
D0=D0- n
D1=D1+ n
D1=D1- n
|
writing
at an address in memory
One writes to memory by recopying the data of register
A or C, with the address pointed by D0 or D1.
Example:
D0 = 8068D
A=DAT0 A
D0=A % One points on the beginning of the screen
LA 1234 % One charges an unspecified value in register
A
DAT0=A A % One recopies this value with the address pointed
by D0
Mnemonic
|
DAT0=A fs
DAT0=C fs
DAT1=A fs
DAT1=C fs
|
One can also indicate to the place of the noted field:
'fs', the number of four-bit bytes which one wishes to write.
Example:
DAT1=A 6 % One writes only the first 6 four-bit
bytes
Mnemonic
|
DAT0=A n
DAT1=A n
DAT0=C n
DAT1=C n
|
Exchange between pointer registers and working
registers
It is possible to exchange the contents of a pointer
register with the contents of a working register, if it is not that only
field A is concerned.
Example:
AD0EX % One exchanges the contents of field A of register
A
% with the contents of the register D0
Mnemonic
|
AD0EX
AD1EX
CD0EX
CD1EX
|
Jumps
and tests
Jumps
Normally, a program is carried out beginning with the
end, but it is possible to upset this direction by carrying out jumps.
There are several types of jumps, the short jumps (GOTO), the long jumps
(GOLONG), the subprogram calls short (GOSUB) and the long subprogram calls
(GOSUBL).
One carries out a jump in the following way:
GOTO label
* label
You can put any name at the place of: ' label' if it is
not that you cannot use the same label twice. Instruction GOLONG is the
same one as instruction GOTO, but has a greater range:
GOTO (# 800h four-bit bytes)
GOLONG (# 8000h four-bit bytes)
There is an instruction known as absolute: GOVLNG
After use of this instruction, the program begins again
with the specified address. It is a jump known as: absolute. One often
uses this instruction to leave a program:
Example:
GOVLNG 05143
Subroutines
One uses the subroutines using the instructions: GOSUB
and GOSUBL. When a subroutine is used, the start address is saved for a
possible return of subroutine, generally noted: RTN.
Summary:
% beginning of a program
GOSUB label1 % the address below is saved
% and program goes to the named subroutine: label1
% After a return of subroutine
% the program begins again with the address saved below
GOVLNG 05143 % End of the program
* label1 % Subroutine: label
RTN % One returns to the initial address: it is the return
of subroutine
Attention, one can go only 6 levels of subroutines deep,
which though is not so bad!
GOSUB (short call: # 800h)
GOSUBL (long call: # 8000h)
Tests
A test is nothing else but a comparison between 2 working
registers. It is preceded by the sign: ?
Ex: ?A=B A
There is in addition a bit called: Carry, which manages
the tests. A test is either true, or false. If the test is true, then the
bit Carry is armed (it is worth 1 then), if on the contrary the test is
false, the bit Carry is disarmed (it is worth 0). This special bit is used
for to us to manage the result of a test. Indeed, on the state of this
bit depend the following instructions:
?A=0 A
GOYES label2
% If Carry = 1 (true test), one carries out a jump towards
the specified label.
% If not one continuous the program.
In the same way:
?A=C A
GONC label2
% If Curry = 0 (false test), one carries out a jump towards
the specified label.
% If not, one continuous the program.
The bit Carry is automatically switched to 0 after such
an instruction. One can compare two working registers, according to a field
in particular:
Ex: ?A=B W
(one compares the fields W of registers A and B)
One can test by superiority or inferiority:
Ex: ?A<C B
Ex: ?B>C A
One can test if the field of a register is null or not:
?A=0 M
One can also test the state of a bit:
?ABIT=1 3
?CBIT=0 6
(on the left: the state of the bit (0 or 1), on the right:
the number of the bit (0 to 15)).
Here is the table of mnemonic principal (fs means field
and n the number of the bit to be tested with 0£
n£ 16):
Comparison
|
Inferiorite/Superiority
|
Bits
|
?A=0 fs
?A¹ 0 fs
?A=B fs
?A¹ B fs
?B=0 fs
?B¹ 0 fs
?B=C fs
?B¹ C fs
?C=0 fs
?C¹ 0 fs
?C=A fs
?C¹ A fs
?D=0 fs
?D¹ 0 fs
?D=C fs
?D¹ C fs
|
?A<B fs
?A£ B fs
?B<C fs
?B£ C fs
?C<A fs
?C£ A fs
?D<C fs
?D£ C fs
?A>B fs
?A³ B fs
?B>C fs
?B£ C fs
?C>A fs
?C£ A fs
?D>C fs
?D£ C fs
|
?ABIT=0 n
?ABIT=1 n
?CBIT=0 n
?CBIT=1 n
|
BASIC
CONCEPTS
Routines in read-only memory.
The routines are portions of programs in read-only
memory which can be compared to subroutines. They are of an extreme utility
for the programmer because they carry out spots which frequently return
in a program of play. These routines are called by a simple GOSBVL xxxxx
or GOVLNG xxxxx.
>Note that these routines can affect certain registers
of calculations like A,B,C or D, it will be necessary to hold of it account
during the development of a program.
Function: Backup of the registers
|
Address S/sx:0679b
|
Call:GOSBVL
|
Address G/gx:0679b
|
This routine is that employed at the beginning of
all the programs out of assembler. It backs up the registers D0,D1,B(A)
and D(A)
|
Function: Restoration of the registers
|
Address S/sx:067d2
|
Call:GOSBVL
|
Address G/gx:067d2
|
This routine supplements the preceding one. It restores
the registers D0,D1,B(A) and D(A) for a return to the rpl of the program.
|
Function: Detection of a pressure on a key
|
Address S/sx:00e0b
|
Call:GOSBVL
|
Address G/gx:00e0b
|
After the execution of the routine, C(A) contains
the value of input of the key if a key is pressed and 00000 if no key is
pressed. Register OUT is put at # 1FFh.
|
Function: C=IN
|
Address S/sx:01160
|
Call:GOSBVL
|
Address G/gx:01160
|
Place the 3 four-bit bytes of the register IN in
the 5 four-bit bytes of the register C.
|
Function: Screen On
|
Address S/sx:01b8f
|
Call:GOSBVL
|
Address G/gx:01b8f
|
This routine lights the screen.
After execution, the register D0 points to address
# 100h.
|
Function: Screen Off
|
Address S/sx:01bbd
|
Call:GOSBVL
|
Address G/gx:01bbd
|
This routine extinguishes the screen.
After execution, the register D0 points to address
# 100h.
|
Function: Conversion of Decimal into Hexadecimal
of the register C
|
Address S/sx:0d62f
|
Call:GOSBVL
|
Address G/gx:0d62f
|
Converts the decimal number placed in C(W) into hexadecimal.
After execution of the routine, A(W), B(W), C(W) will contain the converted
numbers.
|
Function: Conversion of hexadecimal into Decimal
of register A
|
Address S/sx:0db91
|
Call:GOSBVL
|
Address G/gx:0db91
|
Converts the hexadecimal number placed in A(W) into
Decimal.
After execution of the routine, A(W), B(W), C(W)
will contain
the converted numbers.
|
Function: Interruptions Off
|
Address S/sx:
|
Call:GOSBVL
|
Address G/gx:01115
|
The interruptions are prohibited (ST=0 15).
|
Function: Interruptions On
|
Address S/sx:
|
Call:GOSBVL
|
Address G/gx:010e5
|
Authorize interruptions (ST=1 15).
|
Function: Reset (ON C)
|
Address S/sx:
|
Call:GOSBVL
|
Address G/gx:01fbd
|
Carry out a hot restarting as that realizes by the
double
support on the keys ONE and C.
|
Function:Try to Recover Memory (ON A F)
|
Address S/sx:
|
Call:GOSBVL
|
Address G/gx:015f0
|
Even effect that triple support on the keys ONE A
and F.
|
Function: Beep (D and C)
|
Address S/sx:
|
Call:GOSBVL
|
Address G/gx:017a6
|
Even effect that BEEP.
Register C(A) must contain the duration in milliseconds
and D(A) the frequency in Hz
|
Function: Mem
|
Address S/sx:
|
Call:GOSBVL
|
Address G/gx:06806
|
Even effect that MEM.
After execution, C(A) contains the memory size available.
D0 and A(A) are modified.
|
Function: $0000... 00
|
Address S/sx:
|
Call:GOSBVL
|
Address G/gx:05b7d
|
Create a character string made up of C(A) four-bit
bytes.
After execution of the routine, D0 points on the
first character.
R0, C(A) and D1 are modified.
|
Function: Exit
|
Address S/sx:
|
Call:GOSBVL
|
Address G/gx:05143
|
The sourest manner to leave a program out of assembler.
|
Function: D0 = screen
|
Address S/sx:
|
Call:GOSBVL
|
Address G/gx:0ç31
|
After execution of the routine, D0 points on the
address of the beginning
screen. A(A) corresponds to D0.
|
Function: ClrLCD
|
Address S/sx:
|
Call:GOSBVL
|
Address G/gx:01bff
|
Erase the screen and the menus.
Registers A(W), C(A), and D0 are modified.
|
Useful addresses of the read-write memory:
The read-write memory (or RAM I/O) of the inputs
and outputs is very useful for the programmer wishing to modify certain
parameters of the HP48. Indeed the programmer will have the possibility
using these addresses of modifying the contrast of the screen, of lighting
or of extinguishing certain indicators on top of the screen for example.
The range of addresses used by RAM I/O being itself from the address #00100h
to address # 0013Fh.
The technique consists of reading the data pointed
to an address of RAM I/O using a pointer register such D0 or D1:
ex: D0 = xxxxx
Reading the data pointed using a working register
such as A or C:
ex: A=DAT0 A (or C=DAT0 A)
Modifying the data read by arming or disarming
the bits of register A or C:
ex: ABIT=0 2 (or CBIT=1 3)
Then to rewrite the data thus modified at the
address specified in D0 or D1:
ex: DAT0=A A (or DAT0=C A)
For that it is necessary to have a perfect knowledge
of each address of RAM I/O under penalty of losses of frequent data!
Here are presented the principal addresses of
RAM I/O:
#00101 |
Bit nr. 0 to 4 |
Contrast of the screen |
Contrast can take 32 values (either # 20h.)
coded on 5 bits. To modify the values of these 5 bits returns has to modify
the contrast of the screen. Useful when one wishes to modify contrast during
a play. |
#0010B |
Bit nr. 0 to 3 |
Lighting of the indicators |
State of these 4 bits depends lighting on
the indicators in top of the screen. Bit 0 lights the indicator < when
it is armed, bit 1 >, bit 2 a and bit 3 the
indicator of ringing. |
#0010C |
Bit nr. 1&3 |
Lighting of the indicators |
Bit 0 lights the indicator 'busy' when it
is armed, bit 1 the indicator of transmission. Bit 3 authorizes the lighting
of the indicators when it is armed, or the interdicts when it is disarmed.
Useful when one wishes to extinguish the occupied indicator. |
#00120 |
Bit nr. 0 to 3 |
Address screen |
The address of the GROB permanently displayed
with the screen is fixed at this address. You can write a new address in
#00120h to modify the grob screen. |
#00128 |
Bit nr. 0 to 3 |
Small sweeping and height |
These 4 bits control reading, the number
of the lines being refreshed, in writing, the height of the menus. (by
writing #3Fh in #00128h one makes disappear the bar from the menus). To
obtain the number of the lines being refreshed, one reads the 6 bits (ex:
D0 = 00128 A=DAT0 6). Register A is worth thus 0 when the last line was
refreshed. The screen is refreshed 64 times a second. Useful for the development
of a game in several levels of gray. |
#00130 |
Bit nr. 0 to 3 |
Address bitmap finely |
The screen is separated into two. The address
of the lower part is fixed in #00130 and corresponds to the bitmap of the
bar of the menus. |
What
is a source program?
The technical aspect having been approached, let
us pass to the programming to be strictly accurate. To carry out a program
in any language that it either requires the development with the precondition
of a file known as: 'source'. Any program is initially a source file. It
is thus represented by the HP by a chain: " ", and must imperatively end
in the special character: @. What gives, for a program reduced to its simpler
expression:
"
@ "
One obtains the character special: "@" by successive
pressure of the keys: [ alpha ] [ green shift ] [ ENTER ].
How
to make it executable?
We saw previously that a simple source program
was summarized with:
"
@ "
If you assemble this source program, you will
obtain your first executable Code then! But which will not carry out anything
of course, because there is nothing in the program yet! One obtains then
in the pile of the HP48:
Couples
OUT/IN:
It thus proves essential to know the code of input
and output of each keys:
A
out: 002
in: 010
|
B
out: 100
in: 010
|
C
out: 100
in: 008
|
D
out: 100
in: 004
|
E
out: 100
in: 002
|
F
out: 100
in: 001
|
MTH
out: 004
in: 010
|
PRG
out: 080
in: 010
|
CST
out: 080
in: 008
|
VAR
out: 080
in: 004
|
out: 080
in: 002
|
NXT
out: 080
in: 001
|
'
out: 001
in: 010
|
STO
out: 040
in: 010
|
EVAL
out: 040
in: 008
|
¬
out: 040
in: 004
|
¯
out: 040
in: 002
|
®
out: 040
in: 001
|
SIN
out: 008
in: 010
|
COS
out: 020
in: 010
|
TAN
out: 020
in: 008
|
Ö X
out: 020
in: 004
|
yx
out: 020
in: 002
|
1/x
out: 020
in: 001
|
ENTER
out: 010
in: 010
|
+ / -
out: 010
in: 008
|
EEX
out: 010
in: 004
|
LED
out: 010
in: 002
|
Ü
out: 010
in: 001
|
a
out: 008
in: 020
|
7
out: 008
in: 008
|
8
out: 008
in: 004
|
9
out: 008
in: 002
|
¸
out: 008
in: 001
|
<
out: 004
in: 020
|
4
out: 004
in: 008
|
5
out: 004
in: 004
|
6
out: 004
in: 002
|
´
out: 004
in: 001
|
>
out: 002
in: 020
|
1
out: 002
in: 008
|
2
out: 002
in: 004
|
3
out: 002
in: 002
|
-
out: 002
in: 001
|
ONE
out: 400
in: 8000
|
0
out: 001
in: 008
|
.
out: 001
in: 004
|
SPC
out: 001
in: 002
|
+
out: 001
in: 001
|
Important remarks:
The instruction: GOSBVL
01EEC replaces: OUT=C followed by GOSBVL 01160.
We can simply test the state of the bits in C(X),
without using the code IN key to be tested:
Test of the key [ ENTER ]:
LC 010
GOSBVL 01EEC
?CBIT=1 4 |
Couples OUT of [ ENTER ]
OUT=C GOSBVL 01160
It is key actuated? |
To know of which bit one must test according to
the key, if the key is keyboard on the right, it is bit 0. If it is a little
on the right, bit 1,2,3,4. Of right-hand side on the left:
bit n:
|
bit n:
|
bit n:
|
bit n:
|
bit n:
|
4
|
3
|
2
|
1
|
0
|
The key [ ENTER ] is all on the left. This is
why one with tested bit n: 4. This method of testing keys in assembler
is the best, because it's the simplest the and smallest one.
Skeleton
of a game:
Now that the tests of the keyboard were approached,
we can set up the skeleton of a game. We thus will carry out a program
which will end at the time of the support on a key of the keyboard. For
that, we will take again the basic structure of a play studied previously,
but first of all a warning:
ANY program whatever it is must ALWAYS begin
with the routine:
The purpose is to back up the current registers
of Hp48. Then INTOFF which prohibits the processing of the keyboard.
The same ANY program must end in the routine:
GOSBVL 067D2
A=DAT0 A
D0=D0+ 5
PC=(A) |
Who restores the current registers of the HP48.
But we will employ the more powerful routine rather to leave:
Thus, your first autonomous program will arise
in the form:
" GOSBVL 0679B
INTOFF
% here is your program!!
GOSBVL 05143
@ " |
It would be enough to assemble this mini source
to realize that this program functions with wonder! Indeed, it launches
out then stops automatically: It is magic you would say to me.
No, it is simply the
ASSEMBLER !
Working
But let us return rather to our small game. The
key to be tested will be ENTER. Let us analyze specific couple OUT/IN of
key ENTER:
OUT: 010
One tests the state of bit nr.: 4 because the
key is placed on the fourth column on the basis of the line.
The test specific to
this key will be thus:
LC 010
GOSBVL 01EEC
?CBIT=1 4 |
Couples OUT of [ ENTER ]
OUT=C GOSBVL 01160
It is key actuated?
|
Let us add that at a beginning and an end of
our program:
GOSBVL 0679B
INTOFF
* loop
LC 010
GOSBVL 01EEC
?CBIT=1 4
GOYES label_2
GOTO loop
* label_2
GOVLNG 05143 |
It is important to announce here that, in assembler,
the programmer has multiple possibilities to carry out the same spot in
a program. This is why certain programmers of games are very gifted HP48
parasites, in fact they are only very ordered and effective in the analysis
of each function of their game. Thus, a programmer gains with clear and
being structured in the development of his games.
But rather let us take again our small program,
nothing does not prevent us from placing the test of key ENTER in subroutine.
One gains then in clearness:
GOSBVL 0679B
INTOFF |
Principal core
|
* loop
GOSUBL test_quit
%coor of the code!
GOTO loop |
Subroutines
|
* test_quit
LC 010
GOSBVL 01EEC
?CBIT=0 4
RTNYES |
End of the program
|
GOVLNG 05143 |
As their name indicates it, the subroutines will
have to be always located at the end of the program. For those which one
followed, nothing prevents from adding subprogram calls in the core of
the game, then to write these subroutines ones following the others! One
gains then in clearness and effectiveness. Each program with its method,
however I think that this one is simplest with debugger : -)
Involve you to test other keys by modifying couple
OUT according to the preceding table, as well as the state of the corresponding
bits. It should be noted that if your machine does not answer any more,
you will be able constantly to stop the procedure by the double support
on the keys: ON_C What will cause immediate reset of HP48.
How to carry out a
sound?
A video game is nothing different but a renewal
of graphs, of some tests of the keyboard, the decorated whole of some sounds.
We thus will study the manner of carrying out sounds. But be wary, you
not to wait especially to hear your HP48 playing the Mozart or to recreate
the environment of a play Mystique! In fact, the buzzer which equips the
models of HP48 is very limited. It can play only some acute frequencies,
not making it possible to carry out a tape sound. We will thus be satisfied
to carry out simple sound effects, like the sound of the rebound of a ball
against a wall for example!
To carry out a sound, several methods open with
us.
We can do is :
- to have resorts to the routine BEEP which
takes as argument the frequency and the duration of the sound.
- To even create the our own subroutine.
With an aim of familiarizing you with the assembly
language, the second method proves to be preferable!
Let us proceed by stage successive:
* A sound is characterized by its frequency in
Hertz and its duration in seconds.
* It is obtained while activating, then by decontaminating
buzzer HP48, more or less quickly (the frequency), more or less a long
time (duration).
Let us see how to make buzzer of HP48 to
vibrate:
The buzzer is activated while placing #800h in
register OUT, and it is decontaminated while placing #000h in this same
register. An activation, followed by a desactivation causes a CLIC:
This support of program causes a CLIC. A continuation
of clic at regular frequency causes a sound. Let us see how to carry out
a frequency: We should place this program in a first loop, or register
A(A) will be the meter. It will be the effective duration of the sound.
We should place a second loop then, or B(A) will be the meter. It will
be the effective frequency of the sound.
It is enough for us more whereas has to end a
beginning and with our program to make it autonomous.
"
GOSBVL 0679B
INTOFF
01000
LC 00020
B=C A
D=C A
* label_1
LC 800
OUT=C
C=0 X
OUT=C
* label_2
B=B-1 A
GONC label_2
C=D A
B=C A
A=A-1 A
GONC label_1
GOVLNG 05143
@ " |
To modify the initial value of register B(A) or
A(A) thus amounts modifying the frequency or the duration of the sound
thus emitted.
Assemble this program and listen to your HP which
produces its first cry out of assembler!!
How to display a GROB?
We arrive now at the greatest part but also most
delicate during the creation of a video game, namely: how to display a
GROB of unspecified size to the screen? First of all, a small speech: The
screen is a peripheral of the HP as well as the keyboard. It is in fact
the representation of a portion of the memory, therefore to write on the
screen amounts writing in memory. For that, the programmer will have resorts
to the address of the beginning of the grob of the screen, located in memory,
with the address: #8068Dh for the GX and #7050Eh for the SX.
The technique thus consists of pointing at this
address using one of the pointer registers such D0 or D1, ex: D0 = 8068D
of reading the address thus pointed, ex: A=DAT0 A, then to point on this
address has new using D0 or D1, ex: D0=A One collects the data themselves
using one of the working registers such A(A) or C(A), by a reading of the
zone thus pointed, ex: A=DAT0 A (Field A indicates that one wants to modify
the first 5 four-bit bytes, that is to say 5 * 4 = 20 pixels). One can
thus modify with wish these data: ex: A=0 A (one erases) or ABIT=1 3 (bit
3 is armed) and one rewrites given thus modified, ex: DAT0=A A
D0 = 8068D %(address of the screen)
A=DAT0 A %(lecture of the address)
D0=A %(point at this address)
A=DAT0 W %(reads the 16 four-bit bytes, that is
to say 16 * 4 = 64 pixels)
ABIT=1 4 %(arm pixel 4)
DAT0=A A %(rewrites the data thus modified)
If one wants, one can even charge a value and
display it with the screen, ex: LC 55 DAT0=C B (# 55h corresponds to #
0101010101b) It will then be displayed with the screen value # 55h, or
rather bits 1010101010 of the screen.
It will then be enough for us to traverse the
totality (or a part) of the screen to display a GROB on all the screen
(or a part). One course data of the screen while making moving the register
to point ahead:
ex: D0=D0+ n (0<n<17)
or D1=D1+ n (0<n<17)
or behind if one is located in bottom of the screen,
ex: D0=D0- n (0<n<17)
or D1=D1- n (0<n<17)
When you move the register ahead to point, you
move left then on the right. When you exceed the screen (on the right),
the register points then on the left, a lower line.
You traversed a line of the screen (136 pixels),
after having incremented your register to point of 34 four-bit bytes ahead,
or behind. Indeed, 34 * 4 = 136 pixels!
Caution: #34d
= > #22h
What gives with the register to point D0:
D0=D0+ 16
D0=D0+ 16
D0=D0+ 2
Or:
D0=D0- 16
D0=D0- 16
D0=D0- 2
Another more effective method would be to exchange
the contents of the pointer with that of a working register, to modify
this working register and finally, to exchange the contents of the working
register in question with the pointer. Ex:
D0 = 8068D
A=DAT0 A
D0=A %(D0 points with the screen)
AD0EX %(place the address of D0 in A(A))
LC 00022 %(load #22h is #34d four-bit bytes, a
line)
A=A+C A %(moves of a line downwards)
AD0EX %(replaces the new address in D0)
Summary:
To modify a data with the screen:
D0 = 8068D
A=DAT0 A
D0=A % One points on the beginning of the screen
A=DAT0 W % One recovers in A(W) the data of the
screen: 16 four-bit bytes 64bits
A=0 W %(on erases) or ABIT=1 8 (one arms pixel
8)
DAT0=A W % One rewrites the data thus modified
to write a data with the screen:
By crushing:
D0 = 8068D
A=DAT0 A
D0=A % One points on the beginning of the screen
C=0 A
LC 55555 % Loading of a value in C(A)
DAT0=C A %On writes the data contained in C(A)
over the current data
By transparency:
D0 = 8068D
A=DAT0 A
D0=A % One points on the beginning of the screen
A=DAT0 A % One reads the current data
C=0 A
LC 55555 % Loading of a value in C(A)
C=C&A A % " and " logic enters the current
data and the data charged
DAT0=C A % One writes the data contained in C(A)
by transparency
To display a GROB on all the screen
Above all, point out what is really a GROB. A
GROB is a graphic object obtained using environment PICTURE of your HP48.
In this object are stored all the data concerning the graph. It is thus
by reading these data that one can then display a GROB with the screen.
Accustom you as of now handling the GROB:
In environment PICTURE, draw then back up your
drawing using the key [ STO ].
Your drawing is then placed in the 1. level of
the pile, that gives:
Grob 131 * 64
To be able to insert it in your source program,
it is necessary to remove with the GROB their foreword and their size.
For that, you must republish the GROB in the following way:
GROB 131 64 123454100 [... 000
Becomes then:
$1234541000 [... 000
By suppression of prologue GROB 131 64, useless
in assembler.
To notice:
The insertion on the left of the character $ which
characterizes, in a source program, an unspecified data.
Thus, your GROB must resemble this one:
$12345100015343154135411531435411654153411531..
For launching out in the display of a GROB on
the whole screen, still is necessary it that you know how to recover the
address of this GROB!
With this intention, there are several methods:
the most known and employed of all the programmers out of assembler is
this one:
Method 1
GOSUBL label_1 % One places the beginning of the
GROB in RSTK
$000000032251405231430 % (it is the grob without
its size)
* label_1
C=RSTK % Ici one recovers in C(A) the address
of the GROB
% A the output, C(A) contains the address of the beginning of the GROB
% One can then is to save this address, (in R0 for example)
% is to point directly on this one using one of the registers
% pointer D0 or D1.
Example:
D0=c % Or D1=c
Method 2
The second method consists in directly reading
a GROB in the pile, and to display it with the screen. For that, one needs
from the very start of the program the address which contains the register
D1, because usually, it is in this register that is the address of the
object contained in the first level of the pile. One reads this address
using the instruction:
A=DAT1 A % Or C=DAT1 A
If this address is worth 0, therefore if A(A)
is null, there are no objects in the pile.
One tests then with:
?A¹ 0 A
GOYES label_1
GOVLNG 05143
* label_1
this level, one could test if the object in
the pile is well a graphic object:
LC 02B1E
?A=C A
GOYES label_2
GOVLNG 05143
* label_2
It remains us more than has to point on this
GROB using the instruction:
D1=A
This stage, it remains more than has to carry
out the copy of the data of the GROB on the data of the screen. Here is
the complete program which displays a GROB of 131 * 56 on the screen:
" GOSBVL 0679B
INTOFF
GOSUBL label_1
$123454115341865346854186 [...
* label_1
C=RSTK
D1=C
%(D1 points on the GROB to display)
D0 = 8068D
A=DAT0 A
D0=A
%(D0 points on the beginning of the screen)
LC 76F
%(has 56 lines there to display: 56 * 136 = %7616 pixels,
is 1904 four-bit bytes, or %encore # 770h. #770 - 1 = # 76Fh.)
* label_2
A=DAT1 A
%(recopy the data of the GROB %pointée by the
pointer register D1, %dans A(A))
DAT0=A 1
%(copy four-bit bytes by one, the %GROB with the screen,
the address contained %dans the pointer register D0)
D0=D0+ 1
%(moves of a four-bit byte on the right %sur the screen)
D1=D1+ 1
%(moves of a four-bit byte on the right %sur the GROB)
C=C-1 X
GONC label_2
%(loop ends when #770h %quartet is copied to the screen.
That is to say a %GROB of 131 * 56 pixels)
GOVLNG 05143
@ " |
Nothing prevents us from recopying the data of
the GROB to the screen, by several four-bit bytes at the same time.
It is then enough to use larger fields (ex: fields
B,X,W)
in the following way:
A=DAT1 B
DAT0=A B
Here, the fields B gathers 2 four-bit bytes, the
display will be carried out 2 times more quickly, in the condition of adjusting
the meter of loop:
(#770h ¸ 2) -1
= #3B7h
If not, the loop is too long and one writes in
the read-write memory (after the last line of the screen), which is formally
interdict under penalty of Mémory-lost!
Same manner, if one uses the fields W (16 four-bit
bytes), one thus needs a loop of value: (#770h ¸
#10h) - 1 = #76h
Thus, it is by as well as possible adjusting the
fields of our registers, during the display of one GROB to the screen,
which one can gain much speed of execution of the play.
But this method is valid only for the display
of GROB of 131 pixels of width, if not it is necessary to operate in a
different way.
To manage the sprites
How to display a sprite?
First of all, it should be announced that out
of assembler your sprites must have a width which amounts in four-bit bytes,
by group of 4 pixels. I.e.: 4, 8, 12, 16, 20, 24... for a simple reason:
that corresponds to the size of the fields of the registers of works! Thus,
for a sprite of 8 * 12 pixels, one will employ the fields B to display
a line of this sprite because the fields B can contain 8 pixels. You will
have to hold account of it when you carry out your sprites!
The sprites are drawn in surround PICTURE of your
HP48.
To recover a portion of screen (a ball for example)
of environment PICTURE, place the cursor in top on the left of this sprite
and press on the key [ * ] to place a mark, to then move you in bottom
on the right of this sprite and actuate the command [ sub ] to extract
your sprite. This sprite is then placed in the pile. Let us take the example
of a sprite of 8 * 12 pixels, Dessinez a black rectangle of size 8 * 12
pixels, then extract gives it, that in the pile:
Grob 8 * 12
If you publish it:
GROB 8 12 FFFFFFFFFFFF
Then remove the prologue and add the character
$:
$$FFFFFFFFFFFF
It is this portion of graph or sprite which we
must display with the screen. The width being equal to 8 pixels, we will
employ the fields B louse to carry out the display.
With this intention, several methods.
By crushing
We will employ again the method here said " by
crushing ", already approached previously. That means that the sprite will
be displayed over the current data of the screen.
To display a sprite, it is first of all necessary
to take account of its size. Here the width of our sprite is equal to 8
pixels, we will thus employ the fields B which is adapted best to the situation.
The technique then consists in displaying the sprite line with line, and
this using a loop which corresponds to the height (-1) in pixels of the
sprite. Here, our sprite with an effective height of 12 pixels, is # CH
- 1 = # Bh. Our loop of display will have like initial value: # Bh.
to pass from one line to the following one:
With the screen that corresponds has a shift of
34 quads (# 22h), on the other hand, on the sprite, all depends on its
width. For a width of 4 pixels, one moves of two four-bit bytes:
0>4 pixels:
4>8 pixels:
8>12 pixels:
12>16 pixels:
16>20 pixels:
20>24 pixels:
24>28 pixels:
...
|
2 four-bit bytes
2 four-bit bytes
4 four-bit bytes
4 four-bit bytes
6 four-bit bytes
6 four-bit bytes
8 four-bit bytes
...
|
Here the width of the sprite to be displayed being
equal to 8 pixels, one will move line on line: 2 four-bit bytes by 2. We
will display our sprite starting from the left higher corner of the screen
by recovering the address in: GOSBVL 0Ç31. Here what that gives:
" GOSBVL 0679B
INTOFF
GOSUBL sprite_1
$$FFFFFFFFFFFF
* sprite_1
C=RSTK
%(on recovers the address of the sprite)
D1=C %(D1 points on the sprite)
GOSBVL 0Ç31
%avec this routine D0 points on the screen
P = 0
LC B %(il has 12 there line, 12-1=11 or # Bh)
* label_1
A=DAT1 B %(on reads the sprite)
DAT0=A B %(on recopies it on the screen)
D0=D0+ 16
D0=D0+ 16
D0=D0+ 2
%(on passes to the following line to the screen)
D1=D1+ 2
%(on passes to the following line sprite)
C=C-1 P
GONC label_1
%(c' is the loop, 12 line to be copied)
GOVLNG 05143
%(on leaves the program!)
@ " |
By transparency
This technique of display having already been
approached previously, we will not be delayed there. Know that the technique
called by transparency consists has to copy the sprite with the screen
over the data of the screen by transparency between the screen and the
sprite. For that, one will use the instruction '! ' called: " and " logic.
The fields B will play the part of the meter of loop. Here our program:
" GOSBVL 0679B
INTOFF
GOSUBL sprite_1
$$FFFFFFFFFFFF
* sprite_1
C=RSTK %(on recovers the address of the sprite)
D1=C %(D1 points on the sprite)
GOSBVL 0Ç31
%(avec this routine, D0 points on the screen)
P = 0
LC B %(il has 12 there line, 12-1=11 or # Bh)
B=C P
* label_1
A=DAT1 P %(on reads the sprite)
C=DAT0 P %(on reads the screen)
A=A!C P %(on ' mélange' the whole!)
DAT0=A P %(on recopy on the screen)
D0=D0+ 16
D0=D0+ 16
D0=D0+ 2
%(on passes to the following line to the screen)
D1=D1+ 2
%(on passes to the following line sprite)
B=B-1 P
GONC label_1
%(c' is the loop, 12 line to be copied)
GOVLNG 05143 %(on leaves the program!)
@ " |
One cannot work out a video game without knowing
to manage the sprites perfectly. Thus it is necessary that you have a perfect
command of this part of the chapter. Involve to handle the GROB, sprites
and others.
How
to move a sprite?
First approach:
To move a sprite amounts moving on the screen
its position of display. This position depends on the address on which
one points with the screen. To modify this address amounts modifying the
position of display of the sprite, and thus to move it. For that, it is
necessary to the precondition to carry out a backup of the address or the
sprite must be displayed. One could as an example save this address in
the register of backup R0. That will give us then:
GOSBVL 0Ç31
AD0EX
R0=A
It will be enough for us then to move the sprite to
add 1 A the address backed up in R0:
A=R0
A=A+1 A
R0=A
Our sprite will move then four-bit byte (4 pixels)
on the right. Conversely, to move the sprite of a four-bit byte on the
left:
A=R0
A=A-1 A
R0=A
To downwards move the sprite of a line of the screen,
it is necessary to add 34 (# 22h) at this address:
A=R0
A=A+16 A
A=A+16 A
A=A+2 A
R0=A
Conversely, one upwards moves our sprite of a line
of the screen by withdrawing 34 at this address:
A=R0
A=A-16 A
A=A-16 A
A=A-2 A
R0=A
Display sprites (pixel by pixel)
(D.B = n lines of the sprite; A.A=X; C.A=Y; D1=@grob;
D0=@screen)
Authors: HPmad, HPandy, SunHP
|
C=C+C.A B=C.A CSL.A B=B+C.A CD0EX C=C+B.A B=A.A ASRB.A ASRB.A D0=C
DO { A=B.A C=DAT1.A ?ABIT=1.0 { C=C+C.X } ?ABIT=1.1 { C=C+C.X C=C+C.X
}
A=DAT0.A A=-A-1.A C=DAT1.4 A=A&C.A DAT0=A.4 D1=D1+ 4 D0=D0+ 34
D--.B
} WHILENC |
Although very
incomplete, I hope sincerely that of the world of the programming out of
assembler on HP48G(X) you will have liked this small approach!!To further
go, it will be necessary for you Hp48gX with a card of 128Kb + a ML48 book.
Document translated
by Tomas Furlan.
Julien
Meyer
Back
to my Home Page