1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154
|
%
% $Id: internals.tex,v 1.40 2009-11-04 14:32:21 sand Exp $
% vim:tabstop=8:shiftwidth=8:textwidth=78
%
% Copyright (C) 2002-2009 FAUmachine Team <info@faumachine.org>.
% This program is free software. You can redistribute it and/or modify it
% under the terms of the GNU General Public License, either version 2 of
% the License, or (at your option) any later version. See COPYING.
%
\documentclass[a4paper,10pt]{article}
\usepackage{listings}
\usepackage{pgf}
\parindent0pt
\parskip5pt
\title{FAUmachine Internals}
\author{FAUmachine Team
\\{\tt info@faumachine.org}}
\begin{document}
\maketitle
\tableofcontents
% ==================================================================== %
\section{Introduction}
% ==================================================================== %
This small documentation is written to give you an overview about
the internals of FAUmachine.
Due to the fact that FAUmachine is under development all the time
this documentation might be inaccurate\ldots
So, in doubt feel free to send an email to {\tt info@faumachine.org}
and ask questions! We'll be glad to help you!
% ==================================================================== %
\section{Overview}
% ==================================================================== %
FAUmachine is developed to be able to test how systems react on
hardware faults. To do this close to reality all components of the
system under test must be modeled very accurately. Likewise important
point is that the modeled system must consist of exactly the same
components (motherboard, CPU, memory, IDE disk, SCSI CD-ROM drive,
\ldots) as the real system. The system under test might even be a
workstation cluster with network cables, modem connections, serial
terminals and so on!
Therefore in FAUmachine it must be possible to build up very detailed
components and we must be able to configure the simulator with respect
to what components should be part of the simulation and what
components are not used. Components must be connected with other
components the very same way as in reality.
Standard modeling of hardware components and systems is done by
using a hardware description language. We don't use a language
like VHDL (or similar) here because of speed. Even the fastest VHDL
simulators are much too slow for our purpose. Using the FAUmachine
approach simulation is normally fast enough to use these machines in
real-time.
To be able to model each component independantly from each other
no component may have knowledge of another. They all communicate
using interconnects (''signals'') only.
So like using VHDL we have two very different types of objects:
\begin{itemize}
\item Signals
\item Components
\end{itemize}
Components are items like a CPU, a memory module, a north-bridge chip,
a motherboard, an IDE disk, or a network adapter. Items you can buy at
the local computer hardware dealer.
Signals are the interconnects that connect sockets of one component
with other sockets of other components. They describe the structure of
the virtual system.
% ==================================================================== %
\section{Examples}
% ==================================================================== %
Please note that the following examples look very simple. They're
used just to show you the internal software architecture of FAUmachine.
In FAUmachine much more sophisticated components and signals are used!
We're very confident that this approach
\begin{itemize}
\item leads to very clean code
\item makes sure that adding different types of components or signals
is easy
\item has {\bf no} influence on simulation speed!
\end{itemize}
% -------------------------------------------------------------------- %
\subsection{Simple Example}
% -------------------------------------------------------------------- %
Simple example (Sound generator and speaker connected using a cable):
\begin{center}
\pgfimage[width=7cm]{simple}
\end{center}
To make sure that no simulation module has direct access to any other
simulation module, no module function can be called directly.
They might to be called indirectly using signals only.
The only global functions of any simulation module are the {\tt create}
and {\tt destroy} functions. These are called during startup/end of
simulation. They even might be called while simulation is in progress.
So it's possible to add/remove hardware components during run-time.
Remarks:
\begin{itemize}
\item Pointers to objects are passed as ''{\tt void *}'' to make
sure that no component can access private elements of other
components. The other effect is that components can be
connected to any signal without having the signal need to
know anything about the component. Components are just
''objects'' of some kind.
\item Within the components the real pointer types are used. Therefore
some casts within the components are necessary.
\end{itemize}
\pagebreak
To model the small example system in FAUmachine-style we would write
the following code:
\lstset{language=C}
\begin{lstlisting}
struct system {
struct sig_boolean *sig_signal;
void *comp_U1;
void *comp_U2;
};
\end{lstlisting}
In the {\tt create} function of the system we create all necessary
signals and components:
\begin{lstlisting}
void *
system_create(const char *name)
{
struct system *s;
s = malloc(sizeof(*s));
/* Create signals. */
s->signal = sig_boolean_create("Signal");
/* Create components and pass generics and signals. */
s->comp_U1 = sound_generator_create("U1", 440, s->signal);
s->comp_U2 = speaker_create("U2", s->signal);
return s;
}
\end{lstlisting}
We pass the instance name of a component and its connected signals
when calling the component's {\tt create} function. The {\tt name}
parameter might be used for debugging for example. Not used here.
The created signals and components are destroyed again in system's
{\tt destroy} function:
\begin{lstlisting}
void *
system_destroy(void *_s)
{
struct system *s = s;
/* Destroy components. */
sound_generator_destroy(s->comp_U1);
speaker_destroy(s->comp_U2);
/* Destroy signals. */
sig_boolean_destroy(s->signal);
free(s);
}
\end{lstlisting}
This works hierarchically. Any component used may itself be
modeled this way.
\pagebreak
% -------------------------------------------------------------------- %
\subsection{Simple Components}
% -------------------------------------------------------------------- %
In our example we use some very simple components modeled using
the programming language ''C''. All code should go into a file named
''{\tt sound\_generator.c}'' and the prototypes of the {\tt create} and
{\tt destroy} functions should be contained by file
''{\tt sound\_generator.h}''.
\lstset{language=C}
\begin{lstlisting}
struct sound_generator {
unsigned int hz;
struct sig_boolean *port_out;
unsigned int state;
};
\end{lstlisting}
We define a function called periodically:
\begin{lstlisting}
static void
sound_generator_toggle(void *_s)
{
struct sound_generator *s = _s;
s->state ^= 1;
sig_boolean_set(s->port_out, s, s->state);
time_call_after(TIME_HZ / s->hz / 2, sound_generator_toggle, s);
}
\end{lstlisting}
The {\tt create} function might look like
\begin{lstlisting}
void *
sound_generator_create(char *name, int hz, struct sig_boolean *out)
{
struct sound_generator *s;
s = malloc(sizeof(*s));
s->hz = hz;
s->port_out = out;
s->state = 0;
time_call_after(TIME_HZ / s->hz / 2, sound_generator_toggle, s);
return s;
}
\end{lstlisting}
This is the {\tt destroy} function:
\begin{lstlisting}
void
sound_generator_destroy(void *_s)
{
struct sound_generator *s = _s;
free(s);
}
\end{lstlisting}
\pagebreak
The speaker component will be modeled similarly:
\lstset{language=C}
\begin{lstlisting}
struct speaker {
...
};
\end{lstlisting}
We define a callback function called whenever the input signal changes
its value:
\begin{lstlisting}
static void
speaker_set(void *_s, unsigned int val)
{
struct speaker *s = _s;
/* Output value 'val' to local host's sound system... */
}
\end{lstlisting}
The {\tt create} function might look like
\begin{lstlisting}
void *
speaker_create(const char *name, struct sig_boolean *in)
{
static const struct sig_boolean_funcs in_func = {
.set = speaker_set,
};
struct speaker *s;
s = malloc(sizeof(*s));
sig_boolean_connect_in(in, s, &in_func);
return s;
}
\end{lstlisting}
This is the {\tt destroy} function:
\begin{lstlisting}
void
speaker_destroy(void *_s)
{
struct sound_generator *s = _s;
free(s);
}
\end{lstlisting}
% -------------------------------------------------------------------- %
\subsection{Processes}
% -------------------------------------------------------------------- %
The simulation of the {\tt sound\_generator} component above is
event based. Another possiblity is to model it as a process:
\lstset{language=C}
\begin{lstlisting}
struct sound_generator {
struct process process;
unsigned int hz;
struct sig_boolean *port_out;
};
\end{lstlisting}
We define a function called periodically:
\begin{lstlisting}
static void
sound_generator_run(void *_s)
{
struct sound_generator *s = _s;
unsigned int state;
state = 0;
for (;;) {
sig_boolean_set(s->port_out, s, s->state);
sched_delay(TIME_HZ / s->hz / 2);
state ^= 1;
}
/*NOTREACHED*/
}
\end{lstlisting}
The {\tt create} function might look like
\begin{lstlisting}
void *
sound_generator_create(char *name, int hz, struct sig_boolean *out)
{
struct sound_generator *s;
s = malloc(sizeof(*s));
s->hz = hz;
s->port_out = out;
sched_process_init(&s->process, sound_generator_run, s);
return s;
}
\end{lstlisting}
The {\tt destroy} function is the same as in the example above.
These kind of ''processes'' are processes in the sense of co-routines.
They are started and they are executing until they call functions
like {\tt sched\_to\_scheduler} or {\tt sched\_delay}. In this
case they're stopped and other processes might run or events might
be triggered.
Such processes are much more efficient than functions triggered by
events, and components like CPUs or IDE disk/CDROM drives are much
easier to model using processes. In the example above you can see
that e.g. the variable {\tt state} becomes a standard local variable
and it is no longer a member of the {\tt sound\_generator} structure.
Access to such a variable is much faster as registers of the real
CPU might be used by the compiler.
\pagebreak
% -------------------------------------------------------------------- %
\subsection{Simple Signals}
% -------------------------------------------------------------------- %
In our tiny example we used only ''boolean'' signals. The code of these
objects look similar to the following:
The {\tt sig\_boolean\_create} and {\tt sig\_boolean\_destroy}
functions might be pretty simple:
\lstset{language=C}
\begin{lstlisting}
struct sig_boolean *
sig_boolean_create(const char *name)
{
struct sig_boolean *b;
b = malloc(sizeof(*b));
b->member_count = 0;
return b;
}
\end{lstlisting}
\begin{lstlisting}
void
sig_boolean_destroy(struct sig_boolean *b)
{
free(b);
}
\end{lstlisting}
The {\tt sig\_boolean\_connect\_in} function registers a callback
function and a callback parameter of a component:
\begin{lstlisting}
void
sig_boolean_connect_in(
struct sig_boolean *b,
void *s,
struct sig_boolean_funcs *f
)
{
b->member[b->member_count].s = s;
b->member[b->member_count].f = f;
b->member_count++;
}
\end{lstlisting}
The {\tt sig\_boolean\_set} function calls {\em all} registered
{\tt set} callback functions and passes the callback parameter
registered previously:
\begin{lstlisting}
void
sig_boolean_set(struct sig_boolean *b, void *s, unsigned int val)
{
unsigned int i;
for (i = 0; i < b->member_count; i++) {
(*b->member[i].f->set)(b->member[i].s, val);
}
}
\end{lstlisting}
% ==================================================================== %
\section{Shadow Components}
% ==================================================================== %
The {\tt speaker\_set} function of the previous example might be used
to output the created sound to the user using the real systems sound
system (ALSA, ESD, ARTS, \ldots).
In FAUmachine we use a little different approach. All components
might have a GUI and/or an audio shadow component.
\begin{center}
\pgfimage[width=5cm]{shadow}
\end{center}
These shadow components have the very same input/output signals like
the component itself. The shadows are created/destroyed together with
their corresponding non-shadow component. The only purpose of these
components is to interact with the real environment. They might
do audio input/output or they might interact with the graphical
user interface.
Using this approach we have components which do the simulation and
shadow components which do the user interaction. In this example we
have a speaker component that converts the electrical input into
accustical output. (This accustical output might be the input of
a simulated ''microphone'' component!) The output is taken by the
shadow component to be made audible by the user.
A similar example would be a push-button. The push-button component
itself just translates the mechanical ''signal'' into an electrical
one. The GUI shadow component will interact with the GUI and will
receive e.g. mouse clicks. Mouse events will be translated into
mechanical ''signal'' changes.
A LED component will generate an optical ''signal'' from the
electrical signal (just forwarding the boolean value). The GUI
shadow component of the LED will then take this value and
will draw the appropriate image using the GUI interface.
FAUmachine does it this way to separate the simulation and the
graphical/audio interaction with the user. The simulation component
will be the same whatever GUI or audio subsystem is used. The
simulation environment will select the correct shadow component
depending on the GUI or audio subsystem used.
% ==================================================================== %
\section{Complex Signals and Busses}
% ==================================================================== %
% -------------------------------------------------------------------- %
\subsection{Signals}
% -------------------------------------------------------------------- %
FAUmachine knows about a set of different simple signals. ''Simple''
means that these signals have exactly one component which drives the
value of the signal. One component calls the {\tt set} function of
the signal object. This {\tt set} call is distributed to all registered
callback functions.
These signals are:
\begin{itemize}
\item boolean
\item integer
\item string
\end{itemize}
Some signals need ''resolution''. This means more than one component
might call the {\tt set} function of the signal. E.g. in a computer
system we might have more than one PCI adapter driving the very same
IRQ line. So the signal has to remember which component drives which
value and has to calculate a ''resolved'' value based on this set
of values. It might e.g. build the ''OR'' of all boolean values.
The resolved value is then distributed to all connected components.
Signals of this kind are:
\begin{itemize}
\item boolean\_or
\item std\_logic
\end{itemize}
Signals of type {\tt std\_logic} are used to model ''wired-or'' or
''wired-and'' circuits using resistors.
% -------------------------------------------------------------------- %
\subsection{Busses}
% -------------------------------------------------------------------- %
A standard PCI bus consists of very many signals. To execute one single
bus transaction (like doing an I/O-read or memory-write) many signal
changes must happen.
This is not feasable if performance is important. So FAUmachine
introduces bus signals. Using these bus signals it is possible
to call callback functions in connected modules which do the whole
bus transaction in one call.
Example:
\lstset{language=C}
\begin{lstlisting}
sig_pci_bus_ior(bus, myself, port, byte_select, &val);
\end{lstlisting}
will do a whole I/O-read transaction on the PCI bus. It will call
all registered {\tt ior} functions of bus {\tt bus}. All connected
components check whether they are responsible to respond to I/O-reads
to the {\tt port} passed. The component in charge will use the
{\tt port} and {\tt byte\_select} parameters to do the correct access.
The return value is passed back using the address {\tt \&val} given by
the caller.
Similarly, we have for the host bus:
\begin{description}
\item [ior:] I/O read
\item [iow:] I/O write
\item [mr:] Memory read
\item [mw:] Memory write
\item [inta\_addr/inta\_data:] Interrupt acknowledge cycle
\end{description}
Similarly, we have for the PCI bus:
\begin{description}
\item [c0r:] Config space read (level 0)
\item [c0w:] Config space write (level 0)
\item [c1r:] Config space read (level 1)
\item [c1w:] Config space write (level 1)
\item [ior:] I/O read
\item [iow:] I/O write
\item [mr:] Memory read
\item [mw:] Memory write
\item [inta\_addr/inta\_data:] Interrupt acknowledge cycle
\end{description}
Similarly, we have for the ISA bus:
\begin{description}
\item [inb:] Input byte
\item [outb:] Output byte
\item [inw:] Input word
\item [outw:] Output word
\item [readb:] Read byte from memory
\item [writeb:] Write byte to memory
\item [readw:] Read word from memory
\item [writew:] Write word to memory
\item [ack:] Interrupt acknowledge cycle
\end{description}
Even the Shugart bus, SCSI bus, IDE bus, ethernet connections etc.
are modeled this way.
All FAUmachine signal sources are located in the {\tt lib} directory.
They all have a prefix of {\tt sig\_}.
% -------------------------------------------------------------------- %
\subsection{Bus Transaction Forwarding}
% -------------------------------------------------------------------- %
In reality the CPU starts bus transactions on the host bus. These go
to the north-bridge. The north-bridge decides whether to forward
these cycles to a memory module or to the PCI bus. The PCI bus
might forward this transaction to one of the PCI adapters or to the
south-bridge. The south-bridge might execute the cycles by itself
or it might forward it to the ISA bus. On the ISA bus the transaction
will be performed by any ISA adapter or by a component attached to
the bus directly (e.g. floppy controller, keyboard controller,
BIOS, ...).
As we can see transactions are forwarded, forwarded, \ldots
This will lead to an enormous overhead if implemented this way.
For this FAUmachine has introduced so called {\tt *\_info} and
{\tt *\_info\_flush} callback functions:
\begin{description}
\item[\tt info:] An {\tt info}-function might be used to get the
pointer to a callback function registered for a specific
I/O port. This pointer can be used once and again to call
I/O read and I/O write functions of a device by the CPU
directly regardless on which bus this device was registered.
\item[\tt info\_flush:] If any device changes its own I/O address
(e.g. during BIOS PCI configuration) it calls the
{\tt info\_flush} function of its own bus. The bus will
forward this call to all registered components of the bus.
This way components which have called {\tt info} functions
before and cached the pointers returned by these calls might
flush their cached infos.
\end{description}
This way any I/O read or I/O write call of the CPU will result in
{\em one} {\tt info} call cascade through all busses once (slow)
and {\em many} direct calls of the corresponding device function
(fast).
{\bf This is where FAUmachine's simulation speed results from!}
Example how a CPU might use an {\tt info} bus function:
\lstset{language=C}
\begin{lstlisting}
typedef uint32_t (*inl_func_t)(void *, uint16_t);
struct cpu {
...
inl_func_t inl_func[0x10000];
void *inl_state[0x10000];
...
};
\end{lstlisting}
\begin{lstlisting}
uint32_t
cpu_inl(struct cpu *cpu, uint16_t port)
{
if (! cpu->inl_func[port]) {
sig_host_bus_ior_info(cpu->host_bus, port,
&cpu->inl_func[port], &cpu->inl_state[port]);
if (! cpu->inl_func[port]) {
return 0;
}
}
return (*cpu->inl_func[port])(cpu->inl_state[port], port);
}
\end{lstlisting}
\begin{lstlisting}
static void
cpu_inl_info_flush(void *_cpu, uint16_t port)
{
struct cpu *cpu = _cpu;
cpu->inl_func[port] = NULL;
cpu->inl_state[port] = NULL;
}
\end{lstlisting}
% -------------------------------------------------------------------- %
\subsection{Memory Read/Write Bus Cycles}
% -------------------------------------------------------------------- %
If a CPU or any DMA device needs to read/write memory it calls the
{\tt memread}/{\tt memwrite} functions of the bus it is connected
with.
Even if cycle forwarding as described before is used simulation
speed will be very slow as memory read/write cycles occur
{\em very} often.
So in this case we use a similar approach like QEMU:
Busses offer a {\tt map} and an {\tt unmap} function. A CPU might
call the {\tt map} function of the bus to get a pointer to the
simulated memory region (might be part of a graphics adapter, too!).
This pointer can be used to read/write memory directly from within
the CPU or DMA device. If the mapping changes (e.g. during BIOS PCI
re-configuration or because of SMM switches) the devices or bridges
should call the bus' {\tt unmap} function. This way the change
request is broadcasted to all components which cached memory info
before.
% ==================================================================== %
\section{Components, Chips, Architectures}
% ==================================================================== %
% -------------------------------------------------------------------- %
\subsection{Components}
% -------------------------------------------------------------------- %
Components are the things you can buy at the local computer hardware
dealer in your city. Examples:
\begin{itemize}
\item motherboard (incl. chips and sockets)
\item CPU
\item chassis (incl. push buttons and LEDs)
\item power supply
\item IDE disk drive
\item IDE cdrom drive
\item SCSI disk drive
\item SCSI cdrom drive
\item VGA monitor
\item serial terminal
\item SCSI cable
\item serial cable
\item ...
\end{itemize}
Some of these components consist of sub-components. E.g. the
motherboard is formed by many chips, some sockets and many, many
signals connecting these parts. As some of these chips might be
used to build different motherboards, it makes sense to model them
separately.
So, generally each of the FAUmachine components consists of many
\begin{itemize}
\item chips/sockets/...
\item signals
\end{itemize}
How these low-level chips and sockets are modeled is described in
the next chapters. How to build higher level models will be shown in
the chapter thereafter.
% -------------------------------------------------------------------- %
\subsection{Sockets}
% -------------------------------------------------------------------- %
A PCI adapter is connected with the motherboard by about 50 signals.
Even if we use ''bus'' signals combining several of these discrete
signals we have to connect many signals to plug in a PCI adapter
into one PCI slot.
To ease plugging and to make sure pins (signals) are connected
correctly, FAUmachine introduces sockets. Sockets bundle a bunch of
signals forming {\em one} new signal.
\begin{center}
\pgfimage[height=5cm]{socket}
\end{center}
Sockets just forward signal changes from one side of the socket
to the other side. This requires one level of callback function
calls more. But if {\tt info} and {\tt info\_flush} functions
are used this doesn't matter.
% -------------------------------------------------------------------- %
\subsection{Chips and Architectures}
% -------------------------------------------------------------------- %
A south-bridge nowadays contains many functionality distributed over
many chips in former designs. In FAUmachine's chipset the south-bridge
(Intel~82371AB) has an IDE controller with two IDE channels, one USB
controller, two interrupt controllers, two DMA controllers, a real-time
clock, and a programmable interval timer bundled in one chip. In the
future even more functionality might go into the south-bridge chip.
Each of these parts of the chip is independant from the rest of the
chip. So in FAUmachine all these parts are modeled separately. This
might be done the way described above. Just use sub-components and
connect them using signals. The problem is -- speed. This approach
would introduce far too many levels of signals.
So each of these parts is modeled using the ''C'' programming language
and all parts are connected using function calls.
See the following example:
\begin{center}
\pgfimage[height=3cm]{architecture}
\end{center}
\lstset{language=C}
\begin{lstlisting}
struct chip {
/*
* The following includes will add the state info of
* components A and B to the state of the chip.
*/
#define STATE
#include "A.c"
#include "B.c"
#undef STATE
};
\end{lstlisting}
\pagebreak
\begin{lstlisting}
/*forward*/ static void B_I_set(struct chip *, unsigned int);
/* Function usable by component A to output value. */
static void
A_Out_set(struct chip *s, unsigned int val)
{
B_I_set(s, val);
}
/* Function usable by component B to output value. */
static void
B_O_set(struct chip *s, unsigned int val)
{
sig_boolean_set(s->port_x, s, val);
}
/* Include behaviour model of conponents A and B. */
#define BEHAVIOUR
#include "A.c"
#include "B.c"
#undef BEHAVIOUR
static void
chip_x_set(void *_s, unsigned int val)
{
struct chip *s = _s;
A_In_set(s, val);
}
void *
chip_create(const char *name, struct sig_boolean *port_x)
{
static const struct sig_boolean_funcs x_funcs = {
.set = chip_x_set,
};
struct chip *s;
s = malloc(sizeof(*s));
A_create(s);
B_create(s);
sig_boolean_connect_in(port_x, s, &x_funcs);
return s;
}
\end{lstlisting}
Procedures {\tt A\_Out\_set} and {\tt B\_O\_set} will be inlined by
the compiler. So they don't produce any simulation overhead!
Component parts included this way are called ''architectures'' in
FAUmachine. They have much in common with VHDL's architectures.
To be able to include such architectures more than once (south-bridge
needs two DMA and two interrupt controllers) the C preprocessor can
be used to rename function names. This avoids name clashes.
All FAUmachine architectures are located in the {\tt node-pc/simulator}
directory (for historical reasons).
% -------------------------------------------------------------------- %
\subsection{Structural Descriptions}
% -------------------------------------------------------------------- %
Like in VHDL it is possible create high-level components from lower
level ones. As an example chips and signals together might build up
a motherboard. In FAUmachine we can use components and signals like
in VHDL, too. Another option is to use schematic files produced by
the open-source tool {\tt gschem} which is part of GEDA tool suite.
This schematic files can be pre-processed by a FAUmachine tool called
{\tt faum-gnetlist} which generates a VHDL description of that file.
The VHDL files are used by the FAUmachine VHDL interpreter during
runtime.
This is what is drawn by the designer (Motherboard GA 686DLX):
\begin{center}
\pgfimage[height=9cm]{mb_ga_686dlx}
\end{center}
{\tt faum-gnetlist} produces the following VHDL files (excerpt):
\lstset{language=VHDL}
\begin{lstlisting}
ENTITY mb_ga_686dlx IS
GENERIC (
rtc_start : integer := -1
);
PORT (
power : INOUT power_board;
cpu0 : INOUT host_bus;
...
isa2 : INOUT isa_bus;
...
);
END mb_ga_686dlx;
\end{lstlisting}
\begin{lstlisting}
ARCHITECTURE structural OF mb_ga_686dlx IS
SIGNAL XplusX5V : boolean;
SIGNAL XplusX12V : boolean;
...
BEGIN
U42 : conn_isa
PORT MAP (
isa => isa2,
XplusX5V => XplusX5V,
...
);
...
U15 : chip_sst_29EE020
GENERIC MAP (
img => "bios.rom"
)
PORT MAP (
power => XplusX5V,
cs => tmp000042,
main => tmp000021
);
...
END structural;
\end{lstlisting}
It would be possible to generate C-code from the schematic file very
easily, too!
Sources generated this way are located in the {\tt node-pc/simulator}
directory (for historical reasons).
% -------------------------------------------------------------------- %
\subsection{Generated Sources}
% -------------------------------------------------------------------- %
We use a modified version of GEDA's {\tt tragesym} utility to build
{\tt *.sym} files from {\tt *.src} files. These {\tt *.sym} files
can be used in schematic designs (see previous section). For a
description of these files see documentation of the GEDA project.
Look at the following example (Interrupt Controller Intel 8259A
{\tt chip\_intel\_8259A.src}):
\begin{lstlisting}
[options]
wordswap=yes
rotate_labels=no
sort_labels=no
generate_pinseq=no
sym_width=1300
pinwidthvertical=300
pinwidthhorizontal=300
\end{lstlisting}
\begin{lstlisting}
[geda_attr]
version=20080904
name=8259A
device=chip_intel_8259A
refdes=U?
footprint=SO20
description=Interrupt Controller
documentation=http://
author=aures <aures@informatik.uni-erlangen.de>
numslots=0
\end{lstlisting}
\begin{lstlisting}
[pins]
#--------------------------------------------------------------------
#pinnr seq type style posit. net label type
#--------------------------------------------------------------------
spacer l
0 2 in line l reset# boolean
1 3 call line l cs cs
spacer l
11..4 4 call line l main isa_bus_main
spacer l
12..14 5 io line l cas integer
spacer l
spacer l
spacer l
28 1 in line b power boolean
spacer r
18 6 in line r ir0 boolean_or
19 7 in line r ir1 boolean_or
20 8 in line r ir2 boolean_or
21 9 in line r ir3 boolean_or
22 10 in line r ir4 boolean_or
23 11 in line r ir5 boolean_or
24 12 in line r ir6 boolean_or
25 13 in line r ir7 boolean_or
17 14 out line r int boolean_or
spacer r
16 15 in line r sp boolean
spacer r
\end{lstlisting}
Using the modified {\tt tragesym} utility ({\tt faum-tragesym}) we
will get the following graphical component
({\tt chip\_intel\_8259A.sym}; use {\tt gschem} for displaying):
\begin{center}
\pgfimage[height=5cm]{chip_intel_8259A}
\end{center}
This {\tt *.sym} file is parsed by {\tt faum-gnetlist}. This utility
will create a header file suitable for a model built in the C language
(file {\tt chip\_intel\_8259A.h}):
\lstset{language=C}
\begin{lstlisting}
#include "sig_boolean.h"
#include "sig_boolean_or.h"
#include "sig_cs.h"
#include "sig_integer.h"
#include "sig_isa_bus.h"
#include "sig_manage.h"
\end{lstlisting}
\begin{lstlisting}
extern void *
chip_intel_8259A_create(
const char *name,
struct sig_boolean *port_power,
struct sig_boolean *port_resetXhashX,
struct sig_cs *port_cs,
struct sig_isa_bus_main *port_main,
struct sig_integer *port_cas,
struct sig_boolean_or *port_ir0,
struct sig_boolean_or *port_ir1,
struct sig_boolean_or *port_ir2,
struct sig_boolean_or *port_ir3,
struct sig_boolean_or *port_ir4,
struct sig_boolean_or *port_ir5,
struct sig_boolean_or *port_ir6,
struct sig_boolean_or *port_ir7,
struct sig_boolean_or *port_int,
struct sig_boolean *port_sp
);
extern void
chip_intel_8259A_destroy(void *_cpssp);
\end{lstlisting}
In the same step C function stubs are produced
(file {\tt chip\_intel\_8259A.c.tmp}; excerpt):
\begin{lstlisting}
#include <...>
#include "chip_intel_8259A.h"
struct cpssp {
struct sig_boolean_or *port_int;
unsigned int state_power;
unsigned int state_resetXhashX;
...
};
\end{lstlisting}
\begin{lstlisting}
void *
chip_intel_8259A_create(
const char *name,
struct sig_boolean *port_power,
struct sig_boolean *port_resetXhashX,
struct sig_cs *port_cs,
struct sig_isa_bus_main *port_main,
struct sig_integer *port_cas,
struct sig_boolean_or *port_ir0,
struct sig_boolean_or *port_ir1,
struct sig_boolean_or *port_ir2,
struct sig_boolean_or *port_ir3,
struct sig_boolean_or *port_ir4,
struct sig_boolean_or *port_ir5,
struct sig_boolean_or *port_ir6,
struct sig_boolean_or *port_ir7,
struct sig_boolean_or *port_int,
struct sig_boolean *port_sp
)
{
static const struct sig_boolean_funcs power_funcs = {
/* FIXME */
};
static const struct sig_boolean_funcs resetXhashX_funcs = {
/* FIXME */
};
...
struct cpssp *cpssp;
cpssp = malloc(sizeof(*cpssp));
assert(cpssp);
cpssp->state_power = 0;
sig_boolean_connect_in(port_power, cpssp, &power_funcs);
cpssp->state_resetXhashX = 0;
sig_boolean_connect_in(port_resetXhashX, cpssp, &resetXhashX_funcs);
...
return cpssp;
}
\end{lstlisting}
\begin{lstlisting}
void
chip_intel_8259A_destroy(void *_cpssp)
{
struct cpssp *cpssp = _cpssp;
/* FIXME */
free(cpssp);
}
\end{lstlisting}
Only functions modeling the behavior of the component have to be
inserted. The structure of the sources is already prepared.
{\em All} FAUmachine components are generated this way!
Their sources are located in the {\tt node-pc/simulator} directory
(for historical reasons).
Creating components this way makes sure C models and structural
descriptions using these models will fit.
% ==================================================================== %
\section{Simulation Engine}
% ==================================================================== %
FAUmachine's simulation engine (sources are located in
{\tt lib/glue-main.[ch]}) has to
\begin{itemize}
\item call {\tt *\_create} functions on startup to configure system.
\end{itemize}
While simulation is in progress the following tasks have to be
repeated again and again:
\begin{itemize}
\item stop simulation if {\tt sim\_exit} function was called
\item call I/O callbacks if {\tt SIGIO} is received
\item synchronize real-time clock and simulation clock
\item call event-based callback functions at correct times
\item execute processes if nothing else has to be done.
\end{itemize}
After {\tt sim\_exit} has been called the simulation engine has to
\begin{itemize}
\item call {\tt *\_destroy} functions.
\end{itemize}
Execution of processes might be done using multiple real threads.
This way it is possible to run multiple CPUs, CDROM drives etc.
all at the same time.
% ==================================================================== %
\section{Conclusion}
% ==================================================================== %
FAUmachine has a very clean way to model huge virtual machines.
\end{document}
|