...to two assembler-programs, written in NASM-dialect and used to translate NASM-dialect or a new dialect, which
I describe at the end of this text.
The program, which translates NASM-dialect is called "ASMn" in the following text and is limited in some respect,
as it needs to work only under ASMOS, assembling code only for programs running under ASMOS. It is made to
assemble sourcecode with very few modifications, which is written in NASM-dialect.
If the source-compatibility is not needed, use the derivate ASMat, described at the end of this document.
There are a lot of expressions, which will be translated by NASM, but not by ASMn. And there are a few things, which
can be done in ASMn, but not in NASM...
A detailed synopsis you can find in the file "TSOURCE", which can be used as test source for assembling too.
...is a single standalone-program, assembling in a single run.
The output of this program is a listing and a binary, which can be made running using the normal way in the menu-mode
of ASMOS. The source can be made in edit-mode 0 or 1. The error-output is part of the listing. The line will be black-painted
starting exactly at that expression or a part of an expression, which wasn't recognized by ASMn. Normally listing goes on after
an error. The only exceptions are a double defined label, a negative adress for filling ("TIMES") or a too long adress in
"loop"-commands.
The preprocessor stage is as simple as can be - it does not exist. As in ASMOS cut&paste is very easily done, while the copy
can contain every value in a byte, including of files, data or macros in a preprocessor stage isn't needed.
As You do not need real mode code for any other purpose than to write a bootloader (which is done already...), ASMn
does nothing depending on real mode or V86 (implicite "USE 32").
As the destination of code is only ASMOS, there are no command-line-options or linker-headers available (or needed).
After Initialization ASMn is a point in the menu F9.
The ASMn-assembler understands very few expressions. These few are limited to only a few purposes in definitions
(You can't do any arithmetics except simple adress-arithmetic!):
: + * -
A Label can be written with postfix ":" or without it as in NASM. And a command can follow in the same line.
ASMn starts assembling in a line searching for ";" first and skipping whitespace (20h and 00h). Besides these
special signs every other sign is treated to be a mnemomic or the expression "ALIGN 4" (a "standard makro" in NASM).
Similar to NASM and other Assemblers, ASMn finally searches for labels.
If "ALIGN 4" or "align 4 " (or any mix of upper and lower cases of the signs...) is found, ASMn fills with NOPs (=90h).
Behind a label defining a value you can use only:
DT, DQ, DD, DW, DB (in lower or upper case to define the type)
or one of the two quasi-ops "*" (similar "TIMES") or "I" (similar "INCBIN").
Any other letters will be treated as a command!
If the type is DB or db ,then instead of numbers 'text...' or "text..." can follow. And similar to NASM-style
a name of a label representing an adress can follow, if the type is DD or dd.
Onlc then, when the type is DD, DQ or DT, there is a minus "-" allowed as präfix of the digits. But while the type DD
can be used to define integer constants too, the types DQ and DT are oly useable to define floating point format in
the familiar way. Look for more details about FPU and floating point format at the end of this text!
As "TIMES" and "INCBIN" are "types" in ASMn, there is no need for the expression "$" or "$$". If the type of an expression
behind a label is "*", AMSn does filling similar to NASM. In this case there has to follow a count for repetition.
This can be a single number like this:
Different to NASM, ASMn does not translate code, mixed for real and protected mode. But in a few cases (bootloadercode)
mixed code is needed.
As an assembler translation program for such mixed codes would be too complicated, I made two programs, each running faster
and using less memory space for the task. Mixing code is easily done under ASMOS in edit-mode 0, because binary copies
can be made and pasted. Mixing needs not to be done by the translation program!
Look for the details at the original file in the sources!
This derivate is to prefer, if you do not need compatibility with NASM and write and use the source in ASMOS.
ASMat is made to ease writing of programs and to speed up assembling.
In ASMat there is a very simple rule used to define the three dimensions of a sourcecode: comments, commands and labels.
The rule is:
To program the FPU and use the floating point format is special and not to do knowing only about the mnemonics. Because of this,
I describe here the most important details.
Since the Intel-CPU type i486, the FPU is integrated on the same chip as the CPU. It can be programmed using opcode, but contains
its own registers and can calculate parallel to the CPU. For the purpose of synchronisation and error-handling, the FPU is
capable of requesting interrupts. As the FPU once was made as a separate circuit in an own case, there is an own reset and
initialisation to do - different to the ALU.
The original FPU contains eight 80-bit-data-registers, organized as stack and internally adressed by a FPU-stackpointer, which
is readable in bits 11,12,13 of the FPU-status-register and "grows" downward, pointing to the lowest defined element (=TOP) and
stepping with predecrement.
In newer FPUs, there are new data-registers and commands available, but these ones are not recognized by may translation programs.
Besides the stacked data-registers, a control- and a status-register are part of the FPU, which can be accessed similar to those
in the CPU by using special commands.
A very important part of the construction is a format of the operands, which allows representation of point, mantisse (sometimes
called "significant") and exponent. This format is normalized as "IEEE 754". While significant and exponent can be handled in three
different sizes, the point can "flow".
This means, that there is no binary representation of the point similar to the sign-bit. Instead of wasting a bit, the point
is defined by the exponent, which is a special format too to make a signbit for the exponent superfluous. Instead of wasting
a bit a "bias" is added to the real value of the exponent. Up to the value of the bias, exponents are negative.
Initialising and control of the FPU is done using three registers:
the CPU-control-register cr0 controls the FPU too and contains most important settings
the control-register of the FPU can only be accessed using the commands ;fldcw;, ;fstcw; and ;finit;
the status-register of the FPU can only be accessed using the commands ;fstsw; and ;fnstsw;
Of course the status-register is needed at runtime, which contains in bits 0-5 the FPU-flags linked to interrupt requests, if not masked.
These bits show "exceptions". The interrupt-handler has to delete the according flag in the FPU, because this is not done automatically!
In the bits 8,10,14 the flags are set, which are comparable to those in the status-register of the CPU .
Finally the bits 11,12,13 show the actual adress of the Stackpointer in the FPU.
Operands can be transfered from and to memory, but nor registers in the CPU. The right place is the FPU-stack.
While the adress of the stackpointer is an absolute registeradress, the adress allowed in commands is relative to TOP.
Then the name of the registers is in the most assembler dialects "st" and a postfix 0...7. As this postfix adresses
relative to the stackpointer, the actually adressed register has always the name "st0" and is =TOP.
As you can increment or decrement the stackpointer, you can move the relation and make the same register to be "st1" or "st7"
and move TOP. Thus the baseadress =TOP of the stack can rotate through the physical registers.
The FPU uses only operands in the floating point format for extended precision. Every other format for single or double
precision is internally changed!
In every case there is a limited precision of significants and a limited range of numbers because of a limited exponent.
The structure of the three types of "precision" available in the FPU seems to be simple, but the change of decimal digits
to dual digits isn't. The new algorithm used in ASMn and ASMat produces more precision than the known ones in "higher"
languages. I use for some steps 128 bit precision. This causes a difference in the least bits between my translations and
those of other programs.
If You are familiar with the use of decimal exponents, You saw already points float, but certainly without the flowerish
expression for that phenomena...
You know the decimal exponents as 10=10exp2, 100=10exp2 a.s.o... and used this as a multiplier for decimal digits.
At the left hand side of "exp" I wrote the significant, at the right hand side the exponent.
Then you can write the following equation: 123*10exp1=12.3*10exp2=1.23*10exp3=0.123*10exp4.....and see the point
float from the right hand side to the left hand side.
If the numbers are represented as dual digits, then the point flows in the same way - more useable in a transistor circuit
between transistors, which output 0V representing dual 0 or 5V representing dual 1.
But now the floating point does not make a multiplication or division by factor 10, as in the decimal system, but only by
factor 2 . But in both systems this is incrementing oder decrementing the exponent.
Now You can see, that the choice of an exponent is the choice, where to put the point in the significant, if the amount of
bits for the significant is limited as in the FPU. But You need not worry about the right definition of the exponent during
calculation, because the FPU can make the point floating! How to do this, is normalized in "IEEE 754".
By this rule every number represented by dual digits, is treated to be a dual fraction and a leading 1 before the point.
Thus a decimal 1234 is a 1.234*10exp3
As the binary representation of the number has to use the power of 2 instead of 10, the multiplicator in this example
has to be changed: (1,234*5exp3)*2exp3
This change allows to keep the exponent unchanged, but the mantissa has to be multiplied by a power of 5
While the exponent has to be changed to dual digit format too, the multiplicator "2exp" is part of the construction
of the FPU.
As every decimal definition of constants contains a power of 5, which is a divisor, if the exponent is negative, most of
the changed dual digits should be made of more bits than available to be exact. This is the reason, why you normally can't
exactly define the value, which is finally used in the FPU !
Because of this I added the feature to ASMat to define floating point values using hexadecimal digits.
As the MSB of the significant is exactly defined by the exponent, there is a 1, which needs not to fill a bit. Thus the
significant can be doubled by making this 1 implicite. This is, what is called "normalized". The normalized floating
point format is not internally used and not externally to define, if extended precision is switched on!
If single or double precision is on, the FPU outputs results "normalized" too! Only then, when a very small number with
exponent=0 is to define, the FPU makes "denormalized" results and requests for interrupt 16 (if not masked).
The problem with a sign for the exponent is solved in another way. This sign says, if it is a minus, that a significant
isn't multiplied by an implicite 2 (the base of the dual system) with given exponent, but divided by this term. There is
no sign-bit wasted too, but a "bias" is added to the original exponent of the operand. The bias is different due to
precision. The decimal values are: single precision bias=127, double precision bias=1023, extended precision bias=16383.
There are some more values available in the binary exponent for alien results as null, infinite and others...
Besides those alien values there are cut off bits and rounding, which make results not really exact. And as the amount
of bits is limited, "infinite" values can be in fact exact values, which are too big or too small, but not really infinite.
The FPU allows corrections of calculations requesting an interrupt 16 in those cases.
If there is any confusion about expressions, look at the file "TSOURCE", where a synopsis of the commands is written with
comments.
p.p.
This version of the file is shortened - read the file again after unzipping the source...