mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-23 13:27:10 -04:00
commit
b1b89f55fb
14 changed files with 261 additions and 47 deletions
|
@ -32,7 +32,8 @@ numfig_format = {'figure': 'Figure %s', 'table': 'Table %s', 'code-block': 'List
|
|||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = []
|
||||
extensions = ['sphinxcontrib.wavedrom']
|
||||
wavedrom_html_jsinline = False
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
|
|
@ -88,6 +88,8 @@ Reset Value: ``0x0000_0000``
|
|||
+-------+-----+------------------------------------------------------------------+
|
||||
|
||||
|
||||
.. _csr-mhartid:
|
||||
|
||||
MHARTID
|
||||
-------
|
||||
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
{signal: [
|
||||
{name: 'clk', wave: 'p......'},
|
||||
{name: 'data_addr_o', wave: 'x=.xxxx', data: ['Address']},
|
||||
{name: 'data_wdata_o', wave: 'x=.xxxx', data: ['WData']},
|
||||
{name: 'data_req_o', wave: '01.0...'},
|
||||
{name: 'data_gnt_i', wave: '0.10...'},
|
||||
{name: 'data_rvalid_i', wave: '0..10..'},
|
||||
{name: 'data_wdata_o', wave: 'xxx=xxx', data: ['RData']},
|
||||
{name: 'data_we_o', wave: 'x=.xxxx', data: ['WE']},
|
||||
{name: 'data_be_o', wave: 'x=.xxxx', data: ['BE']},
|
||||
],
|
||||
config: { hscale: 2 }
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 30 KiB |
|
@ -1,13 +0,0 @@
|
|||
{signal: [
|
||||
{name: 'clk', wave: 'p......'},
|
||||
{name: 'data_addr_o', wave: 'x==xxxx', data: ['Addr1', 'Addr2']},
|
||||
{name: 'data_wdata_o', wave: 'x==xxxx', data: ['WData1', 'Wdata2']},
|
||||
{name: 'data_req_o', wave: '01.0...'},
|
||||
{name: 'data_gnt_i', wave: '01.0...'},
|
||||
{name: 'data_rvalid_i', wave: '0.1.0..'},
|
||||
{name: 'data_wdata_o', wave: 'xx==xxx', data: ['RData1', 'RData2']},
|
||||
{name: 'data_we_o', wave: 'x==xxxx', data: ['WE1', 'WE2']},
|
||||
{name: 'data_be_o', wave: 'x==xxxx', data: ['BE1', 'BE2']},
|
||||
],
|
||||
config: { hscale: 2 }
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 32 KiB |
|
@ -1,13 +0,0 @@
|
|||
{signal: [
|
||||
{name: 'clk', wave: 'p......'},
|
||||
{name: 'data_addr_o', wave: 'x=..xxx', data: ['Address']},
|
||||
{name: 'data_wdata_o', wave: 'x=..xxx', data: ['WData']},
|
||||
{name: 'data_req_o', wave: '01..0..'},
|
||||
{name: 'data_gnt_i', wave: '0..10..'},
|
||||
{name: 'data_rvalid_i', wave: '0....10'},
|
||||
{name: 'data_wdata_o', wave: 'xxxxx=x', data: ['RData']},
|
||||
{name: 'data_we_o', wave: 'x=..xxx', data: ['WE']},
|
||||
{name: 'data_be_o', wave: 'x=..xxx', data: ['BE']},
|
||||
],
|
||||
config: { hscale: 2 }
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 30 KiB |
|
@ -11,10 +11,12 @@ ZERO-RISCY: User Manual
|
|||
:caption: Contents:
|
||||
|
||||
introduction
|
||||
integration
|
||||
instruction_fetch
|
||||
load_store_unit
|
||||
register_file
|
||||
cs_registers
|
||||
interrupts
|
||||
performance_counters
|
||||
exception_interrupts
|
||||
debug
|
||||
|
|
|
@ -35,3 +35,27 @@ Protocol
|
|||
--------
|
||||
|
||||
The protocol used to communicate with the instruction cache or the instruction memory is the same as the protocol used by the LSU. See the description of the LSU in :ref:`LSU Protocol<lsu-protocol>` for details about the protocol.
|
||||
|
||||
.. caution::
|
||||
|
||||
The instruction fetch interface differs from the LSU interface in that the address can change
|
||||
while the request is valid. This is because it can update the instructions to fetch when a
|
||||
branch occurs. As depicted in :numref:`if_timing_difference` care has to be taken when
|
||||
working with the address. The data returned must of course match the address during the grant
|
||||
cycle.
|
||||
|
||||
.. wavedrom::
|
||||
:name: if_timing_difference
|
||||
:caption: Memory transaction with wait states
|
||||
|
||||
{"signal":
|
||||
[
|
||||
{"name": "clk", "wave": "p......"},
|
||||
{"name": "data_addr_o", "wave": "x===xxx", "data": ["Address", "Address", "Address"]},
|
||||
{"name": "data_req_o", "wave": "01..0.."},
|
||||
{"name": "data_gnt_i", "wave": "0..10.."},
|
||||
{"name": "data_rvalid_i", "wave": "0....10"},
|
||||
{"name": "data_rdata_i", "wave": "xxxxx=x", "data": ["RData"]}
|
||||
],
|
||||
"config": { "hscale": 2 }
|
||||
}
|
||||
|
|
121
doc/integration.rst
Normal file
121
doc/integration.rst
Normal file
|
@ -0,0 +1,121 @@
|
|||
Core Integration
|
||||
================
|
||||
|
||||
The main module is named ``zeroriscy_core`` and can be found in ``zeroriscy_core.sv``. In the following the instantiation template is given and the parameters and interfaces are described.
|
||||
|
||||
Instantiation Template
|
||||
----------------------
|
||||
|
||||
.. code-block:: verilog
|
||||
|
||||
zeroriscy_core
|
||||
#(.N_EXT_PERF_COUNTERS (0),
|
||||
.RV32E (0),
|
||||
.RV32M (1))
|
||||
u_core
|
||||
(// Clock and reset
|
||||
.clk_i (),
|
||||
.rst_ni (),
|
||||
.clock_en_i (),
|
||||
.test_en_i (),
|
||||
|
||||
// Configuration
|
||||
.core_id_i (),
|
||||
.cluster_id_i (),
|
||||
.boot_addr_i (),
|
||||
|
||||
// Instruction memory interface
|
||||
.instr_req_o (),
|
||||
.instr_gnt_i (),
|
||||
.instr_rvalid_i (),
|
||||
.instr_addr_o (),
|
||||
.instr_rdata_i (),
|
||||
|
||||
// Data memory interface
|
||||
.data_req_o (),
|
||||
.data_gnt_i (),
|
||||
.data_rvalid_i (),
|
||||
.data_we_o (),
|
||||
.data_be_o (),
|
||||
.data_addr_o (),
|
||||
.data_wdata_o (),
|
||||
.data_rdata_i (),
|
||||
.data_err_i (),
|
||||
|
||||
// Interrupt inputs
|
||||
.irq_i (),
|
||||
.irq_id_i (),
|
||||
.irq_ack_o (),
|
||||
.irq_id_o (),
|
||||
|
||||
// Debug Interface
|
||||
.debug_req_i (),
|
||||
.debug_gnt_o (),
|
||||
.debug_rvalid_o (),
|
||||
.debug_addr_i (),
|
||||
.debug_we_i (),
|
||||
.debug_wdata_i (),
|
||||
.debug_rdata_o (),
|
||||
.debug_halted_o (),
|
||||
.debug_halt_i (),
|
||||
.debug_resume_i (),
|
||||
|
||||
// Special control signal
|
||||
.fetch_enable_i (),
|
||||
|
||||
// External performance counters
|
||||
.ext_perf_counters_i ()
|
||||
);
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
+-------------------------+-------------+---------+------------------------------------------------+
|
||||
| Name | Type/Range | Default | Description |
|
||||
+=========================+=============+=========+================================================+
|
||||
| ``N_EXT_PERF_COUNTERS`` | int (0..21) | 0 | Number of external performance counters |
|
||||
+-------------------------+-------------+---------+------------------------------------------------+
|
||||
| ``RV32E`` | int (0..1) | 0 | RV32E mode enable (16 integer registers only) |
|
||||
+-------------------------+-------------+---------+------------------------------------------------+
|
||||
| ``RV32M`` | int (0..1) | 1 | M(ultiply) extension enable |
|
||||
+-------------------------+-------------+---------+------------------------------------------------+
|
||||
|
||||
|
||||
Interfaces
|
||||
----------
|
||||
|
||||
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| Signal(s) | Width | Dir | Description |
|
||||
+=========================+=========================+=====+========================================+
|
||||
| ``clk_i`` | 1 | in | Clock signal |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``rst_ni`` | 1 | in |Active-low synchronous reset |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``clock_en_i`` | 1 | in | Clock gating input |
|
||||
| | | | (0: clock gated, 1: clock running) |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``test_en_i`` | 1 | in | Test input, enables clock |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``core_id_i`` | 4 | in | Core id, usually static, can be read |
|
||||
| | | | from :ref:`csr-mhartid` |
|
||||
+-------------------------+-------------------------+-----+ +
|
||||
| ``cluster_id_i`` | 6 | in | |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``boot_adr_i`` | 32 | in | First program counter after reset |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``instr_*`` | Instruction fetch interface, see :ref:`instruction-fetch` |
|
||||
+-------------------------+------------------------------------------------------------------------+
|
||||
| ``data_*`` | Load-store unit interface, see :ref:`load-store-unit` |
|
||||
+-------------------------+------------------------------------------------------------------------+
|
||||
| ``irq_*`` | Interrupt interface, see :ref:`interrupts` |
|
||||
+-------------------------+------------------------------------------------------------------------+
|
||||
| ``debug_*`` | Debug interface, see :ref:`debug-unit` |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``fetch_enable_i`` | 1 | in | Enable the core, won't fetch when 0 |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
| ``ext_perf_counters_i`` | ``N_EXT_PERF_COUNTERS`` | in | External performance counter |
|
||||
+-------------------------+-------------------------+-----+----------------------------------------+
|
||||
|
||||
|
||||
|
56
doc/interrupts.rst
Normal file
56
doc/interrupts.rst
Normal file
|
@ -0,0 +1,56 @@
|
|||
.. _interrupts:
|
||||
|
||||
Interrupts
|
||||
==========
|
||||
|
||||
Interrupts are signaled via the external core interface:
|
||||
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| Signal | Direction | Description |
|
||||
+=========================+===========+===============================================+
|
||||
| ``irq_i`` | in | Interrupt event, level sensitive |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``irq_id_i[4:0]`` | in | Interrupt ID |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``irq_ack_o`` | out | Interrupt acknowledgement |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``irq_id_o[4:0]`` | out | Interrupt acknowledgement ID |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
|
||||
When external interrupts are enabled, the core will serve interrupt requests. An interrupt is signaled as asserted high level at the ``irq_i`` signal. The interrupt ID determines the interrupt vector ID (0 to 31).
|
||||
|
||||
Once the interrupt processing is completed, the core will assert ``irq_ack_o`` for one clock cycle along with the identifier that has been completed.
|
||||
|
||||
.. important::
|
||||
|
||||
The core may not start interrupt processing in the same cycle the level changes.
|
||||
|
||||
:numref:`irq-processing` shows the signal timing during a standard interrupt cycle.
|
||||
|
||||
.. wavedrom::
|
||||
:name: irq-processing
|
||||
:caption: Interrupt processing
|
||||
|
||||
{ "signal": [
|
||||
{ "name": "clk_i", "wave": "p...", "period": 2 },
|
||||
{ "name": "irq_i", "wave": "01..|.0." },
|
||||
{ "name": "irq_id_i", "wave": "x=..|.x.", "data": ["ID0"] },
|
||||
{ "name": "irq_ack_o", "wave": "0...|10." },
|
||||
{ "name": "irq_id_id", "wave": "x...|=x.", "data": ["ID0"] }
|
||||
]
|
||||
}
|
||||
|
||||
As the interrupt identifier is registered once it is handled, it is allowed that the interrupt identifier at the input changes. This behavior can be used to handle interrupt priorities. But as the core may already have started interrupt processing, it is necessary to check the acknowledged ID. An example cycle is shown in :numref:`irq-processing-prio`.
|
||||
|
||||
.. wavedrom::
|
||||
:name: irq-processing-prio
|
||||
:caption: Typical interrupt processing with priorization on the interface. Here the processing of ``ID0`` has already started.
|
||||
|
||||
{ "signal": [
|
||||
{ "name": "clk_i", "wave": "p...", "period": 2 },
|
||||
{ "name": "irq_i", "wave": "01..|.1." },
|
||||
{ "name": "irq_id_i", "wave": "x=.=|...", "data": ["ID0", "ID1"] },
|
||||
{ "name": "irq_ack_o", "wave": "0...|10." },
|
||||
{ "name": "irq_id_id", "wave": "x...|=x.", "data": ["ID0"] }
|
||||
]
|
||||
}
|
|
@ -51,17 +51,63 @@ The LSU provides a valid address in ``data_addr_o`` and sets ``data_req_o`` high
|
|||
|
||||
:numref:`timing1`, :numref:`timing2` and :numref:`timing3` show example-timing diagrams of the protocol.
|
||||
|
||||
.. figure:: images/timing1.png
|
||||
.. wavedrom::
|
||||
:name: timing1
|
||||
:caption: Basic Memory Transaction
|
||||
|
||||
Basic Memory Transaction
|
||||
{"signal":
|
||||
[
|
||||
{"name": "clk", "wave": "p......"},
|
||||
{"name": "data_addr_o", "wave": "x=.xxxx", "data": ["Address"]},
|
||||
{"name": "data_wdata_o", "wave": "x=.xxxx", "data": ["WData"]},
|
||||
{"name": "data_req_o", "wave": "01.0..."},
|
||||
{"name": "data_gnt_i", "wave": "0.10..."},
|
||||
{"name": "data_rvalid_i", "wave": "0..10.."},
|
||||
{"name": "data_wdata_o", "wave": "xxx=xxx", "data": ["RData"]},
|
||||
{"name": "data_we_o", "wave": "x=.xxxx", "data": ["WE"]},
|
||||
{"name": "data_be_o", "wave": "x=.xxxx", "data": ["BE"]}
|
||||
],
|
||||
"config": { "hscale": 2 }
|
||||
}
|
||||
|
||||
.. figure:: images/timing2.png
|
||||
|
||||
.. wavedrom::
|
||||
:name: timing2
|
||||
:caption: Back-to-back Memory Transaction
|
||||
|
||||
Back-to-back Memory Transaction
|
||||
{"signal":
|
||||
[
|
||||
{"name": "clk", "wave": "p......"},
|
||||
{"name": "data_addr_o", "wave": "x==xxxx", "data": ["Addr1", "Addr2"]},
|
||||
{"name": "data_wdata_o", "wave": "x==xxxx", "data": ["WData1", "Wdata2"]},
|
||||
{"name": "data_req_o", "wave": "01.0..."},
|
||||
{"name": "data_gnt_i", "wave": "01.0..."},
|
||||
{"name": "data_rvalid_i", "wave": "0.1.0.."},
|
||||
{"name": "data_wdata_o", "wave": "xx==xxx", "data": ["RData1", "RData2"]},
|
||||
{"name": "data_we_o", "wave": "x==xxxx", "data": ["WE1", "WE2"]},
|
||||
{"name": "data_be_o", "wave": "x==xxxx", "data": ["BE1", "BE2"]}
|
||||
],
|
||||
"config": { "hscale": 2 }
|
||||
}
|
||||
|
||||
.. figure:: images/timing3.png
|
||||
|
||||
.. wavedrom::
|
||||
:name: timing3
|
||||
:caption: Slow Response Memory Transaction
|
||||
|
||||
{"signal":
|
||||
[
|
||||
{"name": "clk", "wave": "p......"},
|
||||
{"name": "data_addr_o", "wave": "x=..xxx", "data": ["Address"]},
|
||||
{"name": "data_wdata_o", "wave": "x=..xxx", "data": ["WData"]},
|
||||
{"name": "data_req_o", "wave": "01..0.."},
|
||||
{"name": "data_gnt_i", "wave": "0..10.."},
|
||||
{"name": "data_rvalid_i", "wave": "0....10"},
|
||||
{"name": "data_wdata_o", "wave": "xxxxx=x", "data": ["RData"]},
|
||||
{"name": "data_we_o", "wave": "x=..xxx", "data": ["WE"]},
|
||||
{"name": "data_be_o", "wave": "x=..xxx", "data": ["BE"]}
|
||||
],
|
||||
"config": { "hscale": 2 }
|
||||
}
|
||||
|
||||
|
||||
Slow Response Memory Transaction
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
setuptools_scm
|
||||
sphinx
|
||||
sphinx>=1.8
|
||||
sphinx_rtd_theme
|
||||
git+https://github.com/wallento/sphinx-wavedrom
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue