RF-ASSEMBLER is a powerful MSX-DOS based Z-80 assembler for MSX2 computers. RF-ASSEMBLER differs from other MSX assemblers in the following respects:
- RF-ASSEMBLER is an assembler, a disassembler and debugger combined. This allows fast software development.
- RF-ASSEMBLER stores the source very efficient both in memory and
on disk. The sources actually resembles the assembled Z-80 code more
than the assembly code. On average this reduces storage by a
factor 2. For example:
LD A,B
is stored only as a single byte:78H
. More information can be found later in this document at the description of theMD
command. This efficient storage of your source code allows very fast assembly! - If your MSX computer is equiped with a MEMORY MAPPER, the source code allows storing the labels in a separate memory mapped RAM. This leaves more memory for running and debugging your software.
Starting RF-ASSEMBLER can be done when running MSX-DOS bij entering:
RFASMV24
followed by the <RETURN>
key. After starting RF-ASSEMBLER the
following question appears:
Include Help Pages (Y/N) ?
When answered with Y
RF-ASSEMBLER will read the file RFASSEM.HLP
,
allowing you to use the HP
(H
elP
) command. This requires about 5K
of RAM, which will not be available for other purposes. If answered with
N
the HP
command will not be available.
Next RF-ASSEMBLER reports for duty:
RF-ASSEMBLER for MSX-2 version 2.4
By Rolf Fokkens - 1987
RAM: Memory mapper (\*)
Free mem : xxxxx (xxxx-xxxx)
# Labels : xxxx (Max:xxxx )
?
As explained in the introduction RF-ASSEMBLER can operate both with and
without a MEMORY MAPPER. The software will identify the memory layout.
The RAM:
(also see the FM
command) line may report the following:
Memory Mapper
, indicating your computer is equiped with at least 128K RAM and a memory mapper.64KByte
, indicating your MSX2 has 64K RAM or no memory mapper. The latter is the case for the Philips VG8230.
The ?
is the RF-ASSEMBLER prompt, which allows you to enter a
command. All command's are made up of only two characters. After
entering a command no <RETURN>
needs to be entered. If the
command is not recognized by RF-ASSEMBLER it will be ignored, and the
?
prompt is displayed again. Except for the commands anything that
you enter needs to be terminated with the -key.
Most commands can be interrupted by hitting both the <CTRL>
and
the <C>
key at the same time. During listings you can hit the
spacebar to pause the listing until you enter the spacebar again.
If RF-ASSEMBLER requests a line number you can (of course) enter a line number, but you can also enter a label which refers to the first line where the label is defined. You can also enter label-number or label+number which refers to an offset of the line where the label is defined. This can be convenient if you are working with large programs.
The RF-ASSEMBLER line editor allow you to enter and change source code
lines. When entering a line there is a large sized cursor, indicating
you are working in overwrite mode. When hitting the <INS>
key
you will work in insert mode indicated by a small sized cursor. The
key toggles between insert and overwrite mode.
The following key strokes have specific meanings as well:
Right arrowMove the cursor right
Left arrowMove the cursor left
keyRemove the character pointed to by the cursor
keyRemove the character left from the cursor
Next follow the two-character editor commands:
This command allows you to enter new sources code. If there is existing source code in memory, RF-ASSEMBLER will ask:
Code erasure. Proceed (Y/N) ?
If you answer 'Y
' the source code in memory will be wiped, and the
defined filename will be ‘forgotten’. If you enter ‘N’ the CP
command is aborted.
After the memory is wiped the following is displayed:
0001
This is the line number of the first line. You can enter the line of assembly code now. After entry of the first line, the following is displayed so you can enter the second line:
0002
This repeats until you hit <CTRL>
<C>
.
The following rules apply for RF-ASSEMBLER source code:
- If a label is defined on a line, the line should not start with white space;
- If no label is defined on a line, the line should start with white space;
- Always enter uppercase, except between quotes ( ' ) or after a semicolon ( ; ).
Some example code:
0001 LOOP DEC BC ; the label LOOP is defined here.
0002 LD A,B ; no label is defined here
0003 OR C
0004 JR NZ,LOOP; no label is defined, but the label LOOP is used.
0005 RET
You can also enter:
0001 LOOP DEC BC
0002 LD A,B
0003 OR C
0004 JR NZ,LOOP
0005 RET
Additional rules that apply:
-
Labels start with an alphabet character, other characters are alpha numerical. A label is max 8 characters in length. Some labels are not allowed:
A
,B
,C
,D
,E
,H
,L
,AF
,BC
,DE
,HL
,IX
,IY
,IXH
,IXL
,IYH
,IYL
,SP
,Z
,NZ
,C
,NC
,PE
,PO
,M
,P
,I
,R
. -
Constants always start with a digit. Hexadecimal constants always end with a
H
, binary constants always end with aB
and octal constants always with aO
. Instead of a number you can also specify a character between quotes ('
), this represents the ASCII code of the character, for example:CP 'A' ; is equivalent with CP 65 LD HL,377O ; is equivalent with LD HL,255
Furthermore you can use $
, which refers to the address of the current
instruction. For example:
LABEL DJNZ LABEL
is equal to
DJNZ $
-
Math expressions allow the following operations: additions (
+
), subtraction (-
), multiplication (*
), division (/
), bitwise AND (&
) and bitwise OR (!
). The order of evaluation is: First*
,/
and&
. Second+
,-
and!
. The order of evaluation can be overruled by applying brackets. Brackets may only be nested 6 times, otherwise this error is displayed:\*** Bad nesting
An example of this:
LD A,(((((((4)))))))+2
The following is allowed:
LD A,(((4)))+2
Application of brackets may introduce ambibuity, for example:
LD A,(d)
This may both mean “load A with constant d” and “load A from memory address d”. When possible RF-ASSEMBLER assumes a memory reference is intended. For example:
0001 LD HL,1+2-3+4+OFFSET 0002 LD (IX+DISPLACE-3),VALUE+0FFH 0003 LD A,'T'+1 0004 LD A,(3)+(4) ; = LD A,7 0005 LD A,((3)+(4)) ; = LD A,(7) 0006 XOR 45H
As a rule of thumb never use more brackets than needed!
Now some examples of invalid RF-ASSEMBLER source code:
0001 LD A,3 ; First character should have been white space
0002 LOOP NOP ; First character should NOT have been white space
0003 0TEST NOP ; First character should not have been a digit
0004 LD HL,FFFFH ; FFFFH should have been 0FFFFH
0006 LD A,'A ; Missing '
0007 ld A,3 ; ld should have been LD
0008 A NOP ; A is an illegal label
This extends the existing source code in memory. The ‘next free’ line
number is displayed, after which everything is like the CP
command.
This allows changing the existing source code in memory. First you’ll be prompted:
Line\#?
Now you can enter the number of the line you want to change, after which the requested line is displayed.
Now you can use the following keys:
- Up arrow: navigate one line up
- Down arrow: navigate one line down\
<D>
(Delete) key: remove the current line\<I>
(Insert) key: insert lines (seeIS
)\<C>
(Change) key: change the line using arrow keys,<INS>
, etc.\<CTRL>
: abort the ED-command
Lines can be inserted in the existing source in memory. First you’ll be requested to enter:
Line#?
Now you can enter the number of the line where you want to insert a
line, after which everything is like the CC
command.
This allows to remove a line. RF-ASSEMBLER asks which line you want te remove. For example assume your have the following source code:
0001 ; line 1
0002 ; line 2
0003 ; line 3
Now suppose you want to remove line 2:
? DL
Line#? 2
You now have the following source code:
0001 ; line 1
0002 ; line 3
As you see line 2 is no longer there.
Remove multiple lines. You’ll be prompted to enter:
First line#?
Last line#?
Next RF-ASSEMBLER will remove the specified lines from the source code in memory.
Move a number of lines in the source in memory. You’ll be prompted:
First line#?
Last line#?
Insrt line#?
This command cannot be used to move lines to the END of the source code
in memory. In that case you’ll need to add a temporary line to the end
first, and then use that line as the 'Insrt line
'.
Proper naming of labels is essential when programming in assembly language, is this allows for better understanding the program. RF-ASSEMBLER allows you to change a label whenever you like, and the change is carried out consistently everywhere in your program. The following is requested when changing a label:
Original label :
New label :
A label cannot be renamed to an existing label. Furthermore the
Original label
should actually exist in the source code.
The commands in this chapter do not assist you in changing your program, they allow you to view the source code and to assemble it to real Z-80 machine code.
The entire source is listed, for example:
? LC
0001 ; line 1
0002 ; line 2
0003 ; line 3
?
You can pause the listing by hitting the space bar, or abort the listing
by hitting <CTRL>
<C>
.
The source is listed staring from a specific line you are prompted to
specify. Assuming your program is the same as shown above at the CC
command, the following is an example of the LL
command:
? LL
First line#? 2
0002 ; line 2
0003 ; line 3
?
Labels and their values can be listed. You reply to RF-ASSEMBLERS prompt Label mask? Allows you to specify a wildcard for the labels you want to be listed, for example:
A* (All labels staring with an A)
A?ENOOT (All labels ending at ENOOT)
If the value of a label is known by RF-ASSEMBLER (after an AM
, AS
,
LI
or WO
command) the value will be displayed as well. For example:
? LS
Label mask? ?A*
LABEL1 F345 LABEL2 0005 WACKO JACKO 0000
?
So all labels with the second character being ‘A’ are listed.
An assembly listing (both source code and generated Z-80 machine code) will be displayed, including a list of labels and their values (see the LS command above). RF-ASSEMBLER asks you from what line the listing should be displayed. Any errors during processing of the source code will be reported. Possible errors are:
Undefined label
: the value of a label can not be determinedDoubly defined
: label is defined multiple timesOut of range
: relative jump is to far
For example:
? AS
First line\#? 2
Pass1
Pass2
0007 00 0002 LABEL NOP
0003 *** Undefined label
0008 210000 0003 LD HL,PRINCE
0009 3E55 0006 LD A,170
LABEL 0007 PRINCE
?
As demonstrated by the example alle used labels are listed. Pass1
is
the first step in which RF-ASSEMBLER attempts to determine the values of
all labels. During Pass2
RF-ASSEMBLER substitutes the lables during
the actual assembly.
Any assembly errors will be determined as explained above at the AS
command.
Assuming your program is the same as the example at the AS
command,
the LI
command will work like this:
? LI
Pass1
Pass2
0003 *** Undefined label
You program is directly assembled to memory, existing code or data in memory will be overwritten. If RF-ASSEMBLER attempts to assemble to reserved parts of memory (for example your source code), it will report an error:
*** Memory error
Assembly aborted
You may have to direct RF-ASSEMBLER to assemble to another part of
memory using the pseudo opcode ORG
(OriGin), for example:
0001 ORG 100H; This program starts at address 100H
The FM
command (explained later in this document) may be useful in
determining free memory.
This chapter documents commands that deal with your floppy disk.
Set the filename of your source code. First the current filename is displayed, the you can enter a new filename. For example:
Old file name : ABCDEFGH.IJK
New file name :
You must choose a valid filename, optionally with an extension. If you
omit the extension, it will default to .ASM
.
Your source code is assembled into Z-80 machine code and written to
disk. The filename is determined by the FN
command, but the extension
will be set to .COM
, which allows you to easily start it from MSX-DOS.
When you are using using the pseudo opcode DEFS
space in the file will
be filled with zeroes. The ORG
pseudo opcode should not be used
multiple times in general, and especially not when using the WO
command because any empty spaces is not initialized. Instead of:
ORG ADDRESS
you should use:
DEFS ADDRESS-$
This will initialize the empty space with zeroes.
Your source code will be written to disk. The following question will be presented:
Ascii or Code (A/C) ?
If answered with A
your source will be written to disk as a normal
human readable ASCII file.
If answered with C
the source will be written in the native
RF-ASSEMBLER format. This saves you a lot of space on disk (up to 3
times) and a lot of time writing to and reading from disk.
In case there is an existing file, this file will be renamed to a file
with a .BAK
extension first.
This commands reads source code from disk. If there’s source code in memory, the following question will be displayed:
Code erasure. Proceed (Y/N) ?
When answered with Y
the existing source code in memory is erased,
otherwise the source code from disk is merged at the end of the source
code in memory. The latter requires the source file to be an ASCII file,
otherwise the following error is displayed:
*** Bad file mode
It allways asks you to enter the filename of the source to be read from disk.
RF-ASSEMBLER automatically identifies if a source file is in ASCII or
Code format. If it is an ASCII file it will be stored in memory as Code.
Whenever RF-ASSEMBLER is not able to convert a line into code, the line
will be prepended by a ;
and stored as a comment.
This command lists the files that are on disk, and the amount of space that is available on disk. RF ASSEMBLER will ask:
Dir mask :
This allows you to specify a wildcard to be applied as filter when listing the files.
Examples:
A:E\*
(All files on drive A: starting with E)????????.???
(All files (on the default drive))*.*
(All files (on the default drive))
For debugging porposes you can disassemble machine code in memory, and
you can single-step through machine code while viewing and editing registers and
memory contents. Before using the debugger you should store your source
code on disk, because the GO
command passes full controll to the code
you are debugging with potential harmful consequences when bugs are
encountered.
This chapter documents the debugger commands.
A memory range is displayed both in hexadecimal and ASCII. RF-ASSEMBLER
asks Address ?
So you can specify from which address the memory should
be displayed. Memory is displayed in blocks of 16 memory locations, any
key you enter shows the next 16 memory locations. <CTRL>
<C>
aborts
the command. For example:
? MD
Address (Hex)? 8000
8000 00 41 42 43 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 .ABCDEFG HIJKLMNO
8000 31 32 33 34 35 36 37 38 39 FF FF FF FF FF FF FF 12345678 9.......
Data in memory can be modified. RF-ASSEMBLER asks which memory address
you want to change, next it shows you the address and it’s contents. Any
(hexadecimal) value you enter will be stored at that memory address. If
you simply hit the <ENTER>
key, the memory address is left
unchanged. Next it shows the next address and it’s contents and all
repeats. For example:
? MM
Address (hex) ? 8000
8000 55
8001 00 44
8002 34 1
Some specific memory locations will be disassembled into Z-80 assembly
code. You will be asked at which memory address this should start. By
entering any key (except <CTRL>
<C>
) RF-ASSEMBLER
disassembles the next instruction. For example:
? DS
Address (Hex)? 8000
8000 21 34 12 LD HL,1234H
8003 00 NOP
8004 18 FA JR 8000H
While debugging and testing your program, it sometimes may be useful to
put some specific machine code somewhere in memory without changing your
source code. This can easily be achieved by means of the AI command.
RF-ASSEMBLER will ask you the memory address Address (hex) ?
at which
you want to put specific machine code. Next the existing machine code is
disassembled on your screen, and you can enter the assembly instructions
you want RF-ASSEMBLER to assemble at this memory address. For example:
? AI
Address (hex) ? 8000
8000 00 NOP LD A,(9001H)
8003 00 NOP NOP
This repeats until you hit CTRL
<C>
.
If you want a part of your program to be executed autonomously, but you
want to regain control in the RF-ASSEMBLER debugger at a certain point,
you can set a breakpoint at that point. If you then fire the GO
command, your program will return to RF-ASSEMBLER at the breakpoint
after which all debugging options are available.
A total of 8 breakpoints can be set. The BK
command will display
defined breakpoints, and allows you to enter another one (unless already
8 are defined):
Address (Hex) ?
Your reply specifies the memory address at which you want to set a breakpoint.
This command removes breakpoints. A list of defined breakpoints (if any) is displayed, for example:
Breakpoints :
1 9000
2 9001
The breakpoints are numbered, you will be asked:
Breakpoint no. ?
Now you can specify the number of the breakpoint you want to be cleared. You can also reply ‘A’ (All) which means all breakpoints will be cleared.
To pass controll to the program you are debugging, use this command. Wrong use of this command may result in loss of control over your computer and loss of source code in memory. Therefore you will be asked:
Go. Proceed (Y/N)?
When answered ‘Y’ controll is transferred to the program being debugged
at the memory location pointed to by the PC
register until it runs
into a breakpoint. You may need to specify a proper value for the PC
register first using the RG
command.
This starts the single stepper. This allows you to run each machine
instruction (pointed to by the PC
register) step by step, while all
CPU registers are displayed. You may need to specify a proper value for
the PC
register first using the RG
command.
Hitting the space bar executes a single instruction and moves the PC
register to the next instruction.
Hitting the <X>
key executes a CALL
(and an RST
) to a
subroutine completely and returns to the debugger after the call has
completed.
Hitting the <G>
key is the same as executing the GO
command.
Hitting <CTRL>
<C>
aborts the single stepper. You can
easily continue using the single stepper by using the SP
command
again.
This command allows you to change a value of any of the Z-80 registers. First the current values of the registers are displayed and the interrupt status, for example:
F : NC,NZ,PO,P,EI
AF 0000 BC 0000 DE 0000 HL 0000 IX 0000 IY 0000
A' 0000 B' 0000 D' 0000 H' 0000 SP D505 PC 0000
The F
(flags) register actually is displayed twice, on the first line
as separate flags, on the second line as a hexadecimal value as part of
AF
. The first line also displayes the interrupt status register.
By answering the following prompt you can specify which register to change:
Register :
You can specifie the following registers / register pairs: AF
, BC
,
DE
, HL
, IX
, IY
, A'
(=AF'
), B'
(=BC'
), D'
(=DE'
),
H'
(=HL'
), SP
, PC
, A
, B
, C
, D
, E
, H
, L
, IXH
,
IYH
, IXL
, IYL
en F
.
Next you can specify the value by answering:
Value :
For the F
(Flags) register not a (hexadecimal) number should be
specified, but one or more of the following flags separated by commas:
C
carry-flag is set to 1NC
carry-flag is set to 0Z
zero-flagis set to 1NZ
zero-flag is set to 0PE
P/V-flag is set to 1PO
P/V-flag is set to 0M
sign-flag is set to 1P
sign-flag is set to 0
Additionally you can change the interrupt-status by specifying the following as part of the flags:
DI
Disable InterruptEI
Disable Interrupt
For example a correct answer might be:
NC,DI,PO,Z
Sometimes it may be convenient to convert a value from and to
hexadecimal, decimal, octal or binary. The CV
command does this for
you. First you’ll be prompted:
Value :
You can specify any number in binary, ocal, decimal or hexadecimal. For example:
Value : 10101010B
0AAH 170 252O 10101010B
You can specify a hexadecimal number by appending an H
, an octal numer
by appending an O
and a binary number by appending a B
. Decimal
numbers have no character appended.
This chapter documents a few unclassified commands.
RF-ASSEMBLER displays the available memory for your programs machine code. Additionally the (maximum) number of labels is displayed, for example:
? FM
Free mem : 9964 (B201-D505)
# Labels : 943 (Max: 1200)
This command displays help pages if loaded during startup of
RF-ASSEMBLER. Pages are selected by hitting keys <0>
to
<9>
. <CTRL>
<C>
aborts the HP
command.
This toggles the printer. Printer on
means that anything on your
screen is sent to your printer as well. If your printer is blocking you
can resolve this by hitting <CTRL>
<STOP>
.
This command terminates RF-ASSEMBLER and brings you back to MSX-DOS. You will be asked:
Quit. Proceed (Y/N)?
When answered ‘Y you will return to MSX-DOS indeed, but any source code in memory will be lost unless you wrote it to disk first!
RF-ASSEMBLER knows pseudo-opcodes that are not true Z-80 assembly instructions. They provide information for RF-ASSEMBLER that will be used during assembly of your source code.
Specifies at which memory address machine code should be generated by RF-ASSEMBLER. For example:
0001 ORG 100H; The program starts at 100H
Specifies the value of a symbol (a label is also a kind of symbol), for example:
0001 VALUE EQU 1234H; VALUE equals 1234H
Puts a specific 1 byte value in memory, for example:
0001 DEFB 5; Put value 5 at this memory address
Like DEFB
but this specifies a 2 bytes value.
Reserves a specified amount of bytes in memory, for example:
0001 DEFS 2; Reserve 2 bytes space here
Store an ASCII string in memory, for example:
0001 DEFM 'Test'; Store the word Test here
This opcode is meaningless to RF-ASSEMBLER, but it allows some
compatibility with other assemblers that require an END
opcode at the
last line of the source code.
*** Bad
A bad answer was given when prompted (e.g. Line\#?
)
*** Bad file mode
While merging source code (RS command) the additional source file is not
ASCII formatted
*** Bad label
An invalid label is referenced or defined in a source code line.
*** Bad nesting
An expression contains to many nested brackets
*** Bad opcode
An invalid Z-80 assembly opcode is used
*** Bad operand
An invalid Z-80 assembly operand is used
*** Bad version
A source file in Code format was created in a newer RF-ASSEMBLER version
*** Disk full
Disk full while writing a file.
*** Double defined label
A label is defined twice
*** Expression too long
An expression in source code is too long
*** File not found
A file is not found on disk
*** Memory error
There’s insufficient memory while assembling to memory (AM
command)
*** Memory full or too many labels
No more memory available to store more source code or labels
*** Missing label declaration
An EQU
pseudo opcode was issued without a label on the same line
*** No label declaration allowed
An ORG
pseudo opcode was issued with a label defined on the same line
*** No source file
While reading a source file (RS
commando) the format is not recognized
by RF-ASSEMBLER
*** Out of range
A relative jump (JR
or DJNZ
) is out of range.
*** Printing aborted
The printer is disabled by hitting the <CTRL>
<STOP>
keys
*** Undefined label
There’s a reference in the source code to an undefined label.
*** Unexpected end of file
While reading a source file (RS
command) the file unexpectedly ends.
CC
(Continue Composition) Add lines to the end of the source code
CP
(ComPose) Create new source code
CS
(Change Symbol) Change a label or symbol
DL
(DeLete) Remove a source code line
DM
(Delete Multiple lines) Remove multiple source code lines
ED
(EDit) Edit source code lines
IS
(InSert) Insert source code lines
MB
(Move Block) Move source code lines to another position
AS
(Assemble to Screen) Create an assembly listing on screen
AM
(Assemble to Memory) Assemble to machine code in memory
LC
(List Completely) Generate a full listing of the source code
LI
(List Internal errors) List all assembly errors
LL
(List to Last line) Generate a listing of the source code starting at
a specific line
LS
(List Symbols) List all labels/symbols in the source code and their
values if known
DR
(DiRectory) List a directory on disk
FN
(FileName) Set the filename of your program
RS
(Read Source) Read a source file from disk
WO
(Write Object) Assemble your program, write it to disk
WS
(Write Source) Write your source code to disk
AI
(Assemble Immediate) Assemble your program, write it to memory
BK
(BreaKpoint) Define a breakpoint
CB
(Clear Breakpoint) Remove a breakpoint
CV
(ConVert) Convert number formats
DS
(DiSassemble) Disassemble machine code in memory
GO
(Go) Run machine code in memory
MD
(Memory Dump) Display memory contents
MM
(Memory Modify) Modify memory contents
RG
(ReGister) Change the value in a Z-80 register
SP
(SteP) Step by step execute machine code in memory
FM
(Free Memory) Display available memory
HP
(HelP) Display help pages
PT
(PrinTer) Enable or disable the printer
QT
(QuiT) Leave RF-ASSEMBLER
RF-ASSEMBLER knows all official Z-80 instructions. Furthermore it knows
some ‘extra’ unofficial instruction that the Z-80 also. These
instructions process the IXH, IXL, IYH en IYL
registers,
meaning:
-
IXH
,IYH
: The upper 8 bits ofIX
,IY
respectively -
IXL
,IYL
: The lower 8 bits ofIX
,IY
respectively
For example:
LD A,IXH
INC IXH
ADD A,IYL
LD IYH,5
RF-ASSEMBLER also knows the SLL
instruction, which is equivalent with:
SCF
RL r ; r denotes any 8 bits register
In general these extra instruction are handled well by the Z-80, but Zilog does not guarantee their proper operation on all Z-80’s.
The complete list of all Z-80 instructions and psuedo opcodes RF-ASSEMBLER knows:
ADC A,s IND LDDR
ADC HL,ss INDR LDI
ADD A,s INI LDIR
ADD HL,ss INIR NEG
ADD IX,pp JP (HL) NOP
ADD IY,rr JP (IX) OR s
AND s JP (IY) OTDR
BIT b,m JP cc,nn OTIR
CALL cc,nn JP nn OUT (C),r
CALL nn JR C,e OUT (n),A
CCF JR NC,e OUTD
CP s JR NZ,e OUTI
CPD JR Z,e POP IX
CPDR JR e POP IY
CPI LD (BC),A POP qq
CPIR LD (DE),A PUSH IX
CPL LD (HL),n PUSH IY
DAA LD (HL),r PUSH qq
DEC IX LD (IX+d),n RES b,m
DEC IY LD (IX+d),r RET
DEC m LD (IY+d),n RET cc
DEC ss LD (IY+d),r RETI
DEC x LD (nn),A RETN
DEFB n LD (nn),IX RL m
DEFM 'cs' LD (nn),IY RLA
DEFS nn LD (nn),ss RLC m
DEFW nn LD A,(BC) RLCA
DI LD A,(DE) RLD
DJNZ e LD A,I RR m
EI LD A,(nn) RRA
END LD A,R RRC m
EQU nn LD I,A RRCA
EX (SP),HL LD IX,(nn) RRD
EX (SP),IX LD IX,nn RST p
EX (SP),IY LD IY,(nn) SBC A,s
EX AF,AF' LD IY,nn SBC HL,ss
EX DE,HL LD R,A SCF
EXX LD r,m SET b,m
HALT LD r,n SLA m
IM 0 LD SP,HL SRA m
IM 1 LD SP,IX SLL m
IM 2 LD SP,IY SRL m
IN A,(n) LD ss,(nn) SUB s
IN r,(C) LD ss,nn XOR s
INC IX LD u,x
INC IY LD x,n
INC m LD x,u
INC ss LD x,x'
INC x LDD
With specific meaning for:
b
: A number from 0 to 7d
: A number from 0 to 255e
: An address that’s at most 128 bytes distant from the current location (*)n
: A number from 0 to 255nn
: A number from 0 to 65535p
: any of the values0
,8
,10H
,18H
,20H
,28H
,30H
of38H
(**)r
:A
B
,C
,D
,E
,H
orL
m
:r
,(HL)
,(IX+d)
or(IY+d)
u
:A
,B
,C
,D
orE
x
:IXH
,IXL
,IYH
orIYL
x'
:IXH'
,IXL'
,IYH'
orIYL'
(***)sr
:n
,(HL)
or(IX+d)
cs
: An ASCII string, e.g.’SillyMessage’
cc
: Any of the conditionsNZ
,Z
,NC
,C
,PO
,PE
,P
orM
pp
:BC
DE
,IX
orSP
qq
:AF
BC
,DE
orHL
rr
:BC
DE
,IY
orSP
ss
:BC
DE
,HL
orSP
(*) **** Out of range
is reported if e
does not meet the constraints
(**) Addresses are rounded down by RF-ASSEMBLER to these values
(***) If x
is part of IX
(resp IY
) is, the so must x'
MSX ROM-BIOS routines are not directly available from MSX-DOS, because the BIOS-ROM is 'hidden' when running MSX-DOS. This may be very inconvenient during testing and debugging with RF-ASSEMBLER because RF-ASSEMBLER runs on MSX-DOS. There is a simple solution though: you can use a so called INTER-SLOT-CALL. This allows programs to call subroutines in other MSX memory slots. An INTER-SLOT-CALL works like this:
RST 30H ; The subroutine at 30H executes the INTER-SLOT-CALL
DEFB SLOTID ; This is the slot ID
DEFW ADDRESS ; This is the memory addres of the subroutine
This is almost equivalent to:
CALL ADDRESS
The additional SLOTID
refers to a specific memory slot though.
SLOTID is a byte value, with the following structure:
FxxxSSPP (bit 7....bit 0)
The letters have the following meaning:
FF
=1 if secundary slot, otherwise 0SS
: secundary slotnumberPP
: primary slotnumber
In all MSX computers the BIOS-ROM is in primary slot 0, so an INTER-SLOT-CALL to the BIOS-ROM looks like this:
RST 30H
DEFB 0 ; Primary slot 0 = BIOS-ROM!
DEFW ADDRESS
For example if we want our program to print a letter on our display it should call the BIOS-routine CHPUT. This would normally look like this:
CHPUT EQU 0A2H
;
CALL CHPUT
Using an INTER-SLOT-CALL this looks like this:
CHPUT RST 30H
DEFB 0 ; Slot ID, so primary slot 0
DEFW 0A2H ; Het adres in de BIOS-ROM
RET
;
CALL CHPUT
This works both when running from MSX-DOS and from BASIC.
If you want your program to call a rountine in the EXTENDED ROM (MSX2),
you cannot call the BIOS rountine as described above. There is an
alternative way to do this from both MSX-DOS and BASIC: CALSLT
. For
example:
CALSLT EQU 1CH
;
PAINT LD IX,69H ; Address of paint
LD IY,(0FAF7H) ; Slot ID in IY
JP 1CH
;
CALL PAINT
Warning: Special care must be taken when using the RF-ASSEMBLER
single-stepper while using the RST 30H
method. Never execute code like
this in the single-stepper:
LABEL RST 30H
DEFB SLOTID
DEFW ADDRESS
RET
This code should always be called completely, so use the X
key in the
single-stepper when running in to this instruction:
CALL LABEL
This single-stepper complication is very hard to solve reliably in RF-ASSEMBLER, as it is caused by the ‘weird’ way the INTER-SLOT-CALL operates.
Programs running from MSX-DOS are very different from BLOAD
programs
running from BASIC:
- MSX-DOS-programs always start at address 100H, so no information about the starting location is stored in the program files.
BLOAD
programs can be stored at any location in memory, and execution can also start at any location in memory. Therefore specific information is stored in the header of aBLOAD
program.
It is no problem to create a BLOAD program with RF-ASSEMBLER., just make sure your source code starts with these lines:
; BLOAD header:
DEFB 0FEH ; BLOAD identifier
DEFW BEGIN ; startaddress
DEFW END ; endaddress
DEFW ENTRY ; execution-address
For example:
;
; example program
;
DEFB 0FEH ; Don’t include these
DEFW BEGIN ; lines during debugging
DEFW END ; in your source code,
DEFW ENTRY ; because of Memory error!
; use these only in the final
; version
;
ORG 9000H
;
; programmatekst
;
BEGIN JP ENTRY
;
CHPUT RST 30H ; Display a letter
DEFB 0 ; using INTER-SLOT-CALL
DEFW 0A2H
RET
;
; main program
;
ENTRY LD A,'a' ; ENTRY=execution address
CALL CHPUT
RET
;
END END
This example program can be run with the BASIC BLOAD command. It displays an ‘a’ and then returns.
Note that this program cleverly uses the END
pseudo opcode.