OpenCores
URL https://opencores.org/ocsvn/ion/ion/trunk

Subversion Repositories ion

[/] [ion/] [trunk/] [doc/] [src/] [tex/] [simulation.tex] - Blame information for rev 220

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 210 ja_rd
\chapter{Logic Simulation}
2
\label{logic_simulation}
3
 
4
    The project has been simulated using Modelsim 6.3g. The test bench
5
    uses some features not present in earlier versions (namely library Signal
6
    Spy) so if you use some other simulator or some earlier version of Modelsim,
7
    see section on Modelsim dependencies (\ref{modelsim_dependencies}) below.\\
8
 
9
    In short, the simulation test bench is meant to run any of the code samples
10
    provided in directory /src, under a controlled environment, while logging
11
    the cpu state to a text log file.\\
12
 
13
    This log file can then be compared to a log file generated by a software
14
    simulator for the same code sample (see section 5.1). The software
15
    simulator is the 'golden model' against which the cpu is tested, so any
16
    difference between both log files means trouble.\\
17
 
18
    This method is far easier than building a fully automated test bench, and
19
    much more convenient and reliable than a visual inspection of the simulation
20
    state.\\
21
 
22
    In addition to the main log file, there is a console log file to which all
23
    data written to the UART is logged (see section~\ref{uart_logging}).\\
24
 
25
    There are a few simulation test bench templates in the /src directory, which
26
    are used by all the code samples.\\
27
    The only ones actually used are '/src/code\_rom\_template.vhdl' and
28
    '/src/sim\_params\_template.vhdl'. The others
29
    are remnants of previous versions that will be removed ASAP.\\
30
 
31
    The template in file '/src/code\_rom\_template.vhdl' is filled with object
32
    code meant to be run from internal FPGA BRAM. This is how we load bootstrap
33
    code into our FPGA. The resulting file is '/vhdl/demo/code\_rom\_pkg.vhdl'
34
    and is used by both the simulation test bench and the synthesizable MCU.\\
35
 
36
    The template in file '/src/sim\_params\_template.vhdl' is filled with
37
    simulation parameters (such as the simulation length, etc.) and the resulting
38
    file is written as '/vhdl/tb/sim\_params\_pkg.vhdl'. This file is only used
39
    by the simulation test bench.
40
 
41
    All of this template filling is done by a python script (/src/bin2hdl.py)
42
    which is invoked from the makefiles and explained in section xxx.\\
43
 
44
    Note that all code samples share the same vhdl files: you need to run the
45
    makefile target 'sim' for the sample you want to simulate; that will
46
    overwrite the two files mentioned above. So there's no vhdl file that is
47
    specific to a particular code sample.\\
48
 
49
    The actual test bench entity is at '/vhdl/tb/mips\_tb.vhdl' and is shared
50
    by all the code samples.\\
51
 
52
    While the test benches and sample code are good enough to catch MOST errors
53
    in the full system (i.e. cache included) they don't help with diagnostic;
54
    once you know there's an error, and the approximate address where it's
55
    triggered (approximate because of the cache) you have to dig into the
56
    simulation waveforms to find it. It's easier than it seems.\\
57
 
58
\section{Running the Simulation}
59
\label{running_the_simulation}
60
 
61
    A simulation script can be found at '/sim/mips\_tb.do'. This script will
62
    simulate the test bench entity in file '/vhdl/tb/mips\_tb.vhdl'.\\
63
 
64
    All the code samples are run with the same script.\\
65
 
66
    The test bench files mentioned in the previous section are automatically
67
    generated for each of the sample programs. This is automatically done by the
68
    sample code makefile,
69
    assuming you have a MIPS cross-toolchain in your computer (see section~\ref{code_samples}).\\
70
 
71
    For convenience, a pre-generated mips\_tb.vhdl is included so you can launch
72
    a simulation without having to install toolchains, etc. The code is that
73
    of the 'hello world' sample.\\
74
 
75
    I guess that if you are interested in this sort of stuff then you probably
76
    know more about Modelsim than I do. Yet, here's a step-by-step guide to
77
    simulating the 'hello world' sample:
78
 
79
\begin{enumerate}
80
    \item Run 'make hello\_sim' from directory '/src/hello'.
81
        This will compile the program sources, build the necessary binary object
82
        files and then create the two package files mentioned above.\\
83
        Read the makefile and comments in the python script '/src/bin2hdl.py'
84
        for details.\\
85
 
86
        ALTERNATIVELY, if you don't have a toolchain you can just skip this
87
        step and use the default vhdl files provided, which are those of the
88
        'hello world' sample.\\
89
 
90
    \item Within Modelsim, change directory to /syn. Modelsim will create its
91
        stuff in this directory. This includes the
92
        log file, which by default will be '/syn/hw\_sim\_log.txt', and the
93
        console log file '/syn/hw\_sim\_console.log'.\\
94
        (You could use any other directory, this is just a convenient place to
95
        put modelsim data out of the way. Just remember where the log files
96
        are.).
97
 
98
    \item Run script '/sim/mips\_tb.do' (menu tools-\textgreater tcl-\textgreater execute macro)
99
        The simulation will run to completion and print a message in Modelsim's
100
        transcript window when it's done. You can open the console log file
101
        to see the program output, in this case the 'Hello world' message.\\
102
 
103
\end{enumerate}
104
 
105
    The test bench terminates the simulation when:
106
 
107
\begin{enumerate}
108
 
109
    \item It detects two consecutive code fetches from the same address.
110
    \item The simulation timeout is reached.
111
 
112
\end{enumerate}
113
 
114
    Condition 1 is meant to detect single-instruction loops such as those
115
    commonly found after the invocation of the main() function in a C program.
116
    This is a convenient way for the software to signal its termination.\\
117
 
118
    The timeout is one of the simulation parameters which is defined in
119
    the makefiles. It is arbitrarily fixed for each sample by trial and error
120
    so that the program has time to execute. Change them if necessary.\\
121
 
122
\section{Simulation File Logging}
123
\label{sim_logging}
124
 
125
    The simulation test bench will log any of the following events:
126
 
127
    \begin{itemize}
128
    \item Changes in the register bank.
129
    \item Changes in registers HI and LO (implemented even if mul/div is not).
130
    \item Changes in registers EPC and SR.
131
    \item Data loads (any resulting register change is logged separately).
132
    \item Data stores.
133
    \end{itemize}
134
 
135
    Note that changes in other internal registers, including PC, are not logged.
136
    This means that for example a long chain of NOPs, or MOVEs that don't change
137
    register values, will not be seen in the log file. This is on purpose.\\
138
 
139
    Events are logged with the address of the instruction that triggered
140
    the change. This holds true even for load instructions.\\
141
    Early versions of the project logged the address of the
142
    preceding instruction -- it was confusing and I have fixed it.\\
143
 
144
    The simulation log file is stored by default in modelsim's working directory
145
    (see above). I don't provide any automated script to do the comparison, you
146
    should use whatever diff tool you like best.\\
147
 
148
\section{Log File Format}
149
\label{log_file_format}
150
 
151
    There is a text line for each of the following events:
152
 
153
    \begin{itemize}
154
    \item Register change
155
 
156
        "(pc) [reg\_num]=value"\\
157
 
158
        Where:
159
 
160
        \begin{tabular}{ l l }
161
            pc       & =\textgreater PC value (8-digit hex)\\
162
            reg\_num & =\textgreater Register index (2-digit hex), or any of {LO,HI,EP}\\
163
            value    & =\textgreater New register value (8-digit hex)\\
164
        \end{tabular}\\
165
 
166
 
167
    \item Write cycle (store)
168
 
169
        "(pc) [address] |mask|=value WR"\\
170
 
171
        Where:
172
 
173
        \begin{tabular}{ l l }
174
        pc      & =\textgreater PC value (8-digit hex)\\
175
        address & =\textgreater Write address\\
176
        mask    & =\textgreater Byte-enable mask (2-digit hex)\\
177
        value   & =\textgreater Write data\\
178
        \end{tabular}\\
179
 
180
        The PC value is the address of the instruction that caused the logged
181
        change, NOT the actual value of the PC at the time of the change.
182
        This is so to make the hardware logger's life easier -- the SW simulator
183
        and the real HW don't work exactly the same when the cache starts
184
        stalling the cpu (which the SW does not simulate) and the best reference
185
        point for all instructions is their own adddress.
186
 
187
        The mask will have a '1' at bits 3..0 for each byte write-enabled. MSB
188
        is bit 3, LSB is bit 0. Note that the data is big endian, so the MSB
189
        is actually the LOWER address. The upper nibble of the mask is always 0.
190
 
191
        The value will match the behavior of the ion cpu; the significant
192
        byte(s) will have the actual write data and the other bytes will not
193
        be relevant but will behave exactly as the real hardware (so that the
194
        logs are directly comparable).
195
 
196
        The WR at the end of the line is for visual reference only.
197
 
198
    \item Read cycle (load)
199
 
200
        "(pc) [address] \textless ** \textgreater =value RD"\\
201
 
202
        Where:
203
 
204
        \begin{tabular}{ l l }
205
        pc      & =\textgreater PC value (8-digit hex)\\
206
        address & =\textgreater Read address\\
207
        \textless ** \textgreater    & =\textgreater Padding (ignore)\\
208
        value   & =\textgreater Read data\\
209
        \end{tabular}\\
210
 
211
        Note that in the real machine, the data is read into the cpu one cycle
212
        after the address bus is output (because the memory is synchronous) so
213
        that the full read cycle spans 2 clock cycles (when proper interlocking
214
        is implemented, the load will overlap the next instruction; right now
215
        it just stalls the pipeline for 1 cycle). This is simplified in the log
216
        files for readability.
217
 
218
        Note that the size of the read (LH/LB/LW) instruction is not recorded:
219
        the CPU always reads 32-bit words.
220
 
221
        The RD at the end of the line is for visual reference only.
222
 
223
    \end{itemize}
224
 
225
 
226
    For example, these are lines 1153-1162 of the simulation log for the
227
    default 'hello world' test program:
228
 
229
                \begin{verbatim}
230
                ...
231
                (BFC009AC) [05]=20000000
232
                (BFC009B0) [20000020] <**>=00000003 RD
233
                (BFC009B0) [03]=00000003
234
                (BFC009B8) [03]=00000002
235
                (BFC009C0) [03]=20000000
236
                (BFC009C4) [20000000] |0F|=00000070 WR
237
                (BFC00E74) [12]=00000004
238
                (BFC00E78) [10]=BFC01048
239
                (BFC00E7C) [BFC01048] <**>=00000069 RD
240
                (BFC00E7C) [05]=00000069
241
                ...
242
                \end{verbatim}\\
243
 
244
    (NOTE: this example taken from revision 176, yours may vary)\\
245
 
246
    The read cycle at pc=0xbfc009b0 modifies register 0x03; that's why there
247
    are two lines with the same pc value.\\
248
 
249
    The code that produced that log is this (from hello.lst):
250
 
251
                \begin{verbatim}
252
                ...
253
                bfc009ac:    3c052000     lui   a1,0x2000
254
                bfc009b0:    8ca30020     lw    v1,32(a1)
255
                bfc009b4:    00000000     nop
256
                bfc009b8:    30630002     andi  v1,v1,0x2
257
                bfc009bc:    1060fffc     beqz  v1,0xbfc009b0
258
                bfc009c0:    3c032000     lui   v1,0x2000
259
                bfc009c4:    ac620000     sw    v0,0(v1)
260
                bfc009c8:    03e00008     jr    ra
261
                bfc009cc:    00000000     nop
262
                ...
263
                bfc00e74:    26520001     addiu  s2,s2,1
264
                bfc00e78:    26100001     addiu  s0,s0,1
265
                bfc00e7c:    92050000     lbu    a1,0(s0)
266
                bfc00e80:    00000000     nop
267
                ...
268
                \end{verbatim}\\
269
 
270
    (Remember the register numbers: \$v0=0x02, \$v1=0x03, \$a1=0x05, \$s0=0x10,
271
    \$s2=0x12)\\
272
 
273
    Note that, unlike previous versions of this project, all changes are logged
274
    with the address of the instruction that caused them.\\
275
 
276
    The log file format is hardcoded into vhdl package mips\_sim\_pkg
277
    and the software simulator C source that implement it. It will
278
    be probably modified as the project moves on so it is best if you verify
279
    all of this yourself with the project version you intend to use before
280
    using this information.\\
281
 
282
    Note that the software simulation log and the modelsim log need not be the
283
    same size even if both CPUs behave identically; the one that spans a longer
284
    simulated time will be longer.\\
285
    The point is that both need to be identical up to the last line of the
286
    shortest file.\\
287
 
288
\section{Console Output Logging}
289
\label{uart_logging}
290
 
291
    Every byte written to the UART TX register is logged (in ascii) to a text
292
    file which by default is '/syn/hw\_sim\_console.log'. Apart from the
293
    automatic insertion of a CR after every LF, the data is logged verbatim.\\
294
 
295
    Though the UART is included in the test bench, the actual UART operation is
296
    bypassed: The test bench forces the 'tx ready' high so that the CPU never has
297
    to wait for a character to be transmitted. This is a simplification that
298
    saves me the trouble to do a cycle-accurate simulation of the UART in the
299
    software simulator.\\
300
 
301
    The UART input is not simulated at all, for simplicity. So, for example, the
302
    Adventure sample, which does read the console input, can't be properly
303
    simulated past the first console input -- there is plenty of code to
304
    simulate before that so this is no problem for the moment.\\
305
 
306
 
307
\section{Use of Modelsim Features}
308
\label{modelsim_dependencies}
309
 
310
    Apart from the format of the simulation scripts, which would be easy to port
311
    to any other simulation tool, the simulation test bench uses a feature of
312
    Modelsim 6.3 that is not even present in earlier versions -- SignalSpy.\\
313
 
314
    The test bench uses SignalSpy to examine internal cpu signals from the top
315
    entity, including the whole register bank. There is no other way to examine
316
    those signals in vhdl, unless you want to add them to the module interface.\\
317
 
318
    The test bench needs to access those signals in order to detect changes in
319
    the internal cpu state that should be logged. That is, it really needs to
320
    look at those signals if it is to be of any use.\\
321
 
322
    If you are using any other simulation tool, look for an alternative method
323
    to get those internal signals or just add them to the core interface. I
324
    would suggest adding a debug port of type record to mips\_cpu -- and hope the
325
    synthesis tool does not choke on it. Adding individual debug ports would be
326
    a PITA.\\
327
    I guess this is why Mentor people took the trouble to write SygnalSpy.\\
328
 
329
    I plan to move to Symphony EDA eventually, so I'll have to fix this.\\
330
 
331
    Using GHDL would be an option, except because it only supports vhdl. The
332
    project will use a SDRAM model in verilog for which I could not find a
333
    vhdl replacement. If the project is to be ported to GHDL (a very desirable
334
    goal even if only because not everybody has access to Modelsim) this will
335
    have to be worked around.\\
336
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.