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

Subversion Repositories s80186

[/] [s80186/] [trunk/] [documentation/] [development-guide.asciidoc] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 jamieiles
= s80x86 Core Development Guide
2
Jamie Iles 
3
 
4
:source-highlighter: coderay
5
 
6
= Developer's Guide
7
 
8
== Building
9
 
10
=== System Requirements
11
 
12
- Docker, tested with version 1.12.1.
13
 
14
=== Quick Start Build
15
 
16
The `scripts/build` script provides everything that is needed to quickly build
17
and test the project.  On the first run, the script will build the required
18
Docker images from `docker/build/Dockerfile`, configure and build the project
19
and run all of the built-in tests.
20
 
21
[source,bash]
22
----
23
./scripts/build
24
----
25
 
26
=== Build Environments
27
 
28
The s80x86 project uses Docker to provide convenient build environments.  This
29
means that it is possible to build and test the design on any Linux system
30
with Docker, regardless of distribution.  The Docker images used internally
31
are all based on Ubuntu 16.04 LTS.
32
 
33
There are two primary build environments:
34
 
35
  - s80x86-build
36
  - s80x86-dev
37
 
38
Each build environment has a script in `docker` to enter the container and
39
build it if not already built.  A 'ccache' cache is created in
40
`_build/.ccache` that persists across container runs to increase build
41
performance.
42
 
43
's80x86-build' is a minimal Ubuntu 16.04 LTS container with the dependencies for
44
building the project and running the tests.  This environment runs everything
45
as the current user's uid/gid to preserve file permissions outside of the
46
container and bind-mounts the project directory into `/build`.  The
47
's80x86-dev' container is intended for developing the project itself and
48
includes extra packages and convenience scripts to make developing easier.
49
Unlike the 's80x86-build' container, this container bind mounts `/home` from
50
the host into the container for convenience and includes packages like GTKWave
51
for viewing waveforms.  It is recommended to use the Docker build environments
52
for all builds and developments as those are used for the baseline development
53
and verification.
54
 
55
=== CI Build Scripts
56
 
57
Several build scripts are included suitable for use in a continuous
58
integration environment.
59
 
60
*scripts/ci/unittest* builds the project from scratch and then runs all of the
61
unit tests, producing JUnit XML suitable for importing into the CI test runner
62
history.
63
 
64
*scripts/ci/gcov-coverage* performs the same steps as `scripts/ci/coverage`
65
but produces Cobertura compatible coverage information that can be read into
66
Jenkins or other CI systems supporting this format.
67
 
68
=== Build Configurations
69
 
70
The CMake based build system supports the following build configurations and
71
can be selected by passing `-DCMAKE_BUILD_TYPE=`'CONFIGURATION' to `cmake`.
72
 
73
*Release* is optimized for performance, no debug information.
74
 
75
*Debug* enables debug information in all C/{cpp} executables, and tracing of
76
Verilog models which will write VCD files for each test run.
77
 
78
*Coverage* builds everything for coverage including {cpp} and Verilog.
79
 
80
=== Configuration Options
81
 
82
There are some CMake configuration options that control features:
83
 
84
  - *-DS80X86_TRAP_ESCAPE* controls whether the escape fault is taken on an
85
  escape opcode.  This defaults to off for DOS compatibility in which case
86
  escape opcodes act like a NOP.
87
 
88
== Simulator
89
 
90
The simulator can run either the software simulation (SoftwareCPU) or the RTL
91
model (RTLCPU).  Typing `^]` will cause the simulator to exit.
92
 
93
----
94
Options:
95
  -h [ --help ]         print this usage information and exit
96
  -b [ --backend ] arg  the simulator backend module to use, either SoftwareCPU
97
                        or RTLCPU, default SoftwareCPU
98
  -r [ --restore ] arg  restore file to load from
99
  -s [ --save ] arg     save file to write from
100
  --bios arg            the bios image to use
101
  --diskimage arg       the boot disk image
102
----
103
 
104
The save and restore functionality are a useful tool for debugging - the
105
entire simulation state can be saved at exit and restored later making it
106
possible to checkpoint once the system is in a known state and then repeatedly
107
debug without waiting for the system to return to the same state.
108
Importantly, this is transferable between backends, so it is possible to boot
109
the system and run an application with the `SoftwareCPU` and then exit and
110
restart with the `RTLCPU` to greatly reduce time taken to get to the
111
interesting debug point.
112
 
113
== Microcode
114
 
115
The microcode is stored in `rtl/microcode` where microcode files have the
116
`.us` suffix.  The microassembler first passes these files through the C
117
preprocessor to allow inclusion of other files and creating macros.
118
 
119
=== Directives
120
 
121
Directives are used to provide information to the microassembler about
122
microcode layout without actually generating microinstructions.
123
 
124
.Microassembler Directives
125
[cols="3,7"]
126
|===
127
| Name | Description
128
| .opcode NUM
129
| The `.opcode NUM` directive tells the microassembler to insert the next
130
  microinstruction at address `NUM` in the microprogram.  This is used for the
131
  first 256 opcodes so that efficient dispatch can be performed by jumping to
132
  the address corresponding to the value of the opcode.
133
| .auto_address
134
| Returns the address assignment to automatically assigned addresses after
135
  using the `.opcode` directive.
136
|===
137
 
138
=== Microinstruction Fields
139
 
140
==== Jumps
141
 
142
.Microcode Jump Types
143
[cols="3,7"]
144
|===
145
| Name | Description
146
| jmp_rm_reg_mem LABEL a| tells the microassembler to generate a jump that will
147
jump to the label if the Mod R/M decoder indicates a register operand in the
148
R/M field and the label + 1 if the R/M field encodes a memory operand.  For
149
example:
150
 
151
[source,asm]
152
----
153
    jmp_rm_reg_mem foo_reg;
154
foo_reg:
155
    next_instruction;
156
foo_mem:
157
    next_instruction;
158
----
159
 
160
will jump to `foo_reg` if the R/M operand is a register operand and `foo_mem`
161
if the R/M operand is a memory operand.  The two microinstructions must be
162
adjacent with the register based instruction appearing first.
163
 
164
| jmp_opcode | Takes the value of the opcode that was fetched and jumps to
165
  that address as an absolute value, used in combination with the `.at`
166
  directive to implement opcodes.
167
 
168
| jmp_dispatch_reg LABEL | Using the reg field of the mod r/m byte, jump to
169
  the target address + the value of the reg field.  Used for implementing
170
  different instructions that share the same opcode.
171
 
172
| jmp_if_not_rep LABEL | Jump to the target address if the string instruction
173
  does not have a rep prefix, otherwise continue execution at the next
174
  incremented address.  Only valid on string instructions that may be combined
175
  with a rep prefix.
176
 
177
| jmp_if_zero LABEL | Jump to the target address if the Z flag is set,
178
  otherwise continue with the adjacent instruction.  Note that this uses the
179
  flags register and not the combinational flags output of the current ALU
180
  operation.
181
 
182
| jmp_rb_zero LABEL | Jump to the target address if RB value is zero,
183
  otherwise continue with the adjacent instruction.
184
 
185
| jmp_if_rep_not_taken LABEL | Check the condition for the current rep prefix
186
  and jump to the target if the termination condition is not met, otherwise
187
  execute the adjacent instruction.  Only valid when there is a rep prefix
188
  present.
189
 
190
| jmp_if_taken LABEL | Jump to the target if the jump instruction has the
191
  condition met, otherwise continue with the adjacent instruction.  This is
192
  only valid for jump instructions, and INTO.
193
 
194
| jmp_loop_done LABEL | Jump to the target if loop has completed.  The loop
195
  counter is loaded from the 5 MSB's of the immediate and decremented on each
196
  iteration.  This is only used for the `enter` instruction.
197
 
198
| jmp LABEL | An unconditional jump, will always transfer control to LABEL.
199
|===
200
 
201
=== Data Sources
202
 
203
.Microcode Data Sources
204
[cols="3,7"]
205
|===
206
| Name | Description
207
| ra_sel | Which general purpose register to fetch for RA.  Note that register
208
  fetches have a single cycle latency.  Only valid when `ra_modrm_rm_reg` is
209
  not set.
210
| rb_cl | Set to use the value of `CL` for RB after a single cycle of latency,
211
  used primarily for shifts.
212
| segment | Set the default segment for the memory operation or segment
213
  register read.  This is the default segment and may be overriden with a
214
  segment override prefix unless `segment_force` is also set.
215
| a_sel a|
216
  Selects which operand source to use for the internal A bus:
217
 
218
    - RA: the fetched RA GPR value.
219
    - IP: the instruction pointer of the next instruction.
220
    - MAR: the contents of the memory address register.
221
    - MDR: the contents of the memory data register.
222
| b_sel a|
223
  Selects which operand source to use for the internal B bus:
224
 
225
    - RB: the fetched RB GPR value.
226
    - IMMEDIATE: an immediate value, either from the immediate reader or from
227
    the constant pool if a microinstruction defined constant is being used.
228
    - SR: the fetched segment register value.
229
    - TEMP: the contents of the temporary register.
230
| immediate | The immediate constant to use.  This forms a constant pool in
231
  the microcode and can be used for operations such as fetching exception
232
  handler addresses, incrementing/decrementing pointers etc.
233
| mar_wr_sel a| Selects the source of the value to be written to the memory
234
  address register:
235
 
236
    - EA: the effective address calculated by the mod r/m decoder.
237
    - Q: the Q bus driven by the ALU.
238
|===
239
 
240
=== Control Signals
241
 
242
.Microcode Control Signals
243
[cols="3,7"]
244
|===
245
| Name | Description
246
| next_instruction | Ends processing of the current instruction, will check
247
  for pending interrupts, jump to the instruction dispatch address, update
248
  CS:IP and reset any intermediate state.
249
| mar_write | Write the value of the `mar_wr_sel` source into the memory
250
  address register.
251
| mdr_write | Write the value of the ALU output into the memory data register.
252
| mem_read | Perform a memory access with the specified segment and memory
253
  address register value, reading into the memory data register.  Note that
254
  the segment register must have had the fetch initiated in the previous
255
  instruction and should be held for the duration of the access.  This field
256
  will cause the microsequencer to stall until the access is complete.  The
257
  `width` field will specify the size of the access.
258
| mem_write | Perform a memory write, writing the contents of the memory data
259
  register to the address specified by the fetched segment and the memory
260
  address register.  As with `mem_read`, the segment must have had the fetch
261
  initiated in the previous instruction and held for the duration of this
262
  instruction.
263
| segment_force | When used in combination with the `segment` field, this will
264
  force that segment to be used unconditionally, ignoring any segment override
265
  prefix.
266
| alu_op | The ALU operation to execute, see
267
  "scripts/microassembler/microasm/types.py" for a full list of operations.
268
| update_flags a| A list of flags that should be written when performing an ALU
269
  operation.  If not specified, no flags will be update.  For example:
270
 
271
[source,asm]
272
----
273
    alu_op ADD, update_flags CF OF ZF AF
274
----
275
 
276
will update the carry, overflow, zero and adjust flags to the result of the
277
ALU operation.
278
| modrm_start | Trigger the mod r/m decoding.  This will stall until complete
279
  and calculate any effective addresses required.
280
| rd_sel_source a| The source of the destination register number:
281
 
282
  - MODRM_REG: use the reg field of the mod r/m byte as the destination
283
  register.
284
  - MODRM_RM_REG: use the rm field of the mod r/m byte as the destination
285
  register.
286
  - MICROCODE_RD_SEL: use the rd_sel field of the instruction to select the
287
  destination register.
288
 
289
| reg_wr_source a| Selects which result should be written to the destination
290
  register:
291
 
292
  - Q: the result of the ALU operation.
293
  - QUOTIENT: the quotient of a division operation.
294
  - REMAINDER: the remainder of a division operation.
295
 
296
| tmp_wr_en | Set to write the output of the ALU into the temporary register.
297
| tmp_wr_sel a| Select the source of the temporary register write:
298
 
299
  - Q_LOW: the low 16-bits of the ALU output by default.
300
  - Q_HIGH: the high 16-bits of the ALU output, only used for 16x16
301
  multiplications.
302
 
303
| width | Selects the width of the operation.  Defaults to 16-bit, but "width
304
  W8" will perform byte operations for register read/write, memory read/write,
305
  immediate fetch and ALU operations.  "width WAUTO" will infer the width from
306
  the opcode, where bit 0 being set indicates a 16-bit operation.
307
| load_ip | Causes the ALU result to be used as the new IP to be taken when
308
  the next instruction is executed.
309
| read_immed | Triggers the immediate reader to read an immediate from the
310
  instruction stream with the specified width.
311
| io | Combined with `mem_read`/`mem_write` to indicate that the operation
312
  should use the I/O address space.  This will cause the segment to be ignored
313
  and the io pin to be asserted for the duration of this microinstruction.
314
| ext_int_inhibit | Used at the end of a microprogram, this flag indicates
315
  that the microsequencer should not check for interrupts after this
316
  instruction.  This is used for instructions like `mov ss, bx` where the
317
  following instruction would set `sp`.
318
| ext_int_inhibit | Used in string instructions to indicate that interrupts
319
  may be serviced at this point.
320
|===
321
 
322
== Debug
323
 
324
The microsequencer provides a very simple way to implement on-chip debug.  The
325
core has a number of signals to interface between a debug controller
326
(typically JTAG) and the microsequencer.  These signals are all in the core
327
clock domain and will require synchronization with a debug controller in a
328
different clock domain.
329
 
330
The debug mechanism works by putting the core into a halt mode where it will
331
perform a tight loop in the microsequencer at which point other debug
332
operations can be issued.  Operations are issued by running a microprogram at
333
a known address allowing more debug procedures to be added easily.  To perform
334
a debug operation, the debug controller first halts the core by raising
335
`debug_seize` and waits for the core to enter the halted state with
336
`debug_stopped` asserted which will be at the end of the current microprogram.
337
Once stopped, the controller can write data to the temporary register if
338
required with `debug_wr_val` and `debug_wr_en` and then run the debug procedure
339
by writing the procedure address to `debug_addr` and asserting `debug_run` for
340
a single clock cycle.
341
 
342
=== Debug Signals
343
 
344
.Debug Interface Signals
345
[cols="2,1,1,3",options="header"]
346
|===
347
| Name | Width | Direction | Description
348
 
349
| debug_stopped | 1 | output | Asserted when the core is in a debug halt and
350
  is ready for debug operations.  The debug controller must not issue any
351
  operations when `debug_stopped` is not asserted.
352
| debug_seize | 1 | input | Asserted by the controller to request that the core
353
  enters debug mode.  This may be deasserted once `debug_stopped` has been
354
  asserted and then the run procedure executed to continue normal operation.
355
| debug_addr | 8 | input | The address of the debug procedure to execute, must
356
  be written at the same time as `debug_run`.  The core will run the procedure
357
  at 100h + `debug_addr`.
358
| debug_run | 1 | input | Asserted by the debug controller to begin the debug
359
  procedure specified in `debug_addr`.
360
| debug_wr_val | 16 | input | Asserted by the debug controller to write the
361
  value in `debug_wr_val` into the temporary register.
362
| debug_wr_en | 1 | input | Asserted by the debug controller to write
363
  `debug_wr_val` into the temporary register.
364
|===
365
 
366
=== Control and Reserved Debug Procedures
367
 
368
  - *0x00*: resume execution.  If `debug_seize` is held high then this will
369
  single-step one instruction, otherwise run indefinitely until seized.
370
  - *0x01 - 0x02: reserved for internal use, execution will yield undefined
371
  behaviour.*
372
 
373
=== Data Transfer Debug Procedures
374
 
375
These debug procedures are used to transfer data between the debug controller
376
and the core.
377
 
378
.Data Transfer Debug Procedures
379
[cols=3*,options="header"]
380
|===
381
| Program Number
382
| Source
383
| Destination
384
| 0x03 | `AX` | `debug_val`
385
| 0x04 | `CX` | `debug_val`
386
| 0x05 | `DX` | `debug_val`
387
| 0x06 | `BX` | `debug_val`
388
| 0x07 | `SP` | `debug_val`
389
| 0x08 | `BP` | `debug_val`
390
| 0x09 | `SI` | `debug_val`
391
| 0x0a | `DI` | `debug_val`
392
| 0x0b | `ES` | `debug_val`
393
| 0x0c | `CS` | `debug_val`
394
| 0x0d | `SS` | `debug_val`
395
| 0x0e | `DS` | `debug_val`
396
| 0x0f | `IP` | `debug_val`
397
| 0x10 | `FLAGS` | `debug_val`
398
| 0x11 | `debug_val` | `IP`
399
| 0x12 | `debug_val` | `FLAGS`
400
| 0x13 | `debug_val` | `AX`
401
| 0x14 | `debug_val` | `CX`
402
| 0x15 | `debug_val` | `DX`
403
| 0x16 | `debug_val` | `BX`
404
| 0x17 | `debug_val` | `SP`
405
| 0x18 | `debug_val` | `BP`
406
| 0x19 | `debug_val` | `SI`
407
| 0x1a | `debug_val` | `DI`
408
| 0x1b | `debug_val` | `ES`
409
| 0x1c | `debug_val` | `CS`
410
| 0x1d | `debug_val` | `SS`
411
| 0x1e | `debug_val` | `DS`
412
| 0x1f | `debug_val` | `MAR`
413
| 0x20 | `debug_val` | `MDR`
414
| 0x21 | mem8[DS:MAR] | `debug_val`
415
| 0x22 | mem16[DS:MAR] | `debug_val`
416
| 0x23 | MDR | mem8[DS:MAR]
417
| 0x24 | MDR | mem16[DS:MAR]
418
| 0x25 | io8[MAR] | `debug_val`
419
| 0x26 | io16[MAR] | `debug_val`
420
| 0x27 | MDR | io8[MAR]
421
| 0x28 | MDR | io16[MAR]
422
|===
423
 
424
[NOTE]
425
====
426
All memory transfers implicitly use DS as the segment.  To write outside of
427
the current data segment, save the value of DS, write it with the new value,
428
perform the access and then restore DS.
429
====
430
 
431
== FPGA JTAG
432
 
433
The DE0-Nano and DE0-CV boards use the Altera Virtual JTAG to implement a
434
debug bridge between the development machine and the FPGA design.  This is not
435
a compliant JTAG TAP, but provides a reference implementation of implementing
436
a debug interface for the core.
437
 
438
The implementation uses a 2 bit instruction register and variable length data
439
register.
440
 
441
.JTAG Instruction Register Definitions
442
[cols=2*,options="header"]
443
|===
444
| Register
445
| Name
446
| 2'b00 | IDCODE
447
| 2'b01 | STATUS_CONTROL
448
| 2'b10 | DEBUG_VALUE
449
| 2'b11 | RUN_PROCEDURE
450
|===
451
 
452
=== IDCODE
453
 
454
The IDCODE register is a 32-bit register containing the device ID code.  This
455
register is read-only, values shifted in are ignored.
456
 
457
=== STATUS_CONTROL
458
 
459
.JTAG STATUS_CONTROL Data Register
460
[cols="2,1,1,3",options="header"]
461
|===
462
| Field
463
| Bits
464
| Access
465
| Description
466
| RUN | [0:0] | R/W | Returns the current execution state of the CPU, "1"
467
indicates that the core is executing in normal mode.  Write a "0" to enter
468
debug mode, polling this bit until it reflects that the core has stopped.  To
469
restart the core, write a "1", and then run debug procedure "0".
470
| RESET | [1:1] | R/W | Core reset control, write "1" to start a reset, write
471
"0" to clear.
472
| RESERVED | [15:2] | RO | Reserved for future use.
473
| WRITE_ENABLE | [16] | WO | Write as "1" to write the value shifted in into
474
the core, otherwise the shifted value will be discarded.
475
|===
476
 
477
=== DEBUG_VALUE
478
 
479
.JTAG DEBUG_VALUE Data Register
480
[cols="2,1,1,3",options="header"]
481
|===
482
| Field
483
| Bits
484
| Access
485
| Description
486
| VALUE | [15:0] | RW | The value to be written to/read from the debug
487
controller.
488
| WRITE_ENABLE | [16] | R/W | For the value shifted in, if this is set to "1",
489
then the VALUE will be written into the debug controller, otherwise discarded.
490
For the value shifted out, if "1", then the VALUE field is valid.  When
491
reading, this bit should be polled until it returns "1".
492
|===
493
 
494
=== RUN_PROCEDURE
495
 
496
.JTAG RUN_PROCEDURE Data Register
497
[cols="2,1,1,3",options="header"]
498
|===
499
| Field
500
| Bits
501
| Access
502
| Description
503
| VALUE | [7:0] | WO | The debug procedure to run.  This is a write-only
504
field.
505
|===
506
 
507
== FPGA Reference Designs
508
 
509
=== DE0-Nano
510
 
511
To build the DE0-Nano design, configure the build with "-DBUILD_DE0_NANO=ON".
512
The build target "de0-nano" will build the FPGA, and "de0-nano-program" will
513
load the design into the FPGA via the Altera USB Blaster.
514
 
515
.DE0-Nano Memory Map
516
[cols="1,1,4",options="header"]
517
|===
518
| Start | End | Description
519
| 20'h0000 | 20'hfffff | SDRAM
520
|===
521
 
522
.DE0-Nano IO Port Map
523
[cols="1,1,4",options="header"]
524
|===
525
| Address | Width (bits) | Description
526
| 16'h0020 | 8 | PIC command register
527
| 16'h0021 | 8 | PIC data register
528
| 16'h0040 | 8 | PIT channel 0 data register
529
| 16'h0043 | 8 | PIT control register
530
| 16'hffec | 16 a| BIOS control register:
531
 
532
  - [0]: BIOS ROM enabled.
533
 
534
| 16'hfff0 | 16 a| SPI control register:
535
 
536
  - [15:10]: reserved.
537
  - [9]: CS activate.
538
  - [8:0]: clock divider.
539
| 16'hfff2 | 16 a| SPI transfer register:
540
 
541
  - [15:9]: reserved.
542
  - [8]: transfer busy.
543
  - [7:0]: transfer data.
544
 
545
Writing to this register will initiate a one byte transfer.  The CPU should
546
then poll until bit 8 is clear at which point [7:0] will contain the received
547
data.
548
 
549
| 16'ffff6 | 8 a| IRQ test register:
550
  - [7]: write a 1 to raise NMI, 0 to clear NMI.
551
  - [6:0]: write a 1 to raise interrupt N.
552
 
553
| 16'hfffa | 8 a| UART data register, write to transmit data, read to fetch
554
the received data.
555
| 16'hfffb | 8 a| UART status register:
556
 
557
  - [7:2]: reserved.
558
  - [1]: transmitter busy.
559
  - [0]: receive data ready, cleared once the data register is read.
560
 
561
| 16'hfffc | 16 a| SDRAM configuration register:
562
 
563
  - [15:1]: reserved.
564
  - [0]: SDRAM configuration complete.  The SDRAM should not be accessed until
565
  this bit is set.
566
 
567
| 16'hfffe | 16 | LED register, writing will set the LED registers on the
568
  board, a 1 is enabled, 0 is disabled.
569
|===
570
 
571
=== DE0-CV
572
 
573
To build the DE0-CV design, configure the build with "-DBUILD_DE0_CV=ON".
574
The build target "de0-cv" will build the FPGA, and "de0-cv-program" will
575
load the design into the FPGA via the Altera USB Blaster.
576
 
577
.DE0-CV Memory Map
578
[cols="1,1,4",options="header"]
579
|===
580
| Start | End | Description
581
| 20'h0000 | 20'hfffff | SDRAM
582
|===
583
 
584
.DE0-CV IO Port Map
585
[cols="1,1,4",options="header"]
586
|===
587
| Address | Width (bits) | Description
588
| 16'h0020 | 8 | PIC command register
589
| 16'h0021 | 8 | PIC data register
590
| 16'h0040 | 8 | PIT channel 0 data register
591
| 16'h0043 | 8 | PIT control register
592
| 16'h0060 | 8 a| PS/2 data register:
593
 
594
  - [7:0]: read the head of the FIFO, 0 if no bytes available.  Write to
595
  transmit a byte, must only be written when bit 2 of the status register is
596
  clear.
597
 
598
| 16'h0061 | 8 a| PS/2 control/status register:
599
 
600
  - [7:3]: reserved
601
  - [2]: transmit in progress, cleared when the transmitter is idle.
602
  - [1]: a byte with a parity error was received and discarded.  Cleared on
603
  read.
604
  - [0]: receive FIFO not empty/acknowledge.  Write to acknowledge the last
605
  received byte and pop it from the FIFO.
606
 
607
| 16'hffec | 16 a| BIOS control register:
608
 
609
  - [0]: BIOS writable.
610
 
611
| 16'hfff0 | 16 a| SPI control register:
612
 
613
  - [15:10]: reserved.
614
  - [9]: CS activate.
615
  - [8:0]: clock divider.
616
| 16'hfff2 | 16 a| SPI transfer register:
617
 
618
  - [15:9]: reserved.
619
  - [8]: transfer busy.
620
  - [7:0]: transfer data.
621
 
622
Writing to this register will initiate a one byte transfer.  The CPU should
623
then poll until bit 8 is clear at which point [7:0] will contain the received
624
data.
625
 
626
| 16'ffff6 | 8 a| IRQ test register:
627
  - [7]: write a 1 to raise NMI, 0 to clear NMI.
628
  - [6:0]: write a 1 to raise interrupt N.
629
 
630
| 16'hfffa | 8 a| UART data register, write to transmit data, read to fetch
631
the received data.
632
| 16'hfffb | 8 a| UART status register:
633
 
634
  - [7:2]: reserved.
635
  - [1]: transmitter busy.
636
  - [0]: receive data ready, cleared once the data register is read.
637
 
638
| 16'hfffc | 16 a| SDRAM configuration register:
639
 
640
  - [15:1]: reserved.
641
  - [0]: SDRAM configuration complete.  The SDRAM should not be accessed until
642
  this bit is set.
643
|===
644
 
645
=== BIOS
646
 
647
The reference BIOS is a non-compliant BIOS for demonstration purposes.  The
648
bios is built with the Mentor Graphics `ia16-elf` toolchain which is installed
649
in the standard docker images.  The BIOS uses an SD card to emulate the floppy
650
drive and will boot the first sector of whatever is written to that SD card.
651
 
652
The BIOS is loaded at "f000:e000", and the BIOS stack grows down from
653
"f000:dffe".  The UART is used for video and keyboard services.
654
 
655
== RTL Tests
656
 
657
The RTL tests are written in {cpp}, using Verilator to create {cpp} models of the
658
Verilog.  For example, given a synchronous Fifo, the Verilator model can be
659
created using the Verilator CMake package:
660
 
661
[source,cmake]
662
----
663
include(Verilator)
664
add_library(verilator STATIC ${VERILATOR_LIB_SOURCES})
665
verilate(Fifo ${CMAKE_CURRENT_SOURCE_DIR}/Fifo.v)
666
----
667
 
668
This will generate a `verilator` library containing the common Verilator
669
support functions, run Verilator on `Fifo.v` and generate a `VFifo` library
670
and `VFifo.h` header for inclusion in the test code.  A templated wrapper
671
'VerilogTestbench' in `VerilogTestbench.h` provides convenient methods for
672
resetting and clocking the device under test along with running deferred and
673
clock edge events, tracing and coverage.
674
 
675
The device under test can then be encapsulated inside a class and used for
676
writing tests with Google Test.  For example, wrapping the Verilog model:
677
 
678
[source,c++]
679
----
680
#include 
681
 
682
#include "VerilogTestbench.h"
683
 
684
class FifoTestbench : public VerilogTestbench {
685
public:
686
    FifoTestbench(VFifo *dut);
687
    void push(uint32_t val);
688
    uint32_t pop();
689
};
690
 
691
FifoTestbench::FifoTestbench(VFifo *dut)
692
    : VerilogTestbench(dut)
693
{
694
    dut->wr_en = 0;
695
    dut->wr_data = 0LU;
696
    dut->rd_en = 0;
697
}
698
 
699
void FifoTestbench::push(uint32_t val)
700
{
701
    dut->wr_data = val;
702
    dut->wr_en = 1;
703
    cycle();
704
    dut->wr_en = 0;
705
}
706
 
707
uint32_t FifoTestbench::pop()
708
{
709
    dut->rd_en = 1;
710
    cycle();
711
    dut->rd_en = 0;
712
 
713
    return dut->rd_data;
714
}
715
----
716
 
717
Then a test can be written to exercise it:
718
 
719
[source,c++]
720
----
721
TEST(Fifo, ResetClears)
722
{
723
    FifoTestbench tb;
724
 
725
    for (uint32_t m = 0; m < 4; ++m)
726
        tb.push(m);
727
 
728
    ASSERT_FALSE(tb.dut->empty);
729
    tb.reset();
730
    ASSERT_TRUE(tb.dut->empty);
731
}
732
----
733
 
734
More complex tests that have deferred events such as reading from memory can
735
be written by adding events on positive+negative clock edges and running after
736
a number of cycles.  `tests/rtl/TestPrefetch.cpp` uses a number of these
737
concepts.  With the right abstractions it can be possible to type-parameterize
738
these test cases to run against pure software simulations and Verilog models.
739
 
740
= Programmer's Reference
741
 
742
== Interrupts
743
 
744
The CPU core implements the following exceptions.  Traps are handled after the
745
instruction and the saved CS:IP points to the next instruction, faults are
746
restartable and the saved CS:IP points to the instruction that caused the
747
fault and so can be restarted.  The core correctly handles multiple prefix
748
bytes during an interrupted string instruction.
749
 
750
.Exceptions
751
[cols="2,2,1,6",options="header"]
752
|===
753
| Name | Type | Number | Description
754
| Divide-by-zero | Trap | 0 | Raised when division by zero occurs or the result of
755
the division operation does not fit in the range of the destination register.
756
| Single-step | Trap | 1 | Raised when `TF` is set and the core steps an instruction.
757
| NMI | Interrupt | 2 | Non-maskable interrupt, raised when the `nmi` signal
758
has a negative to positive edge.
759
| INT | Interrupt | 3 | Normal interrupt, raised by the `int3` instruction.
760
| Overflow | Trap | 4 | Overflow, raised by an `into` instruction if `OF` is
761
set.
762
| Bound | Trap | 5 | Bounds check, raised when the `bound` instruction detects
763
an out-of-bounds address.
764
| Invalid Opcode | Trap | 6 a| Raised when an invalid opcode is executed.
765
Invalid opcodes do not include unimplemented opcodes or undocumented opcodes.
766
The opcodes that raise this trap are:
767
 
768
  * 8'h0f
769
  * 8'h63
770
  * 8'h64
771
  * 8'h65
772
  * 8'h66
773
  * 8'h67
774
  * 8'hf1
775
  * 8'hff or 8'hfe with /reg=7
776
  * 8'h62 (bound) with a register operand
777
 
778
| Escape | Fault | 7 | Escape opcode, this will always be raised on an `esc`
779
instruction as no coprocessors are supported.
780
|===
781
 
782
== Instructions
783
 
784
The following tables list all of the supported instructions along with sizes
785
and timings for each.  The timings are measured using the RTL simulation under
786
the following conditions:
787
 
788
  * The prefetch FIFO contains the instruction and is padded with other bytes
789
    to be full.
790
  * The instruction and data busses are connected to an arbiter that gives
791
    priority to data accesses.
792
  * Memory accesses take a single cycle to complete.
793
 
794
Instructions with a MOD R/M byte have a variable length and execution time
795
depending on whether the addressing mode has a displacement.  In the
796
instruction tables, the length reflects this, and if the addressing mode uses
797
a displacement, add one cycle per displacement byte for the execution timing.
798
 
799
Prefix bytes add one byte to the instruction length and one cycle to the
800
execution time, and for conflicting prefixes such as multiple segment
801
overrides, the last prefix is used.
802
 
803
<<<
804
 
805
include::instructions.asciidoc[]

powered by: WebSVN 2.1.0

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