Re: [quirks-uvm-devel] One more program
Status: Pre-Alpha
Brought to you by:
teodor
|
From: Sergei L. <se...@mo...> - 2002-04-01 21:03:04
|
Hello.
> I got the flex, bison and libraries.
OK. Let me know if you get any troubles with
adding it to the MSVC++ build process.
> I am compiling the *.ua with ua.exe. Is this correct?
Exactly. `ua' stays for "UVM assembler". The `au' tool is a
disassembler. You can view *.ru files with it in the original form.
About the first (CtoF) program. It mainly correct. But I haven't
catch some error in your previous letter (and you have repeated it).
When we define auMul (a b c) it means:
c = a * b;
And when we define auSum (a b c) it means:
c = a + b;
When we define auMul (a/out B/in C/in) think like it is equation with
unknown a:
C = a * B, i.e.:
a = C / B.
So, the positions of operands in your divisions and subtractions should
be changed (We have got 10/(18 * C) instead of 18 * C / 10).
In your second example I've found some errors (besides of described
above) on topics I haven't good explained yet.
Each AU (au module: auSum, auMul) can be (for each procedure) in the
single instance. I.e., we can't have two auMul in the same procedure
(but auMul, au2Mul, au3Mul). Think about AUs as real electronic
devices (procedure scoped). When we say: "map auMul[2] on some
register" that means the first multiplier, when we say "map au2Mul[2]
on another register" that means the second one. But we cant say "map
auMul[2] on the register A and on the register B" (only one real
register should be in the mapping relation). Let's I explain the
advantage of such approach.
Let's see on expression A * B * C. Now we oblige to use intermediate
register to store value of A * B i.e.:
-- lv[0] = A, lv[1] = B, lv[2] = C, lv[3] = (B * C), fp[0] - the result
type ~Mul is <int32/in int32/in int32/out stu>; -- (you can use
-- aliases for types).
declare map
auMul is ~Mul;
au2Mul is ~Mul;
map is
(auMul[0], lv[0]) (auMul[1], lv[1]) (auMul[2], lv[3])
(au2Mul[0], lv[3]) (au2Mul[1], lv[2]) (auMul[2], fp[0])
end map;
But it is not our goal. It is temporary stage in movement to more
power mapping:
declare map
auMul is ~Mul;
au2Mul is ~Mul;
map is
(auMul[0], lv[0]) (auMul[1], lv[1])
(auMul[2], au2Mul[0]) -- attach 2 output of auMul to 0 input of au2Mul
(au2Mul[1], lv[2]) (auMul[2], fp[0])
end map;
We will be able use it if we will accept the principle of AU
(Arithmetic Unit) as a device, not AU as a function (or
predicate). And with the second variant we get new combined device. I
try generate code by patterns which include several devices in such
connections. In many cases we can do more accurate register
allocation. So, let's think about temporary registers as about
temporary solution.
The second moment is the use of act. I already wrote:
> (When you invoke `act' the according map calls all defined AUs from
> top to bottom. It is not on principle to which AU from this map you
> point with act. Ideally we need only one map and an algorithm for
> finding AUs which involved in operation ...
Well, I mean this fragment from your code:
> exit @Loop when not lv[0];
> * auMul;
> * auSum;
> lv[5] <- lv[2];
We don't need two acts. The *auMul will invoke all AUs declared in
the same map to work. They will perform their action according to
definition order:
> declare map
> -- Get access to two registers of
> incrementer/decrementer
> auInc is <int32/in int32/out stu>;
>
> -- Three ports of multiplier
> auMul is <int32/in int32/in int32/out stu>;
> au2Mul is <int32/out int32/in int32/in stu>;
> auSum is <int32/in int32/in int32/out
> stu>;
>
> map is
i.e.: auInc, then auMul, then au2Mul, then auSum. In this order each
module will perform its action. So, the map is monolithic entity. You
can't call separate modules from it. You can refer to all of its
modules by pointing any of them, i.e:
*auMul;
or
*auSum;
All variants are equal.
OK. Some trifles at the end.
1. What is auCmp with to channels (in out) ? If it is new module you enter
please comment what it does.
2. `endif' should be `end if'.
3. Why you doesn't use `else' parts? It is faster.
P.S,
Now I prepare a general schema of the assembler backend we will implement.
I will finish it in a few days.
But you could start working in this area (if you wish). The task is:
Get a command reference book for any of these processors: Intel 386,
486 or Pentium. Write down all registers besides of those which is
used for special operations like protected mode control etc.
Try find several groups (they can be intersected). For example:
- registers which can be used as any argument in big part of arithmetic
operation (general purpose);
- accumulator (some operations can work only with it);
- registers for counter in rotation operations;
...
The main rule is: all register in one groups are fully replaceable in
operations. I can use any of these registers in some concrete
place. So, this classification should be base on a place where
particular set (group) of registers can be use (example of such
"place": the first operand of a `mul' operation).
Give a simple name (identifier) to each group.
We will use such information as a part of description for a target
processor.
--
Thanks,
Sergei
|