WinAli
WinAli is a model assembler (see also assembly language ) for Windows and DOS . The generated machine code is executed with a model computer that is an emulation of a real processor. WinAli is intended for learning assembly language. The developer is aimed at students who already have knowledge of ( object-oriented ) high-level languages , primarily Pascal .
Data types
Ordinal
WinAli only knows one data type . According to the WinAli documentation, it is an integer . However, the data type is two bytes in size and therefore does not correspond to the Pascal data type Integer
or the C data type int
(on 32- bit systems) which occupy four bytes.
The fact that the WinAli data type can store signed values two bytes in size makes it a Smallint
(Pascal) or a short
(C).
register
WinAli provides 16 registers which, however, have no specific meaning, as is the case with x86 assemblers.
Register such as CX
are not implemented in WinAli. Instead, the registers are simply addressed with the numbers 0
to 15
.
Stack
Just as there are 16 registers, there are also 16 independent stacks that are addressed in the same way as the registers. Consequently, it depends on the context whether the character is 0
interpreted as the first register or as the first stack.
variables
Since variables can only have a single data type in WinAli , it is not necessary to explicitly Smallint
identify this as . A variable wVar
is defined as follows;
wVar ds f
However, it is not only possible to define a single variable, but also a whole (constant) array rgwVar
with, for example, 16 elements;
rgwVar ds 16f
Constants
There are two ways to define constants. The more elegant of these is wTwo = 2
to declare the constant as such;
wTwo dc '2'
However, you don't have to declare a new symbol for every constant. If you write down wTwo
the number in inverted commas instead of a symbol (such as:) at a point where a variable or constant is expected, WinAli automatically declares it when assembling.
wFive dc '5' ... lda 0,wFive;gleichbedeutend mit: lda 0,'5' ...
syntax
Formally
The syntax of WinAli is strongly based on a real assembler such as TASM ( Borland ) or MASM ( Microsoft ). You can divide each line of code into four columns;
label command params comment
The indenting of the words serves for better legibility.
keyword | meaning |
---|---|
label
|
A label or a jump destination that can be jumped to from another line. Often this column remains empty. |
command
|
Command to be executed on this line. A detailed explanation of all commands is given in the section Command Reference . |
params
|
Each command has one or two parameters , this is at least one register and, depending on the command, another register, a stack or an address to a memory location . If the command has two parameters, they are separated by a comma " , ". |
comment
|
A comment of any length, which is introduced by a " ; " or a " * " and terminated by the end of the line. |
example
The following example shows the structure and appearance of a WinAli program.
loop sta 0,wSav;wSav = r lda 0,cwMult sub 0,'1';cwMult-- sta 0,cwMult cmp 0,'1' add 0,'1' mul 0,wSav;r:=cwMult*wSav bne loop
As you can see from the Pascal commands noted in the comment area on the right, a WinAli program is always longer and also less intuitive than a program in a high-level language such as C, C ++ or Pascal.
Command reference
There are several versions of the WinAli command syntax circulating, so the command names are different. The command lda
can be called in another version instead l
. However, the number of commands is the same.
Commands
Input and output commands | ||
---|---|---|
ini A
|
The value entered by the user is A saved in the address .
|
|
outi A
|
The A value stored in the address is output on the UI .
|
|
transport | ||
lda R,A
|
Loads the A value stored in the address into the register R .
|
R:=A;
|
ldr R0,R1
|
Loads the value in the register R1 into the register R0 .
|
R0:=R1;
|
ldcr R0,R1
|
Loads the complement of the value in the register R1 into the register R0 .
|
R0:=-R1;
|
sta R,A
|
Stores the value in the register R in the address A .
|
A:=R;
|
arithmetic | ||
add R,A
|
Adds the value in the address A to the value in the register R .
|
R:=R+A;
|
addr R0,R1
|
Adds the value of the register R1 to the value of the register R0 .
|
R0:=R0+R1;
|
sub R,A
|
Subtracts the value in the address A from the value in the register R .
|
R:=R-A;
|
subr R0,R1
|
Subtracts the value of the register R1 from the value of the register R0 .
|
R0:=R0-R1;
|
mul R,A
|
Multiplies the value in the address A by the value in the register R .
|
R:=R*A;
|
mulr R0,R1
|
Multiplies the value of the register R1 by the value of the register R0 .
|
R0:=R0*R1;
|
div R,A
|
Divides the value of the register R by the value in the address A .
|
R:=R div A;
|
divr R0,R1
|
Divides the value of the register R0 by the value of the register R1 .
|
R0:=R0 div R1;
|
Comparison (is evaluated relative to the first parameter) | ||
cmp R,A
|
Compares the value of the register R with the value in the address A .
|
if (R ## A) then
|
cmpr R0,R1
|
Compares the value of the register R0 with the value of the register R1 .
|
if (R0 ## R1) then
|
Jump (if conditional, depending on the result of a comparison) | ||
b A
|
Jumps to the program line A specified in the address (label) (in short: jumps to A ).
|
goto A;
|
be A
|
Jumps to A when the operands of the comparison were the same.
|
if (R = O) then goto A;
|
bne A
|
Jumps to A if the operands of the comparison were not equal.
|
if (R <> O) then goto A;
|
bh A
|
Jumps to A if the first operand of the comparison was greater than the second.
|
if (R > O) then goto A;
|
bnl A
|
Jumps to A if the first operand of the comparison was greater than / equal to the second.
|
if (R >= O) then goto A;
|
bnh A
|
Jumps to A if the first operand of the comparison was less than or equal to the second.
|
if (R <= O) then goto A;
|
bl A
|
Jumps to A if the first operand of the comparison was smaller than the second.
|
if (R < O) then goto A;
|
Jump to a subroutine (all unconditional) | ||
bal R,A
|
Jumps to A and saves the return address in the register R .
|
|
balr R0,R1
|
Jumps to R1 and saves the return address in the register R0 .
|
|
la R,A
|
Loads the address of A into the register R .
|
R:=@A;
|
br R
|
Jumps to the address R stored in the register .
|
|
Stack operations | ||
push R,S
|
Push't the value in the register R into the stack S .
|
S.Push(R);
|
pop R,S
|
Pop't the top item from the stack S into the register R .
|
R:=S.Pop();
|
top R,S
|
Copies the top element from the stack S into the register R . However, the element remains in the stack.
|
R:=S.Top
|
control | ||
eoj
|
Marks the end of the source code. |
end.
|
nop
|
Does not perform any operation. Can be used to make the code clearer. | |
nopr
|
Same effect as nop , but only occupies two instead of four bytes.
|
Note on the table:
- Explanations are written in (Object) Pascal.
- The correct notation of the code WITH line break has been omitted for the sake of clarity.
Command size
The size of an instruction is either two or four bytes.
Each command with two parameters, the second parameter of which is an address (i.e. no register and no stack), and the command nop
occupy four bytes. All other commands occupy two bytes.
Data structures
Arrays
In contrast to many other assemblers, arrays are implemented directly in WinAli. Addressing elements by directly calculating their address using an offset and the base address is therefore not necessary. When addressing an element, WinAli even performs a range check and triggers a runtime error if the index is incorrect . Has the array rgwVar been declared;
rgwVar ds 8f
Then you can address an element by loading the offset into one of the registers, 1
to 15
and then noting that register in brackets after the name of the array (using the register 0
for indexing does not work). The offset is the relative address of the element in the array, i.e. the product of index and data size (which is always 2). The following example copies the value at the location of '3'
the array rgwVar
into the variable iwDrei
, using the register 1
for indexing;
: iwDrei ds f
: rgwVar ds 8f
: ...
: lda 1,'6' ;Index * Datengröße = Offset <=> '3' * '2' = '6'
: lda 0,rgwVar(1)
: sta 0,iwDrei
This corresponds to the following code in Pascal or C
//Pascal:
var
iwDrei: SmallInt;
rgwVar: array[0..7] of SmallInt;
...
iwDrei:= rgVar[3];
//C:
short iwDrei;
short rgwVar[8]
...
iwDrei = rgwVar[3];
Saving a value in an array works in the same way.
Absolute addressing
However, there is also a second variant of addressing an element in an array. This is a bit more cumbersome because you don't use the relative offset - as above - but the absolute one. To do this, however, the address of the array must first be read out;
la 1,rgwVar ;die absolute Adresse des ersten Elementes des Arrays
add 1,'6'
lda 0,0(1) ;WICHTIG: Die erste 0 bezeichnet das Register 0, die zweite 0 nicht.
sta 0,iwDrei
The really practical thing about this method is the fact that you can dereference pointers to arbitrary variables . Although this is not intended by WinAli, reading and writing of values is quite possible.
Stack
As already mentioned, the WinAli assembler has 16 stacks with the designations 0
up to 15
. For stylistic reasons, however, only one should be used, since a "real" assembler also only has one stack. However, when implementing recursive methods, it is much easier 1
to use the stack to store the return addresses.
Others
You have to implement all other data structures that you need yourself, as there are no libraries etc. The best strategy for this is to write your own method (void*) malloc (char);
and its counterpart free (void *,char);
(in Pascal, for example, function malloc (byte): Pointer;
or procedure free (Pointer,byte);
) that manage a kind of memory in an array.
Objects
It would even be possible to create and release objects (in the object-oriented sense). A class TAuto could be noted as follows.
TAuto dc '4' ;Größe eines Objektes dieser Klasse
FcwSize dc '0'
FdwVelo dc '1'
FwColor dc '2'
FdwLast dc '3'
See also
- Bug
- Assembler
- Assembly language
- emulator
- Virtual machine
- Hungarian notation - the variables used here were named after this notation