diff --git a/doc/conf.py b/doc/conf.py index 53be1aba..ebe3e038 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -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'] diff --git a/doc/cs_registers.rst b/doc/cs_registers.rst index 56177a3a..ee17d1e8 100644 --- a/doc/cs_registers.rst +++ b/doc/cs_registers.rst @@ -88,6 +88,8 @@ Reset Value: ``0x0000_0000`` +-------+-----+------------------------------------------------------------------+ +.. _csr-mhartid: + MHARTID ------- diff --git a/doc/images/timing1.json b/doc/images/timing1.json deleted file mode 100644 index e0ff9c78..00000000 --- a/doc/images/timing1.json +++ /dev/null @@ -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 } -} diff --git a/doc/images/timing1.png b/doc/images/timing1.png deleted file mode 100644 index d172e16b..00000000 Binary files a/doc/images/timing1.png and /dev/null differ diff --git a/doc/images/timing2.json b/doc/images/timing2.json deleted file mode 100644 index 9bf340bc..00000000 --- a/doc/images/timing2.json +++ /dev/null @@ -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 } -} diff --git a/doc/images/timing2.png b/doc/images/timing2.png deleted file mode 100644 index dc4ab9e9..00000000 Binary files a/doc/images/timing2.png and /dev/null differ diff --git a/doc/images/timing3.json b/doc/images/timing3.json deleted file mode 100644 index 8bf3c83a..00000000 --- a/doc/images/timing3.json +++ /dev/null @@ -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 } -} diff --git a/doc/images/timing3.png b/doc/images/timing3.png deleted file mode 100644 index ceeab21b..00000000 Binary files a/doc/images/timing3.png and /dev/null differ diff --git a/doc/index.rst b/doc/index.rst index 10662a23..bd00cbe8 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -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 diff --git a/doc/instruction_fetch.rst b/doc/instruction_fetch.rst index e6b1e5ed..69849d78 100644 --- a/doc/instruction_fetch.rst +++ b/doc/instruction_fetch.rst @@ -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` 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 } + } diff --git a/doc/integration.rst b/doc/integration.rst new file mode 100644 index 00000000..48f53a5b --- /dev/null +++ b/doc/integration.rst @@ -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 | ++-------------------------+-------------------------+-----+----------------------------------------+ + + + diff --git a/doc/interrupts.rst b/doc/interrupts.rst new file mode 100644 index 00000000..ba7cb206 --- /dev/null +++ b/doc/interrupts.rst @@ -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"] } + ] + } diff --git a/doc/load_store_unit.rst b/doc/load_store_unit.rst index 8a2664f0..e7611503 100644 --- a/doc/load_store_unit.rst +++ b/doc/load_store_unit.rst @@ -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 diff --git a/doc/requirements.txt b/doc/requirements.txt index a0700776..daa69718 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,3 +1,4 @@ setuptools_scm -sphinx +sphinx>=1.8 sphinx_rtd_theme +git+https://github.com/wallento/sphinx-wavedrom