本帖最后由 轩辕志瑜 于 2024-8-20 19:58 编辑
找些开源cpu的rtl代码和讲解cpu芯片开发的视频看看。
用 https://github.com/darklife/darkriscv 这个项目举个例子:
config.vh(参数配置定义文件)
- /*
- * Copyright (c) 2018, Marcelo Samsoniuk
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- //`timescale 1ns / 1ps
- // to port to a new board, use TESTMODE to test:
- // - the reset button is working
- // - the LED is blinking at 1Hz
- // - the UART is looped
- //`define __TESTMODE__
- ////////////////////////////////////////////////////////////////////////////////
- // darkriscv configuration
- ////////////////////////////////////////////////////////////////////////////////
- // pipeline stages:
- //
- // 2-stage version: core and memory in different clock edges result in less
- // clock performance, but less losses when the program counter changes
- // (pipeline flush = 1 clock). Works like a 4-stage pipeline and remember
- // the 68040 clock scheme, with instruction per clock = 1. alternatively,
- // it is possible work w/ 1 wait-state and 1 clock edge, but with a penalty
- // in performance (instruction per clock = 0.5).
- //
- // 3-stage version: core and memory in the same clock edge require one extra
- // stage in the pipeline, but keep a good performance most of time
- // (instruction per clock = 1). of course, read operations require 1
- // wait-state, which means sometimes the read performance is reduced.
- `define __3STAGE__
- // RV32I vs RV32E:
- //
- // The difference between the RV32I and RV32E regarding the logic space is
- // minimal in typical applications with modern 5 or 6 input LUT based FPGAs,
- // but the RV32E is better with old 4 input LUT based FPGAs.
- `define __RV32E__
- // muti-threading support:
- //
- // Decreases clock performance by 20% (80MHz), but enables two or more
- // contexts (threads) in the core. The threads work in symmetrical way,
- // which means that they will start with the same exactly core parameters
- // (same initial PC, same initial SP, etc). The boot.s code is designed
- // to handle this difference and set each thread to different
- // applications.
- // Notes:
- // a) threading is currently supported only in the 3-stage pipeline version.
- // b) the old experimental "interrupt mode" was removed, which means that
- // the multi-thread mode does not make anything "visible" other than
- // increment the gpio register.
- // c) the threading in the non-interrupt mode switches when the program flow
- // changes, i.e. every jal instruction. When the core is idle, it is
- // probably in a jal loop.
- // The number of threads must be 2**n (i.e. THREADS = 3 means 8 threads)
- //`define __THREADS__ 3
- // mac instruction:
- //
- // The mac instruction is similar to other register to register
- // instructions, but with a different opcode 7'h1111111. the format is mac
- // rd,r1,r2, but is not currently possible encode in asm, by this way it is
- // available in licb as int mac(int rd, short r1, short r2). Although it
- // can be used to accelerate the mul/div operations, the mac operation is
- // designed for DSP applications. with some effort (low level machine
- // code), it is possible peak 100MMAC/s @100MHz.
- //`define __MAC16X16__
- // interrupt support
- //
- // The interrupt support in the core uses the machine registers mtvec and
- // mepc, which means support the control special register instruction csrrw,
- // in a way that is possible read/write the mtvec and mepc.
- // the interrupt itself works like the thread switch, with the difference
- // that:
- // a) the PC will be saved in the mepc register
- // b)the PC will receive the mtvec value
- // c) single interrupt, which means that the mtvec offset is always zero
- // The interrupt support cannot be used with threading (because makes no
- // much sense?)... also, it requires the 3 stage pipeline (again, makes no
- // much sense use it with the 2-stage pipeline).
- //`define __INTERRUPT__
- // ebreak support
- //
- // ebreak enable live debug w/ gdb, with break points, single-step, etc...
- // it basically consists in a single instruction that replace the normal
- // instruction, so an exception will be triggered, which is like an interrupt,
- // but with no real interrupt source.
- //`define __EBREAK__
- // CSR support
- //
- // enable this to use CSR registers... INTERRUPT and EBREAK use this in
- // order to read some special exception registers. Also, THREADS use this in
- // order to identify the core number.
- //`define __CSR__
- // instruction trace:
- //
- // prints the PC, the respective instruction and some useful information,
- // skipping halt and flush, in order to track the instruction execution
- // sequence. traces are very useful to debug, since is possible dump the
- // traces from a working core in order to debug a non-working core. when
- // trace is enabled, the UART print is blocked, also, the trace does not
- // dump data when the core is in reset.
- // the trace file is stored on "sim/darksocv.txt"
- //`define __TRACE__
- //`define __TRACEFULL__
- // performance measurement:
- //
- // The performance measurement can be done in the simulation level by
- // eabling the __PERFMETER__ define, in order to check how the clock cycles
- // are used in the core. The report is displayed when the FINISH_REQ signal
- // is actived by the UART.
- // the performance counters does not count when the core is in reset.
- `define __PERFMETER__
- // initial PC
- //
- // Typically, the PC is set [by HW] to address 0, representing the start of
- // ROM memory and the SP is set [by SW] to the final of RAM memory. In the
- // linker, the start of ROM memory matches with the .text area, which is
- // defined in the boot.c code and the start of RAM memory matches with the
- // .data and other volatile data, in a way that the stack can be positioned
- // in the top of RAM and does not match with the .data.
- `define __RESETPC__ 32'd0
- ////////////////////////////////////////////////////////////////////////////////
- // darksocv configuration:
- ////////////////////////////////////////////////////////////////////////////////
- // harvard architecture
- //
- // darkriscv core is *always* harvard, but it possible multiplex the instr.
- // and data buses over the time on the SoC level, in a way that it mimics a
- // classic von neumann architecture, which is useful for single-port memory,
- // such as SDRAMs, PSRAM, etc. when multiplexed, the instruction fetch turns
- // to be very slow, so caches are essential with this scenario!
- //`define __HARVARD__
- // cache depth
- //
- // when enabled, the caches will try map and store the read operations, in a
- // way that future read operations in the same address will be faster! it is
- // specially applicable to non-harvard SoC configuration, since that the
- // harvard SoC configuration is faster than the cache!
- // the cache depth N means that the each cache will be 32-bit x 2^N
- `define __LUTCACHE__
- `define __CDEPTH__ 6
- `define __ICACHE__
- `define __DCACHE__
- // interactive simulation:
- //
- // When enabled, will trick the simulator in order to enable interactive
- // access via the stdin, in a way that is possible type interactive commands,
- // which will make your simulator crazy! unfortunately, it works only with
- // iverilog... at least, Xilinx ISIM does not liket the $fgetc()
- //`define __INTERACTIVE__
- // icarus register debug:
- //
- // As most people observed, the icarus verilog does not dump the register
- // bank because icarus does not dump arrays by default. However, it is possible
- // activate this special option in order to dump the register bank. This
- // makes no effect in other simulators, but it appears as a warning.
- //`define __REGDUMP__
- // memory size:
- //
- // The current test firmware requires 8KB of memory, but it depends of the
- // memory layout: whenthe I-bus and D-bus are both attached in the same BRAM,
- // it is possible assume that 8kB is enough, but when the I-bus and D-bus are
- // attached to separate memories, the I-BRAM requires around 5KB and the
- // D-BRAM requires about 1.5KB. A safe solution is just simply and set the
- // size as the same.
- // The size is defined as 2**MLEN, i.e. the address bits used in the memory.
- // WARNING: this setup must match with the src/darksocv.ld.src file!
- `define MLEN 15 // MEM[14:0] -> 32KBytes LENGTH = 0x8000 for coremark!
- // read-modify-write cycle:
- //
- // Generate RMW cycles when writing in the memory. This option basically
- // makes the read and write cycle symmetric and may work better in the cases
- // when the 32-bit memory does not support separate write enables for
- // separate 16-bit and 8-bit words. Typically, the RMW cycle results in a
- // decrease of 5% in the performance (not the clock, but the instruction
- // pipeline eficiency) due to memory wait-states.
- //`define __RMW_CYCLE__
- // bram wait states
- //
- // to simulate high latency memories, is possible set the number of wait-states
- // for bram here! case not configured, wait-states defaults to 1.
- //`define __WAITSTATE__ 3
- // UART speed is set in bits per second, typically 115200 bps:
- //`define __UARTSPEED__ 115200
- // UART queue:
- //
- // Optional RX/TX queue for communication oriented applications. The concept
- // foreseen 256 bytes for TX and RX, in a way that frames up to 128 bytes can
- // be easily exchanged via UART.
- //`define __UARTQUEUE__
- ////////////////////////////////////////////////////////////////////////////////
- // board definition:
- ////////////////////////////////////////////////////////////////////////////////
- // The board is automatically defined in the xst/xise files via Makefile or
- // ISE. Case it is not the case, please define you board name here:
- //`define AVNET_MICROBOARD_LX9
- //`define XILINX_AC701_A200
- //`define QMTECH_SDRAM_LX16
- // the following defines are automatically defined:
- `ifdef __ICARUS__
- `define SIMULATION 1
- `endif
- `ifdef XILINX_ISIM
- `define SIMULATION 2
- `endif
- `ifdef MODEL_TECH
- `define SIMULATION 3
- `endif
- `ifdef XILINX_SIMULATOR
- `define SIMULATION 4
- `endif
- // the board definition is done on the tool, otherwise we assume simulation
- `ifdef AVNET_MICROBOARD_LX9
- `define BOARD_ID 1
- //`define BOARD_CK 100000000
- //`define BOARD_CK 66666666
- //`define BOARD_CK 40000000
- // example of DCM logic:
- `define BOARD_CK_REF 100000000
- `define BOARD_CK_MUL 6
- `ifdef __3STAGE__
- `define BOARD_CK_DIV 6 // 3-stage, 1-ws, 9=66MHz 6=100MHz
- `else
- `define BOARD_CK_DIV 9 // 2-stage, 1-ws, 9=66MHz 6=100MHz
- `endif
- `define XILINX6CLK 1
- `endif
- `ifdef XILINX_AC701_A200
- `define BOARD_ID 2
- //`define BOARD_CK 90000000
- `define BOARD_CK_REF 90000000
- `define BOARD_CK_MUL 4
- `define BOARD_CK_DIV 2
- `endif
- `ifdef QMTECH_SDRAM_LX16
- `define BOARD_ID 3
- `define BOARD_CK_REF 50000000
- `define BOARD_CK_MUL 4
- `define BOARD_CK_DIV 2
- `define INVRES 1
- `define XILINX6CLK 1
- `endif
- `ifdef QMTECH_SPARTAN7_S15
- `define BOARD_ID 4
- `define BOARD_CK_REF 50000000
- `define BOARD_CK_MUL 20
- `define BOARD_CK_DIV 10
- `define XILINX7CLK 1
- `define VIVADO 1
- `define INVRES 1
- `endif
- `ifdef LATTICE_BREVIA2_XP2
- `define BOARD_ID 5
- `define BOARD_CK 50000000
- `define INVRES 1
- `endif
- `ifdef LATTICE_ECP5_COLORLIGHTI9
- `define LATTICE_ECP5_PLL_REF25MHZ 1
- `define BOARD_ID 14
- `define BOARD_CK 125_000_000 // cause we use a pll with 25MHz ref clks
- `define INVRES 1
- `endif
- `ifdef LATTICE_ECP5_COLORLIGHTI5
- `define LATTICE_ECP5_PLL_REF25MHZ 1
- `define BOARD_ID 15
- `define BOARD_CK 125_000_000 // cause we use a pll with 25MHz ref clks
- `define INVRES 1
- `endif
- `ifdef LATTICE_ECP5_ULX3S
- `define LATTICE_ECP5_PLL_REF25MHZ 1
- `define BOARD_ID 16
- `define BOARD_CK 125_000_000 // cause we use a pll with 25MHz ref clks
- `define INVRES 1
- `endif
- `ifdef LATTICE_ICE40_BREAKOUT_HX8K
- `define BOARD_ID 17
- `define BOARD_CK 65_000_000 // cause we use a pll with 25MHz ref clks
- `define INVRES 1
- `endif
- `ifdef PISWORDS_RS485_LX9
- `define BOARD_ID 6
- `define BOARD_CK_REF 50000000
- `define BOARD_CK_MUL 4
- `define BOARD_CK_DIV 2
- `define INVRES 1
- `define XILINX6CLK 1
- `endif
- `ifdef DIGILENT_SPARTAN3_S200
- `define BOARD_ID 7
- `define BOARD_CK 50000000
- `define __RMW_CYCLE__
- `endif
- `ifdef ALIEXPRESS_HPC40GBE_K420
- `define BOARD_ID 8
- //`define BOARD_CK 200000000
- `define BOARD_CK_REF 100000000
- `define BOARD_CK_MUL 12
- `define BOARD_CK_DIV 5
- `define XILINX7CLK 1
- `define INVRES 1
- `endif
- `ifdef QMTECH_ARTIX7_A35
- `define BOARD_ID 9
- `define BOARD_CK_REF 50000000
- `define BOARD_CK_MUL 20
- `define BOARD_CK_DIV 10
- `define XILINX7CLK 1
- `define VIVADO 1
- `define INVRES 1
- `endif
- `ifdef ALIEXPRESS_HPC40GBE_XKCU040
- `define BOARD_ID 10
- //`define BOARD_CK 200000000
- `define BOARD_CK_REF 100000000
- `define BOARD_CK_MUL 8 // x8/2 = 400MHZ (overclock!)
- `define BOARD_CK_DIV 2 // vivado reco. = 250MHz
- `define XILINX7CLK 1
- `define INVRES 1
- `endif
- `ifdef PAPILIO_DUO_LOGICSTART
- `define BOARD_ID 11
- `define BOARD_CK_REF 32000000
- `define BOARD_CK_MUL 2
- `define BOARD_CK_DIV 2
- `define XILINX6CLK 1
- `endif
- `ifdef QMTECH_KINTEX7_K325
- `define BOARD_ID 12
- `define BOARD_CK_REF 50000000
- `define BOARD_CK_MUL 20
- `define BOARD_CK_DIV 4
- `define XILINX7CLK 1
- `define INVRES 1
- `endif
- `ifdef SCARAB_MINISPARTAN6_PLUS_LX9
- `define BOARD_ID 13
- `define BOARD_CK_REF 50000000
- `define BOARD_CK_MUL 4
- `define BOARD_CK_DIV 2
- // `define INVRES 0
- `define XILINX6CLK 1
- `endif
- `ifdef QMTECH_CYCLONE10_CL016
- `define BOARD_ID 17
- `define BOARD_CK 50000000
- `define INVRES 1
- `define MIFBRAM 1
- `define __RMW_CYCLE__
- `endif
- `ifdef PISSWORDS_CH34X_LX16
- `define BOARD_ID 18
- `ifdef __3STAGE__
- `define BOARD_CK_REF 50000000
- `define BOARD_CK_MUL 4
- `define BOARD_CK_DIV 2
- `define XILINX6CLK 1
- `else
- `define BOARD_CK 50000000
- `endif
- `define INVRES 1
- `define __SDRAM__ 1
- `endif
- `ifndef BOARD_ID
- `define BOARD_ID 0
- `define BOARD_CK 100000000
- //`define __SDRAM__ 1
- `endif
- `ifdef BOARD_CK_REF
- `define BOARD_CK (`BOARD_CK_REF * `BOARD_CK_MUL / `BOARD_CK_DIV)
- `endif
- // darkuart baudrate automtically calculated according to board clock:
- `ifndef __UARTSPEED__
- `define __UARTSPEED__ 115200
- `endif
- `define __BAUD__ ((`BOARD_CK/`__UARTSPEED__))
- // register number depends of CPU type RV32[EI] and number of threads
- `ifdef __THREADS__
- `ifdef __RV32E__
- `define RLEN 16*(2**`__THREADS__)
- `else
- `define RLEN 32*(2**`__THREADS__)
- `endif
-
- `define __CSR__
- `else
- `ifdef __RV32E__
- `define RLEN 16
- `else
- `define RLEN 32
- `endif
- `endif
- `ifdef __INTERRUPT__
- `define __CSR__
- `endif
- `ifdef __EBREAK__
- `define __CSR__
- `endif
复制代码
darkriscv.v (CPU核心模块)
- /*
- * Copyright (c) 2018, Marcelo Samsoniuk
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- `timescale 1ns / 1ps
- // implemented opcodes:
- `define LUI 7'b01101_11 // lui rd,imm[31:12]
- `define AUIPC 7'b00101_11 // auipc rd,imm[31:12]
- `define JAL 7'b11011_11 // jal rd,imm[xxxxx]
- `define JALR 7'b11001_11 // jalr rd,rs1,imm[11:0]
- `define BCC 7'b11000_11 // bcc rs1,rs2,imm[12:1]
- `define LCC 7'b00000_11 // lxx rd,rs1,imm[11:0]
- `define SCC 7'b01000_11 // sxx rs1,rs2,imm[11:0]
- `define MCC 7'b00100_11 // xxxi rd,rs1,imm[11:0]
- `define RCC 7'b01100_11 // xxx rd,rs1,rs2
- `define SYS 7'b11100_11 // exx, csrxx, mret
- // proprietary extension (custom-0)
- `define CUS 7'b00010_11 // cus rd,rs1,rs2,fc3,fct5
- // not implemented opcodes:
- //`define FCC 7'b00011_11 // fencex
- // configuration file
- `include "../rtl/config.vh"
- module darkriscv
- #(
- parameter CPTR = 0
- )
- (
- input CLK, // clock
- input RES, // reset
- input HLT, // halt
- `ifdef __INTERRUPT__
- input IRQ, // interrupt request
- `endif
- input [31:0] IDATA, // instruction data bus
- output [31:0] IADDR, // instruction addr bus
- input [31:0] DATAI, // data bus (input)
- output [31:0] DATAO, // data bus (output)
- output [31:0] DADDR, // addr bus
- output [ 2:0] DLEN, // data length
- output DRW, // data read/write
- output DRD, // data read
- output DWR, // data write
- output DAS, // address strobe
-
- `ifdef SIMULATION
- input ESIMREQ, // end simulation req
- output reg ESIMACK = 0, // end simulation ack
- `endif
- output [3:0] DEBUG // old-school osciloscope based debug! :)
- );
- // dummy 32-bit words w/ all-0s and all-1s:
- wire [31:0] ALL0 = 0;
- wire [31:0] ALL1 = -1;
- reg XRES = 1;
- `ifdef __THREADS__
- reg [`__THREADS__-1:0] TPTR = 0; // thread ptr
- `endif
- // pipeline flow control on HLT!
- reg HLT2 = 0;
- reg [31:0] IDATA2 = 0;
- always@(posedge CLK)
- begin
- HLT2 <= HLT;
-
- if(HLT2^HLT) IDATA2 <= IDATA;
- end
- wire[31:0] IDATAX = XRES ? 0 : HLT2 ? IDATA2 : IDATA;
- // decode: IDATA is break apart as described in the RV32I specification
- `ifdef __3STAGE__
- reg [31:0] XIDATA;
- reg XLUI, XAUIPC, XJAL, XJALR, XBCC, XLCC, XSCC, XMCC, XRCC, XCUS, XSYS; //, XFCC, XSYS;
- reg [31:0] XSIMM;
- reg [31:0] XUIMM;
- always@(posedge CLK)
- begin
- XIDATA <= HLT ? XIDATA : IDATAX;
- XLUI <= HLT ? XLUI : IDATAX[6:0]==`LUI;
- XAUIPC <= HLT ? XAUIPC : IDATAX[6:0]==`AUIPC;
- XJAL <= HLT ? XJAL : IDATAX[6:0]==`JAL;
- XJALR <= HLT ? XJALR : IDATAX[6:0]==`JALR;
- XBCC <= HLT ? XBCC : IDATAX[6:0]==`BCC;
- XLCC <= HLT ? XLCC : IDATAX[6:0]==`LCC;
- XSCC <= HLT ? XSCC : IDATAX[6:0]==`SCC;
- XMCC <= HLT ? XMCC : IDATAX[6:0]==`MCC;
- XRCC <= HLT ? XRCC : IDATAX[6:0]==`RCC;
- XCUS <= HLT ? XRCC : IDATAX[6:0]==`CUS;
- //XFCC <= HLT ? XFCC : IDATAX[6:0]==`FCC;
- XSYS <= HLT ? XSYS : IDATAX[6:0]==`SYS;
- // signal extended immediate, according to the instruction type:
- XSIMM <= HLT ? XSIMM :
- IDATAX[6:0]==`SCC ? { IDATAX[31] ? ALL1[31:12]:ALL0[31:12], IDATAX[31:25],IDATAX[11:7] } : // s-type
- IDATAX[6:0]==`BCC ? { IDATAX[31] ? ALL1[31:13]:ALL0[31:13], IDATAX[31],IDATAX[7],IDATAX[30:25],IDATAX[11:8],ALL0[0] } : // b-type
- IDATAX[6:0]==`JAL ? { IDATAX[31] ? ALL1[31:21]:ALL0[31:21], IDATAX[31], IDATAX[19:12], IDATAX[20], IDATAX[30:21], ALL0[0] } : // j-type
- IDATAX[6:0]==`LUI||
- IDATAX[6:0]==`AUIPC ? { IDATAX[31:12], ALL0[11:0] } : // u-type
- { IDATAX[31] ? ALL1[31:12]:ALL0[31:12], IDATAX[31:20] }; // i-type
- // non-signal extended immediate, according to the instruction type:
- XUIMM <= HLT ? XUIMM :
- IDATAX[6:0]==`SCC ? { ALL0[31:12], IDATAX[31:25],IDATAX[11:7] } : // s-type
- IDATAX[6:0]==`BCC ? { ALL0[31:13], IDATAX[31],IDATAX[7],IDATAX[30:25],IDATAX[11:8],ALL0[0] } : // b-type
- IDATAX[6:0]==`JAL ? { ALL0[31:21], IDATAX[31], IDATAX[19:12], IDATAX[20], IDATAX[30:21], ALL0[0] } : // j-type
- IDATAX[6:0]==`LUI||
- IDATAX[6:0]==`AUIPC ? { IDATAX[31:12], ALL0[11:0] } : // u-type
- { ALL0[31:12], IDATAX[31:20] }; // i-type
- end
- reg [1:0] FLUSH = -1; // flush instruction pipeline
- `else
- wire [31:0] XIDATA;
- wire XLUI, XAUIPC, XJAL, XJALR, XBCC, XLCC, XSCC, XMCC, XRCC, XCUS, XSYS; //, XFCC, XSYS;
- wire [31:0] XSIMM;
- wire [31:0] XUIMM;
- assign XIDATA = IDATAX;
- assign XLUI = IDATAX[6:0]==`LUI;
- assign XAUIPC = IDATAX[6:0]==`AUIPC;
- assign XJAL = IDATAX[6:0]==`JAL;
- assign XJALR = IDATAX[6:0]==`JALR;
- assign XBCC = IDATAX[6:0]==`BCC;
- assign XLCC = IDATAX[6:0]==`LCC;
- assign XSCC = IDATAX[6:0]==`SCC;
- assign XMCC = IDATAX[6:0]==`MCC;
- assign XRCC = IDATAX[6:0]==`RCC;
- assign XCUS = IDATAX[6:0]==`CUS;
- //assign XFCC <= IDATAX[6:0]==`FCC;
- assign XSYS = IDATAX[6:0]==`SYS;
- // signal extended immediate, according to the instruction type:
- assign XSIMM =
- IDATAX[6:0]==`SCC ? { IDATAX[31] ? ALL1[31:12]:ALL0[31:12], IDATAX[31:25],IDATAX[11:7] } : // s-type
- IDATAX[6:0]==`BCC ? { IDATAX[31] ? ALL1[31:13]:ALL0[31:13], IDATAX[31],IDATAX[7],IDATAX[30:25],IDATAX[11:8],ALL0[0] } : // b-type
- IDATAX[6:0]==`JAL ? { IDATAX[31] ? ALL1[31:21]:ALL0[31:21], IDATAX[31], IDATAX[19:12], IDATAX[20], IDATAX[30:21], ALL0[0] } : // j-type
- IDATAX[6:0]==`LUI||
- IDATAX[6:0]==`AUIPC ? { IDATAX[31:12], ALL0[11:0] } : // u-type
- { IDATAX[31] ? ALL1[31:12]:ALL0[31:12], IDATAX[31:20] }; // i-type
- // non-signal extended immediate, according to the instruction type:
- assign XUIMM =
- IDATAX[6:0]==`SCC ? { ALL0[31:12], IDATAX[31:25],IDATAX[11:7] } : // s-type
- IDATAX[6:0]==`BCC ? { ALL0[31:13], IDATAX[31],IDATAX[7],IDATAX[30:25],IDATAX[11:8],ALL0[0] } : // b-type
- IDATAX[6:0]==`JAL ? { ALL0[31:21], IDATAX[31], IDATAX[19:12], IDATAX[20], IDATAX[30:21], ALL0[0] } : // j-type
- IDATAX[6:0]==`LUI||
- IDATAX[6:0]==`AUIPC ? { IDATAX[31:12], ALL0[11:0] } : // u-type
- { ALL0[31:12], IDATAX[31:20] }; // i-type
- reg FLUSH = -1; // flush instruction pipeline
- `endif
- `ifdef __THREADS__
- `ifdef __RV32E__
- reg [`__THREADS__-1:0] RESMODE = -1;
- wire [`__THREADS__+3:0] DPTR = XRES ? { RESMODE, 4'd0 } : { TPTR, XIDATA[10: 7] }; // set SP_RESET when RES==1
- wire [`__THREADS__+3:0] S1PTR = { TPTR, XIDATA[18:15] };
- wire [`__THREADS__+3:0] S2PTR = { TPTR, XIDATA[23:20] };
- `else
- reg [`__THREADS__-1:0] RESMODE = -1;
- wire [`__THREADS__+4:0] DPTR = XRES ? { RESMODE, 5'd0 } : { TPTR, XIDATA[11: 7] }; // set SP_RESET when RES==1
- wire [`__THREADS__+4:0] S1PTR = { TPTR, XIDATA[19:15] };
- wire [`__THREADS__+4:0] S2PTR = { TPTR, XIDATA[24:20] };
- `endif
- `else
- `ifdef __RV32E__
- wire [3:0] DPTR = XIDATA[10: 7]; // set SP_RESET when RES==1
- wire [3:0] S1PTR = XIDATA[18:15];
- wire [3:0] S2PTR = XIDATA[23:20];
- `else
- wire [4:0] DPTR = XIDATA[11: 7]; // set SP_RESET when RES==1
- wire [4:0] S1PTR = XIDATA[19:15];
- wire [4:0] S2PTR = XIDATA[24:20];
- `endif
- `endif
- wire [6:0] OPCODE = FLUSH ? 0 : XIDATA[6:0];
- wire [2:0] FCT3 = XIDATA[14:12];
- wire [6:0] FCT7 = XIDATA[31:25];
- wire [31:0] SIMM = XSIMM;
- wire [31:0] UIMM = XUIMM;
- // main opcode decoder:
- wire LUI = FLUSH ? 0 : XLUI; // OPCODE==7'b0110111;
- wire AUIPC = FLUSH ? 0 : XAUIPC; // OPCODE==7'b0010111;
- wire JAL = FLUSH ? 0 : XJAL; // OPCODE==7'b1101111;
- wire JALR = FLUSH ? 0 : XJALR; // OPCODE==7'b1100111;
- wire BCC = FLUSH ? 0 : XBCC; // OPCODE==7'b1100011; //FCT3
- wire LCC = FLUSH ? 0 : XLCC; // OPCODE==7'b0000011; //FCT3
- wire SCC = FLUSH ? 0 : XSCC; // OPCODE==7'b0100011; //FCT3
- wire MCC = FLUSH ? 0 : XMCC; // OPCODE==7'b0010011; //FCT3
- wire RCC = FLUSH ? 0 : XRCC; // OPCODE==7'b0110011; //FCT3
- wire CUS = FLUSH ? 0 : XCUS; // OPCODE==7'b0110011; //FCT3
- //wire FCC = FLUSH ? 0 : XFCC; // OPCODE==7'b0001111; //FCT3
- wire SYS = FLUSH ? 0 : XSYS; // OPCODE==7'b1110011; //FCT3
- `ifdef __THREADS__
- `ifdef __3STAGE__
- reg [31:0] NXPC2 [0:(2**`__THREADS__)-1]; // 32-bit program counter t+2
- `endif
- `else
- `ifdef __3STAGE__
- reg [31:0] NXPC2; // 32-bit program counter t+2
- `endif
- `endif
- reg [31:0] REGS [0:`RLEN-1]; // general-purpose 32x32-bit registers (s1)
- reg [31:0] NXPC; // 32-bit program counter t+1
- reg [31:0] PC; // 32-bit program counter t+0
- `ifdef SIMULATION
- integer i;
-
- initial for(i=0;i!=`RLEN;i=i+1) REGS[i] = 0;
- `endif
- // source-1 and source-1 register selection
- wire [31:0] U1REG = REGS[S1PTR];
- wire [31:0] U2REG = REGS[S2PTR];
- wire signed [31:0] S1REG = U1REG;
- wire signed [31:0] S2REG = U2REG;
- // L-group of instructions (OPCODE==7'b0000011)
- wire [31:0] LDATA = FCT3[1:0]==0 ? { FCT3[2]==0&&DATAI[ 7] ? ALL1[31: 8]:ALL0[31: 8] , DATAI[ 7: 0] } :
- FCT3[1:0]==1 ? { FCT3[2]==0&&DATAI[15] ? ALL1[31:16]:ALL0[31:16] , DATAI[15: 0] } :
- DATAI;
- // C-group: CSRRW
- `ifdef __CSR__
- wire CSRX = SYS && FCT3[1:0];
- `ifdef __INTERRUPT__
- reg [31:0] MSTATUS = 0;
- reg [31:0] MSCRATCH = 0;
- reg [31:0] MCAUSE = 0;
- reg [31:0] MEPC = 0;
- reg [31:0] MTVEC = 0;
- reg [31:0] MIE = 0;
- reg [31:0] MIP = 0;
- wire MRET = SYS && FCT3==0 && XIDATA[31:20]==12'b001100000010;
- `endif
- `ifdef __EBREAK__
- reg [31:0] SSTATUS = 0;
- reg [31:0] SSCRATCH = 0;
- reg [31:0] SCAUSE = 0;
- reg [31:0] SEPC = 0;
- reg [31:0] STVEC = 0;
- reg [31:0] SIE = 0;
- reg [31:0] SIP = 0;
- wire EBRK = SYS && FCT3==0 && XIDATA[31:20]==12'b000000000001;
- wire SRET = SYS && FCT3==0 && XIDATA[31:20]==12'b000100000010;
- `endif
- wire [31:0] CRDATA =
- `ifdef __THREADS__
- XIDATA[31:20]==12'hf14 ? { CPTR, TPTR } : // core/thread number
- `else
- XIDATA[31:20]==12'hf14 ? CPTR : // core number
- `endif
- `ifdef __INTERRUPT__
- XIDATA[31:20]==12'h344 ? MIP : // machine interrupt pending
- XIDATA[31:20]==12'h304 ? MIE : // machine interrupt enable
- XIDATA[31:20]==12'h341 ? MEPC : // machine exception PC
- XIDATA[31:20]==12'h342 ? MCAUSE : // machine expection cause
- XIDATA[31:20]==12'h305 ? MTVEC : // machine vector table
- XIDATA[31:20]==12'h300 ? MSTATUS : // machine status
- XIDATA[31:20]==12'h340 ? MSCRATCH : // machine status
- `endif
- `ifdef __EBREAK__
- XIDATA[31:20]==12'h144 ? SIP : // machine interrupt pending
- XIDATA[31:20]==12'h104 ? SIE : // machine interrupt enable
- XIDATA[31:20]==12'h141 ? SEPC : // machine exception PC
- XIDATA[31:20]==12'h142 ? SCAUSE : // machine expection cause
- XIDATA[31:20]==12'h105 ? STVEC : // machine vector table
- XIDATA[31:20]==12'h100 ? SSTATUS : // machine status
- XIDATA[31:20]==12'h140 ? SSCRATCH : // machine status
- `endif
- 0; // unknown
- wire [31:0] WRDATA = FCT3[1:0]==3 ? (CRDATA & ~CRMASK) : FCT3[1:0]==2 ? (CRDATA | CRMASK) : CRMASK;
- wire [31:0] CRMASK = FCT3[2] ? XIDATA[19:15] : U1REG;
-
- `endif
- // RM-group of instructions (OPCODEs==7'b0010011/7'b0110011), merged! src=immediate(M)/register(R)
- wire signed [31:0] S2REGX = XMCC ? SIMM : S2REG;
- wire [31:0] U2REGX = XMCC ? UIMM : U2REG;
- wire [31:0] RMDATA = FCT3==7 ? U1REG&S2REGX :
- FCT3==6 ? U1REG|S2REGX :
- FCT3==4 ? U1REG^S2REGX :
- FCT3==3 ? U1REG<U2REGX : // unsigned
- FCT3==2 ? S1REG<S2REGX : // signed
- FCT3==0 ? (XRCC&&FCT7[5] ? U1REG-S2REGX : U1REG+S2REGX) :
- FCT3==1 ? S1REG<<U2REGX[4:0] :
- //FCT3==5 ?
- !FCT7[5] ? S1REG>>U2REGX[4:0] :
- `ifdef MODEL_TECH
- -((-S1REG)>>U2REGX[4:0]); // workaround for modelsim
- `else
- $signed(S1REG)>>>U2REGX[4:0]; // (FCT7[5] ? U1REG>>>U2REG[4:0] :
- `endif
- `ifdef __MAC16X16__
- // MAC instruction rd += s1*s2 (OPCODE==7'b1111111)
- //
- // 0000000 01100 01011 100 01100 0110011 xor a2,a1,a2
- // 0000000 01010 01100 000 01010 0110011 add a0,a2,a0
- // 0000000 01100 01011 000 01010 0001011 mac a0,a1,a2
- //
- // 0000 0000 1100 0101 1000 0101 0000 1011 = 00c5850b
- wire MAC = CUS && FCT3==0;
- wire signed [15:0] K1TMP = S1REG[15:0];
- wire signed [15:0] K2TMP = S2REG[15:0];
- wire signed [31:0] KDATA = K1TMP*K2TMP;
- `endif
- // J/B-group of instructions (OPCODE==7'b1100011)
- wire BMUX = FCT3==7 && U1REG>=U2REG || // bgeu
- FCT3==6 && U1REG< U2REGX || // bltu
- FCT3==5 && S1REG>=S2REG || // bge
- FCT3==4 && S1REG< S2REGX || // blt
- FCT3==1 && U1REG!=U2REGX || // bne
- FCT3==0 && U1REG==U2REGX; // beq
- wire [31:0] PCSIMM = PC+SIMM;
- wire JREQ = JAL||JALR||(BCC && BMUX);
- wire [31:0] JVAL = JALR ? DADDR : PCSIMM; // SIMM + (JALR ? U1REG : PC);
- always@(posedge CLK)
- begin
- `ifdef __THREADS__
- RESMODE <= RES ? -1 : RESMODE ? RESMODE-1 : 0;
- XRES <= |RESMODE;
- `else
- XRES <= RES;
- `endif
- `ifdef __3STAGE__
- FLUSH <= XRES ? 2 : HLT ? FLUSH : // reset and halt
- FLUSH ? FLUSH-1 :
- `ifdef __EBREAK__
- EBRK ? 2 : // ebreak jmps to system level, i.e. sepc = PC; PC = stvec
- SRET ? 2 : // sret returns from system level, i.e. PC = sepc
- `endif
- `ifdef __INTERRUPT__
- MRET ? 2 : // mret returns from interrupt, i.e. PC = mepc
- `endif
- JREQ ? 2 : 0; // flush the pipeline!
- `else
- FLUSH <= XRES ? 1 : HLT ? FLUSH : // reset and halt
- JREQ; // flush the pipeline!
- `endif
- `ifdef __INTERRUPT__
- `ifdef __EBREAK__
- MIP[11] <= IRQ&&MSTATUS[3]&&MIE[11]&&!SIP[1];
- `else
- MIP[11] <= IRQ&&MSTATUS[3]&&MIE[11];
- `endif
-
- if(XRES)
- begin
- MTVEC <= 0;
- MEPC <= 0;
- MIE <= 0;
- MCAUSE <= 0;
- MSTATUS <= 0;
- MSCRATCH <= 0;
- end
- else
- if(!HLT||!FLUSH)
- begin
- if(CSRX)
- begin
- case(XIDATA[31:20])
- 12'h300: MSTATUS <= WRDATA;
- 12'h340: MSCRATCH <= WRDATA;
- 12'h305: MTVEC <= WRDATA;
- 12'h341: MEPC <= WRDATA;
- 12'h304: MIE <= WRDATA;
- endcase
- end
- else
- if(MIP[11] && JREQ)
- begin
- MEPC <= JVAL; // interrupt saves the next PC!
- MSTATUS[3] <= 0; // no interrupts when handling ebreak!
- MSTATUS[7] <= MSTATUS[3]; // copy old MIE bit
- MCAUSE <= 32'h8000000b; // ext interrupt
- end
- else
- if(MRET)
- begin
- MSTATUS[3] <= MSTATUS[7]; // return last MIE bit
- end
- end
- `endif
- `ifdef __EBREAK__
-
- if(XRES)
- begin
- STVEC <= 0;
- SEPC <= 0;
- SIE <= 0;
- SIP <= 0;
- SCAUSE <= 0;
- SSTATUS <= 0;
- SSCRATCH <= 0;
- end
- else
- if(!HLT||!FLUSH)
- begin
- if(EBRK) // ebreak cannot be blocked!
- begin
- SEPC <= PC; // ebreak saves the current PC!
- SSTATUS[1] <= 0; // no interrupts when handling ebreak!
- SSTATUS[5] <= SSTATUS[1]; // copy old MIE bit
- SCAUSE <= 32'h00000003; // ebreak
- SIP[1] <= 1; // set when ebreak!
- end
- else
- if(CSRX)
- begin
- case(XIDATA[31:20])
- 12'h100: SSTATUS <= WRDATA;
- 12'h140: SSCRATCH <= WRDATA;
- 12'h105: STVEC <= WRDATA;
- 12'h141: SEPC <= WRDATA;
- 12'h104: SIE <= WRDATA;
- endcase
- end
- else
- if(SRET)
- begin
- SSTATUS[3] <= SSTATUS[7]; // return last MIE bit
- SIP[1] <= 0; //return from ebreak
- end
- end
-
- `endif
- `ifdef __RV32E__
- REGS[DPTR] <= XRES||DPTR[3:0]==0 ? 0 : // reset x0
- `else
- REGS[DPTR] <= XRES||DPTR[4:0]==0 ? 0 : // reset x0
- `endif
- HLT ? REGS[DPTR] : // halt
- LCC ? LDATA :
- AUIPC ? PCSIMM :
- JAL||
- JALR ? NXPC :
- LUI ? SIMM :
- MCC||RCC ? RMDATA:
- `ifdef __MAC16X16__
- MAC ? REGS[DPTR]+KDATA :
- `endif
- `ifdef __CSR__
- CSRX ? CRDATA :
- `endif
- REGS[DPTR];
- `ifdef __3STAGE__
- `ifdef __THREADS__
- NXPC <= /*XRES ? `__RESETPC__ :*/ HLT ? NXPC : NXPC2[TPTR];
- NXPC2[XRES ? RESMODE : TPTR] <= XRES ? `__RESETPC__ : HLT ? NXPC2[TPTR] : // reset and halt
- JREQ ? JVAL : // jmp/bra
- NXPC2[TPTR]+4; // normal flow
- TPTR <= XRES ? 0 : HLT ? TPTR : // reset and halt
- JAL /*JREQ*/ ? TPTR+1 : TPTR;
- //TPTR==0/*&& IREQ*/&&JREQ ? 1 : // wait pipeflush to switch to irq
- //TPTR==1/*&&!IREQ*/&&JREQ ? 0 : TPTR; // wait pipeflush to return from irq
- `else
- NXPC <= /*XRES ? `__RESETPC__ :*/ HLT ? NXPC : NXPC2;
- NXPC2 <= XRES ? `__RESETPC__ : HLT ? NXPC2 : // reset and halt
- `ifdef __EBREAK__
- SRET ? SEPC : // return from system call
- EBRK ? STVEC : // ebreak causes an system call
- `endif
- `ifdef __INTERRUPT__
- MRET ? MEPC : // return from interrupt
- MIP[11]&&JREQ ? MTVEC : // pending interrupt + pipeline flush
- `endif
- JREQ ? JVAL : // jmp/bra
- NXPC2+4; // normal flow
- `endif
- `else
- NXPC <= XRES ? `__RESETPC__ : HLT ? NXPC : // reset and halt
-
- `ifdef __EBREAK__
- MRET ? MEPC :
- EBRK ? MTVEC : // ebreak causes an interrupt
- `endif
- `ifdef __INTERRUPT__
- MRET ? MEPC :
- MIP[11]&&JREQ ? MTVEC : // pending interrupt + pipeline flush
- `endif
- JREQ ? JVAL : // jmp/bra
- NXPC+4; // normal flow
- `endif
- PC <= /*XRES ? `__RESETPC__ :*/ HLT ? PC : NXPC; // current program counter
- end
- // IO and memory interface
- assign DATAO = U2REG;
- assign DADDR = U1REG + SIMM;
- // based in the Scc and Lcc
- assign DRW = !SCC;
- assign DLEN[0] = (SCC||LCC)&&FCT3[1:0]==0; // byte
- assign DLEN[1] = (SCC||LCC)&&FCT3[1:0]==1; // word
- assign DLEN[2] = (SCC||LCC)&&FCT3[1:0]==2; // long
- assign DWR = SCC;
- assign DRD = LCC;
- assign DAS = SCC||LCC;
- `ifdef __3STAGE__
- `ifdef __THREADS__
- assign IADDR = NXPC2[TPTR];
- `else
- assign IADDR = NXPC2;
- `endif
- `else
- assign IADDR = NXPC;
- `endif
-
- `ifdef __INTERRUPT__
- assign DEBUG = { IRQ, MIP, MIE, MRET };
- `else
- assign DEBUG = { XRES, |FLUSH, SCC, LCC };
- `endif
- `ifdef SIMULATION
- `ifdef __PERFMETER__
- integer clocks=0, running=0, load=0, store=0, flush=0, halt=0;
- `ifdef __THREADS__
- integer thread[0:(2**`__THREADS__)-1],curtptr=0,cnttptr=0;
- integer j;
- initial for(j=0;j!=(2**`__THREADS__);j=j+1) thread[j] = 0;
- `endif
- always@(posedge CLK)
- begin
- if(!XRES)
- begin
- clocks = clocks+1;
- if(HLT)
- begin
- if(SCC) store = store+1;
- else if(LCC) load = load +1;
- else halt = halt +1;
- end
- else
- if(|FLUSH)
- begin
- flush=flush+1;
- end
- else
- begin
- `ifdef __THREADS__
- for(j=0;j!=(2**`__THREADS__);j=j+1)
- thread[j] = thread[j]+(j==TPTR?1:0);
- if(TPTR!=curtptr)
- begin
- curtptr = TPTR;
- cnttptr = cnttptr+1;
- end
- `endif
- running = running +1;
- end
- if(ESIMREQ)
- begin
- $display("****************************************************************************");
- $display("DarkRISCV Pipeline Report (%0d clocks, %0d instr, CPI = %.2f):",
- clocks,running,1.0*clocks/running);
- $display("core%0d: %0d%% run, %0d%% wait (%0d%% i-bus, %0d%% d-bus/rd, %0d%% d-bus/wr), %0d%% flush",
- CPTR,
- 100.0*running/clocks,
- 100.0*(load+store+halt)/clocks,
- 100.0*halt/clocks,
- 100.0*load/clocks,
- 100.0*store/clocks,
- 100.0*flush/clocks);
- `ifdef __THREADS__
- for(j=0;j!=(2**`__THREADS__);j=j+1) $display(" thread%0d: %0d%% running",j,100.0*thread[j]/clocks);
- $display("%0d thread switches, %0d clocks/threads",cnttptr,clocks/cnttptr);
- `endif
- $display("****************************************************************************");
- $finish();
- end
- end
- `ifdef __EBREAK__
- if(0 && !HLT&&!FLUSH&&EBRK)
- begin
- $display("breakpoint at %x",PC);
- $stop();
- end
- `endif
-
- if(!FLUSH && IDATA===32'dx)
- begin
- $display("invalid IDATA at %x",PC);
- $stop();
- end
-
- if(LCC&&!HLT&&!FLUSH&&( (DLEN==4 && DATAI[31:0]===32'dx)||
- (DLEN==2 && DATAI[15:0]===16'dx)||
- (DLEN==1 && DATAI[ 7:0]=== 8'dx)))
- begin
- $display("invalid DATAI@%x at %x",DADDR,PC);
- $stop();
- end
-
- `ifdef __TRACE__
- if(!XRES)
- begin
- `ifdef __TRACEFULL__
- if(FLUSH)
- $display("trace: %x:%x flushed",PC,XIDATA);
- else
- if(HLT)
- begin
- //$display("%x:%x %s halted %x:%x",PC,XIDATA,LCC?"lx":"sx",DADDR,LCC?LDATA:DATAO);
- $display("trace: %x:%x halted",PC,XIDATA);
- end
- else
- `else
- if(!FLUSH && !HLT)
- `endif
- begin
- case(XIDATA[6:0])
- `LUI: $display("trace: %x:%x lui %%x%0x,%0x", PC,XIDATA,DPTR,$signed(SIMM));
- `AUIPC: $display("trace: %x:%x auipc %%x%0x,PC[%0x]", PC,XIDATA,DPTR,$signed(SIMM));
- `JAL: $display("trace: %x:%x jal %%x%0x,%0x", PC,XIDATA,DPTR,$signed(SIMM));
- `JALR: $display("trace: %x:%x jalr %%x%0x,%%x%0x,%0d", PC,XIDATA,DPTR,S1PTR,$signed(SIMM));
- `BCC: $display("trace: %x:%x bcc %%x%0x,%%x%0x,PC[%0d]", PC,XIDATA,S1PTR,S2PTR,$signed(SIMM));
- `LCC: $display("trace: %x:%x lx %%x%0x,%%x%0x[%0d]\t%x:%x", PC,XIDATA,DPTR,S1PTR,$signed(SIMM),DADDR,LDATA);
- `SCC: $display("trace: %x:%x sx %%x%0x,%%x%0x[%0d]\t%x:%x", PC,XIDATA,DPTR,S1PTR,$signed(SIMM),DADDR,DATAO);
- `MCC: $display("trace: %x:%x alui %%x%0x,%%x%0x,%0d", PC,XIDATA,DPTR,S1PTR,$signed(SIMM));
- `RCC: $display("trace: %x:%x alu %%x%0x,%%x%0x,%%x%0x", PC,XIDATA,DPTR,S1PTR,S2PTR);
- `SYS: $display("trace: %x:%x sys (no decode)", PC,XIDATA);
- `CUS: $display("trace: %x:%x cus (no decode)", PC,XIDATA);
- default: $display("trace: %x:%x ??? (no decode)", PC,XIDATA);
- endcase
- end
- end
- `endif
-
- end
- `else
- always@(posedge CLK) if(ESIMREQ) ESIMACK <= 1;
- `endif
- `endif
- endmodule
复制代码
darkbridge.v (把cpu核心和L1缓存整合在一起的模块)
- /*
- * Copyright (c) 2018, Marcelo Samsoniuk
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- `timescale 1ns / 1ps
- `include "../rtl/config.vh"
- module darkbridge
- (
- input CLK, // clock
- input RES, // reset
- output HLT,
- `ifdef __INTERRUPT__
- input XIRQ,
- `endif
- // x-bus
- output XXDREQ,
- output XXWR,
- output XXRD,
- output [3:0] XXBE,
- output [31:0] XXADDR,
- output [31:0] XXATAO,
- input [31:0] XXATAI,
- input XXDACK,
- `ifdef __HARVARD__
- output YDREQ,
- output [31:0] YADDR,
- input [31:0] YDATA,
- input YDACK,
- `endif
- `ifdef SIMULATION
- input ESIMREQ,
- output ESIMACK,
- `endif
- output [3:0] DEBUG // osciloscope
- );
- // darkriscv bus interface
- wire [31:0] IADDR;
- wire [31:0] IDATA;
- wire IDACK;
-
- wire [31:0] DADDR;
- wire [31:0] DATAO;
- wire [31:0] DATAI;
- wire [ 2:0] DLEN;
- wire IHLT,
- DRW,
- DWR,
- DRD,
- DAS;
- wire DDACK;
-
- // darkriscv
- wire [3:0] KDEBUG;
-
- darkriscv
- #(
- .CPTR(0)
- )
- core0
- (
- .CLK (CLK),
- .RES (RES),
- .HLT (IHLT),
- `ifdef __INTERRUPT__
- .IRQ (XIRQ),
- `endif
- .IDATA (IDATA),
- .IADDR (IADDR),
- .DADDR (DADDR),
- .DATAI (DATAI),
- .DATAO (DATAO),
- .DLEN (DLEN),
- .DRW (DRW),
- .DWR (DWR),
- .DRD (DRD),
- .DAS (DAS),
- `ifdef SIMULATION
- .ESIMREQ(ESIMREQ),
- .ESIMACK(ESIMACK),
- `endif
- .DEBUG (KDEBUG)
- );
- // instruction cache
- wire YDREQ;
- wire [31:0] YADDR;
- wire [31:0] YDATA;
- wire YDACK;
- `ifdef __ICACHE__
-
- darkcache #(.ID(0)) l1_inst
- (
- .CLK (CLK),
- .RES (RES),
- .HLT (HLT),
-
- .DAS (!RES),
- .DRD (1'b1),
- .DWR (1'b0),
- .DLEN (3'd4),
- .DADDR (IADDR),
- .DATAI (32'd0),
- .DATAP (IDATA),
- .DDACK (IDACK),
- .XDREQ (YDREQ),
- //.XRD (XRD),
- //.XWR (XWR),
- //.XBE (XBE),
- .XADDR (YADDR),
- .XATAI (YDATA),
- //.XATAO (XDATO),
- .XDACK (YDACK)
- );
- `else
- assign YDREQ = !RES;
- assign YADDR = IADDR;
- assign IDATA = YDATA;
- assign IDACK = YDACK;
- `endif
- // data cache
- wire XDREQ;
- wire XWR;
- wire XRD;
- wire [3:0] XBE;
- wire [31:0] XADDR;
- wire [31:0] XATAO;
- wire XDACK;
- wire [31:0] XATAI;
-
- `ifndef __HARVARD__
- reg [31:0] XATAI2 = 0;
- reg XDACK2 = 0;
- `endif
- `ifdef __DCACHE__
-
- darkcache #(.ID(1)) l1_data
- (
- .CLK (CLK),
- .RES (RES),
- .HLT (HLT),
-
- .DAS (DAS),
- .DRD (DRD),
- .DWR (DWR),
- .DLEN (DLEN),
- .DADDR (DADDR),
- .DATAI (DATAO),
- .DATAO (DATAI),
- .DDACK (DDACK),
- .XDREQ (XDREQ),
- .XRD (XRD),
- .XWR (XWR),
- .XBE (XBE),
- .XADDR (XADDR),
- .XATAI (XATAI),
- .XATAO (XATAO),
- .XDACK (XDACK)
- );
- `else
- assign XDREQ = DAS;
- assign XRD = DRD;
- assign XWR = DWR;
- assign XADDR = DADDR;
- assign XBE = DLEN[0] ? ( DADDR[1:0]==3 ? 4'b1000 : // 8-bit
- DADDR[1:0]==2 ? 4'b0100 :
- DADDR[1:0]==1 ? 4'b0010 :
- 4'b0001 ) :
- DLEN[1] ? ( DADDR[1]==1 ? 4'b1100 : // 16-bit
- 4'b0011 ) :
- 4'b1111; // 32-bit
-
- assign XATAO = DLEN[0] ? ( DADDR[1:0]==3 ? { DATAO[ 7: 0], 24'd0 } :
- DADDR[1:0]==2 ? { 8'd0, DATAO[ 7: 0], 16'd0 } :
- DADDR[1:0]==1 ? { 16'd0, DATAO[ 7: 0], 8'd0 } :
- { 24'd0, DATAO[ 7: 0] } ):
- DLEN[1] ? ( DADDR[1]==1 ? { DATAO[15: 0], 16'd0 } :
- { 16'd0, DATAO[15: 0] } ):
- DATAO;
- assign DATAI = DLEN[0] ? ( DADDR[1:0]==3 ? XATAI[31:24] :
- DADDR[1:0]==2 ? XATAI[23:16] :
- DADDR[1:0]==1 ? XATAI[15: 8] :
- XATAI[ 7: 0] ):
- DLEN[1] ? ( DADDR[1]==1 ? XATAI[31:16] :
- XATAI[15: 0] ):
- XATAI;
- assign DDACK = XXDACK;
- `endif
- `ifdef __HARVARD__
- assign XXDREQ = XDREQ;
- assign XXWR = XWR;
- assign XXRD = XRD;
- assign XXBE = XBE;
- assign XXADDR = XADDR;
- assign XXATAO = XATAO;
- assign XATAI = XXATAI;
- assign XDACK = XXDACK;
- assign IHLT = (!RES && !IDACK) || (DAS && !DDACK);
-
- assign HLT = IHLT;
- `else
- reg [1:0] XSTATE = 0;
-
- always@(posedge CLK)
- begin
- XSTATE <= RES ? 0 :
- XSTATE==0 && XDREQ ? 2 : // idle to data
- XSTATE==0 && YDREQ ? 1 : // idle to instr
- XSTATE==2 && XXDACK && YDREQ ? 1 : // data to instr
- XSTATE==2 && XXDACK ? 0 : // data to idle
- XSTATE==1 && XXDACK ? 0 : // instr to idle
- XSTATE; // no change
-
- XATAI2 <= (XSTATE==2 && XXDACK) ? XXATAI : XATAI2;
- XDACK2 <= XDREQ && (XSTATE==2 && XXDACK) ? XXDACK :
- YDREQ && (XSTATE==1 && XXDACK) ? 0 : XDACK2;
- end
- assign XXDREQ = XSTATE==2 ? XDREQ : XSTATE==1 ? YDREQ : 1'b0;
- assign XXWR = XSTATE==2 ? XWR : XSTATE==1 ? 1'b0 : 1'b0;
- assign XXRD = XSTATE==2 ? XRD : XSTATE==1 ? 1'b1 : 1'b0;
- assign XXBE = XSTATE==2 ? XBE : XSTATE==1 ? 4'd15 : 4'd0;
- assign XXADDR = XSTATE==2 ? XADDR : XSTATE==1 ? YADDR : 32'd0;
- assign XXATAO = XSTATE==2 ? XATAO : XSTATE==1 ? 32'd0 : 32'd0;
- assign YDATA = XXATAI;
- assign YDACK = XSTATE==1 && XXDACK;
- assign XATAI = XSTATE==1 ? XATAI2 : XXATAI;
- assign XDACK = XSTATE==1 ? XDACK2 : XXDACK;
- assign IHLT = (!RES && !IDACK) || (DAS && !DDACK);
-
- assign HLT = 0;
- `endif
-
- assign DEBUG = { XDREQ, HLT, XDACK, IDACK };
- endmodule
复制代码
darkcache.v (L1缓存模块)
- /*
- * Copyright (c) 2018, Marcelo Samsoniuk
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- `timescale 1ns / 1ps
- `include "../rtl/config.vh"
- module darkcache
- #(
- parameter ID = 0
- )
- (
- input CLK, // clock
- input RES, // reset
- input HLT,
- // darkriscv
- input DAS, // address valid
- input DRD, // read/write
- input DWR, // read/write
- input [2:0] DLEN, // data length in bytes
- input [31:0] DADDR, // address
- input [31:0] DATAI, // data input
- output [31:0] DATAO, // data output
- output DDACK, // data ack
- output [31:0] DATAP, // pipelined data output
-
- // memory
-
- output XDREQ, // address valid
- output XRD, // data read
- output XWR, // data write
- output [3:0] XBE, // byte enable
- output [31:0] XADDR, // address
- output [31:0] XATAO, // data output
- input [31:0] XATAI, // data input
- input XDACK, // data ack
- output [3:0] DEBUG // osciloscope
- );
- // cache
- `ifdef __CDEPTH__
- `ifdef __LUTCACHE__
-
- wire [31:0] CDATO;
-
- reg [31:`__CDEPTH__+2] CTAG [0:2**`__CDEPTH__-1];
- reg [31:0] CDATA [0:2**`__CDEPTH__-1];
- reg CVAL [0:2**`__CDEPTH__-1];
-
- integer i;
-
- initial
- begin
- $display("cache%0d: %0dx32-bits (%0d bytes)",
- ID,
- (2**`__CDEPTH__),
- 4*(2**`__CDEPTH__));
-
- for(i=0;i!=2**`__CDEPTH__;i=i+1)
- begin
- CDATA [i] = 0;
- CTAG [i] = 0;
- CVAL [i] = 0;
- end
- end
- wire [`__CDEPTH__-1:0] CINDEX = DADDR[`__CDEPTH__+1:2];
- wire HIT = RES ? 0 : (DRD && CVAL[CINDEX] && CTAG[CINDEX]==DADDR[31:`__CDEPTH__+2]);
- wire CLR = RES ? 0 : (DWR && CVAL[CINDEX] && CTAG[CINDEX]==DADDR[31:`__CDEPTH__+2]);
- wire DTREQ = RES||HIT ? 0 : (DADDR[31:30]==0||DADDR[31:30]==2) && DRD;
- reg [31:0] DATAOFF = 0;
- always@(posedge CLK)
- begin
- if(DTREQ && XDACK)
- begin
- //$display("cache%0d: miss_on_rd %x:%x\n",ID,DADDR,XATAI);
- CDATA [CINDEX] <= XATAI;
- CTAG [CINDEX] <= DADDR[31:`__CDEPTH__+2];
- CVAL [CINDEX] <= 1;
- end
- else
- if(CLR)
- begin
- if(DLEN==4)
- begin
- //$display("cache%0d: miss_on_wr %x:%x\n",ID,DADDR,DATAI);
- CDATA [CINDEX] <= DATAI;
- CTAG [CINDEX] <= DADDR[31:`__CDEPTH__+2];
- CVAL [CINDEX] <= 1;
- end
- else
- begin
- //$display("cache%0d: flush_on_wr %x:%x\n",ID,DADDR,DATAI);
- CVAL [CINDEX] <= 0;
- end
- end
- // if(HIT) $display("cache%0d: hit_on_rd %x:%x\n",ID,DADDR,DATAI);
- if(!HLT) DATAOFF <= CDATO;
- end
- assign CDATO = HIT ? CDATA[CINDEX] : XATAI;
- assign DATAP = DATAOFF;
-
- assign DDACK = HIT ? 1 : XDACK;
-
- `else
- wire [31:0] CDATO;
- /*
- reg [31:`__CDEPTH__+2] CTAG [0:2**`__CDEPTH__-1];
- reg [31:0] CDATA [0:2**`__CDEPTH__-1];
- reg CVAL [0:2**`__CDEPTH__-1];
- */
- (* ram_style = "block" *) reg [31:0] COMBO [0:2*2**`__CDEPTH__-1];
-
- integer i;
-
- initial
- begin
- $display("cache%0d: %0dx32-bits (%0d bytes)",
- ID,
- (2**`__CDEPTH__),
- 4*(2**`__CDEPTH__));
-
- for(i=0;i!=2*2**`__CDEPTH__;i=i+1)
- begin
- /*
- CDATA [i] = 0;
- CTAG [i] = 0;
- CVAL [i] = 0;
- */
- COMBO [i] = 0;
- end
- end
- wire [`__CDEPTH__-1:0] CINDEX = DADDR[`__CDEPTH__+1:2];
- wire [`__CDEPTH__:0] CINDEX1 = { 1'b0, CINDEX };
- wire [`__CDEPTH__:0] CINDEX2 = { 1'b1, CINDEX };
- wire HIT = RES ? 0 : (DRD && CVALFF && CTAGFF==DADDR[31:`__CDEPTH__+2]);
- wire CLR = RES ? 0 : (DWR && CVALFF && CTAGFF==DADDR[31:`__CDEPTH__+2]);
- wire DTREQ = RES||HIT ? 0 : (DADDR[31:30]==0||DADDR[31:30]==2) && DRD;
- reg [31:0] DATAOFF = 0;
- reg [31:0] COMBOFF1 = 0;
- reg [31:0] COMBOFF2 = 0;
- wire [31:0] CDATAFF = COMBOFF1[31:0];
- wire [31:`__CDEPTH__+2] CTAGFF = COMBOFF2[31:`__CDEPTH__+2];
- wire [`__CDEPTH__+1:1] FILLER = COMBOFF2[`__CDEPTH__+1:1];
- wire CVALFF = COMBOFF2[0];
- reg HIT2 = 0;
-
- always@(posedge CLK)
- begin
- HIT2 <= HIT;
-
- if((DTREQ && XDACK)||CLR) COMBO [CINDEX1] <= (DTREQ && XDACK) ? /*{ DADDR[31:`__CDEPTH__+2], ~FILLER, 1'b1 }*/ DADDR|1'b1 : 0;
- if((DTREQ && XDACK)||CLR) COMBO [CINDEX2] <= (DTREQ && XDACK) ? XATAI : 0;
-
- COMBOFF1 <= COMBO[CINDEX1];
- COMBOFF2 <= COMBO[CINDEX2];
- /*
- CTAGFF <= CTAG [CINDEX];
- CDATAFF <= CDATA[CINDEX];
- CVALFF <= CVAL [CINDEX];
-
- if((DTREQ && XDACK)||CLR)
- begin
- //$display("cache%0d: miss_on_rd %x:%x\n",ID,DADDR,XATAI);
-
- CDATA [CINDEX] <= XATAI;
- CTAG [CINDEX] <= DADDR[31:`__CDEPTH__+2];
- CVAL [CINDEX] <= 1;
- end
-
- else
- if(CLR)
- begin
- if(DLEN==4)
- begin
- //$display("cache%0d: miss_on_wr %x:%x\n",ID,DADDR,DATAI);
- CDATA [CINDEX] <= DATAI;
- CTAG [CINDEX] <= DADDR[31:`__CDEPTH__+2];
- CVAL [CINDEX] <= 1;
- end
- else
- begin
- //$display("cache%0d: flush_on_wr %x:%x\n",ID,DADDR,DATAI);
- COMBO [CINDEX] <= 0;
- end
- end
- */
- // if(HIT) $display("cache%0d: hit_on_rd %x:%x\n",ID,DADDR,DATAI);
- if(!HLT) DATAOFF <= CDATO;
- end
- assign CDATO = HIT ? CDATAFF : XATAI;
- assign DATAP = DATAOFF;
- assign DDACK = HIT2 ? 1 : XDACK;
-
- `endif
- `else
- wire [31:0] CDATO = XATAI;
- wire HIT = 0;
- assign DDACK = XDACK;
- `endif
- // convert darkriscv bus to xbus
- assign XDREQ = HIT ? 0 : DAS;
- assign XRD = HIT ? 0 : DRD;
- assign XWR = HIT ? 0 : DWR;
- assign XADDR = HIT ? 0 : DADDR;
- assign XBE = HIT ? 0 : DLEN[0] ? ( DADDR[1:0]==3 ? 4'b1000 : // 8-bit
- DADDR[1:0]==2 ? 4'b0100 :
- DADDR[1:0]==1 ? 4'b0010 :
- 4'b0001 ) :
- DLEN[1] ? ( DADDR[1]==1 ? 4'b1100 : // 16-bit
- 4'b0011 ) :
- 4'b1111; // 32-bit
-
- assign XATAO = HIT ? 0 : DLEN[0] ? ( DADDR[1:0]==3 ? { DATAI[ 7: 0], 24'd0 } :
- DADDR[1:0]==2 ? { 8'd0, DATAI[ 7: 0], 16'd0 } :
- DADDR[1:0]==1 ? { 16'd0, DATAI[ 7: 0], 8'd0 } :
- { 24'd0, DATAI[ 7: 0] } ):
- DLEN[1] ? ( DADDR[1]==1 ? { DATAI[15: 0], 16'd0 } :
- { 16'd0, DATAI[15: 0] } ):
- DATAI;
- assign DATAO = DLEN[0] ? ( DADDR[1:0]==3 ? CDATO[31:24] :
- DADDR[1:0]==2 ? CDATO[23:16] :
- DADDR[1:0]==1 ? CDATO[15: 8] :
- CDATO[ 7: 0] ):
- DLEN[1] ? ( DADDR[1]==1 ? CDATO[31:16] :
- CDATO[15: 0] ):
- CDATO;
- assign DEBUG = { DAS, HIT, XDREQ, XDACK };
- endmodule
复制代码
darkram.v (内存模块)
- /*
- * Copyright (c) 2018, Marcelo Samsoniuk
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- `timescale 1ns / 1ps
- `include "../rtl/config.vh"
- module darkram
- (
- input CLK, // clock
- input RES, // reset
- input HLT, // halt
-
- input IDREQ,
- input [31:0] IADDR,
- output [31:0] IDATA,
- output IDACK,
- input XDREQ,
- input XRD,
- input XWR,
- input [3:0] XBE,
- input [31:0] XADDR,
- input [31:0] XATAI,
- output [31:0] XATAO,
- output XDACK,
-
- output [3:0] DEBUG
- );
- // ro/rw memories
- reg [31:0] MEM [0:2**`MLEN/4-1]; // ro memory
- // memory initialization
- integer i;
- initial
- begin
- `ifdef SIMULATION
- $display("dpram: unified BRAM w/ %0dx32-bit",2**`MLEN/4);
- `ifdef __WAITSTATE__
- $display("dpram: waitstates=%0d enabled (default=1)",`__WAITSTATE__);
- `endif
- `ifdef __RMW_CYCLE__
- $display("dpram: RMW cycle enabled.",);
- `endif
-
- for(i=0;i!=2**`MLEN/4;i=i+1)
- begin
- MEM[i] = 32'd0;
- end
- `endif
- // workaround for vivado: no path in simulation and .mem extension
- `ifdef XILINX_SIMULATOR
- $readmemh("darksocv.mem",MEM);
- `elsif MODEL_TECH
- $readmemh("../../../../src/darksocv.mem",MEM);
- `else
- $readmemh("../src/darksocv.mem",MEM,0);
- `endif
- end
- // instruction memory
- `ifdef __ICACHE__
- reg [3:0] ITACK = 0;
- reg [31:0] ROMFF = 0;
- always@(posedge CLK)
- begin
- `ifdef __WAITSTATE__
- ITACK <= RES ? 0 : ITACK ? ITACK-1 : IDREQ ? `__WAITSTATE__ : 0;
- `else
- ITACK <= RES ? 0 : ITACK ? ITACK-1 : IDREQ ? 1 : 0;
- `endif
-
- ROMFF <= MEM[IADDR[`MLEN-1:2]];
- end
- assign IDATA = ROMFF;
- assign IDACK = ITACK==1;
- `else
- reg [3:0] ITACK = 0;
- reg [31:0] ROMFF = 0;
- always@(posedge CLK)
- begin
- `ifdef __WAITSTATE__
- ITACK <= RES ? 0 : ITACK ? ITACK-1 : IDREQ ? `__WAITSTATE__ : 0; // i-bus wait-state
- `endif
- ROMFF <= MEM[IADDR[`MLEN-1:2]];
- // if(!RES && !HLT) $display("bram: addr=%x inst=%x\n",IADDR,ROMFF);
- end
- assign IDATA = ROMFF;
-
- `ifdef __WAITSTATE__
- assign IDACK = ITACK==1;
- `else
- assign IDACK = IDREQ;
- `endif
- `endif
- // data memory
- reg [3:0] DTACK = 0;
- reg [31:0] RAMFF = 0;
- always@(posedge CLK) // stage #1.0
- begin
- `ifdef __RMW_CYCLE__
- `ifdef __WAITSTATE__
- DTACK <= RES ? 0 : DTACK ? DTACK-1 : XDREQ && (XRD||XWR) ? `__WAITSTATE__ : 0;
- `else
- DTACK <= RES ? 0 : DTACK ? DTACK-1 : XDREQ && (XRD||XWR) ? 1 : 0;
- `endif
- `else
- `ifdef __WAITSTATE__
- DTACK <= RES ? 0 : DTACK ? DTACK-1 : XDREQ && XRD ? `__WAITSTATE__ : 0;
- `else
- DTACK <= RES ? 0 : DTACK ? DTACK-1 : XDREQ && XRD ? 1 : 0;
- `endif
- `endif
- RAMFF <= MEM[XADDR[`MLEN-1:2]];
- //individual byte/word/long selection, thanks to HYF!
- `ifdef __RMW_CYCLE__
- // read-modify-write operation w/ 1 wait-state:
- if(XWR && XDREQ)
- begin
- MEM[XADDR[`MLEN-1:2]] <=
- {
- XBE[3] ? XATAI[3 * 8 + 7: 3 * 8] : RAMFF[3 * 8 + 7: 3 * 8],
- XBE[2] ? XATAI[2 * 8 + 7: 2 * 8] : RAMFF[2 * 8 + 7: 2 * 8],
- XBE[1] ? XATAI[1 * 8 + 7: 1 * 8] : RAMFF[1 * 8 + 7: 1 * 8],
- XBE[0] ? XATAI[0 * 8 + 7: 0 * 8] : RAMFF[0 * 8 + 7: 0 * 8]
- };
- end
- `else
- // write-only operation w/ 0 wait-states:
-
- if(XWR && XDREQ && XBE[3]) MEM[XADDR[`MLEN-1:2]][3 * 8 + 7: 3 * 8] <= XATAI[3 * 8 + 7: 3 * 8];
- if(XWR && XDREQ && XBE[2]) MEM[XADDR[`MLEN-1:2]][2 * 8 + 7: 2 * 8] <= XATAI[2 * 8 + 7: 2 * 8];
- if(XWR && XDREQ && XBE[1]) MEM[XADDR[`MLEN-1:2]][1 * 8 + 7: 1 * 8] <= XATAI[1 * 8 + 7: 1 * 8];
- if(XWR && XDREQ && XBE[0]) MEM[XADDR[`MLEN-1:2]][0 * 8 + 7: 0 * 8] <= XATAI[0 * 8 + 7: 0 * 8];
- `endif
- end
- assign XATAO = RAMFF;
-
- `ifdef __RMW_CYCLE__
- assign XDACK = DTACK==1;
- `else
- assign XDACK = DTACK==1 ||(XDREQ&&XWR);
- `endif
-
- assign DEBUG = { XDREQ,XRD,XWR,XDACK };
- endmodule
复制代码
darksocv.v (SOC也可以称为TOP模块)
- /*
- * Copyright (c) 2018, Marcelo Samsoniuk
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * * Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- `timescale 1ns / 1ps
- `include "../rtl/config.vh"
- module darksocv
- (
- input XCLK, // external clock
- input XRES, // external reset
- input UART_RXD, // UART receive line
- output UART_TXD, // UART transmit line
- `ifdef __SDRAM__
- output S_CLK,
- output S_CKE,
- output S_NCS,
- output S_NWE,
- output S_NRAS,
- output S_NCAS,
- output [1:0] S_DQM,
- output [1:0] S_BA,
- output [12:0] S_A,
- inout [15:0] S_DB,
- `endif
- output [3:0] LED, // on-board leds
- output [3:0] DEBUG // osciloscope
- );
- // clock and reset
- wire CLK,RES;
- `ifdef BOARD_CK
-
- darkpll darkpll0
- (
- .XCLK(XCLK),
- .XRES(XRES),
- .CLK(CLK),
- .RES(RES)
- );
- `else
- // internal/external reset logic
- reg [7:0] IRES = -1;
- `ifdef INVRES
- always@(posedge XCLK) IRES <= XRES==0 ? -1 : IRES[7] ? IRES-1 : 0; // reset low
- `else
- always@(posedge XCLK) IRES <= XRES==1 ? -1 : IRES[7] ? IRES-1 : 0; // reset high
- `endif
- assign CLK = XCLK;
- assign RES = IRES[7];
- `endif
- `ifdef __TESTMODE__
-
- // tips to port darkriscv for a new target:
- //
- // - 1st of all, test the blink code to confirms the reset
- // polarity, i.e. the LEDs must blink at startup when
- // the reset button *is not pressed*
- // - 2nd check the blink rate: the 31-bit counter that starts
- // with BOARD_CK value and counts to zero, blinking w/
- // 50% of this period
- reg [31:0] BLINK = 0;
-
- always@(posedge CLK)
- begin
- BLINK <= RES ? 0 : BLINK ? BLINK-1 : `BOARD_CK;
- end
-
- assign LED = (BLINK < (`BOARD_CK/2)) ? -1 : 0;
- assign UART_TXD = UART_RXD;
- `endif
- // darkbridge interface
- wire XIRQ;
- wire XDREQ;
- wire [31:0] XADDR;
- wire [31:0] XATAO;
- wire XWR,
- XRD;
- wire [3:0] XBE;
- wire [3:0] XDREQMUX;
-
- assign XDREQMUX[0] = XDREQ && XADDR[31:30]==0;
- assign XDREQMUX[1] = XDREQ && XADDR[31:30]==1;
- assign XDREQMUX[2] = XDREQ && XADDR[31:30]==2;
- assign XDREQMUX[3] = XDREQ && XADDR[31:30]==3;
- wire [31:0] XATAIMUX [0:3];
- wire XDACKMUX [0:3];
-
- // darkriscv
- wire [3:0] KDEBUG;
-
- wire ESIMREQ,ESIMACK;
- wire HLT;
- wire IDREQ;
- wire [31:0] IADDR;
- wire [31:0] IDATA;
- wire IDACK;
- `ifndef __HARVARD__
- assign IDREQ = 0;
- `endif
- darkbridge
- bridge0
- (
- .CLK (CLK),
- .RES (RES),
- .HLT (HLT),
- `ifdef __INTERRUPT__
- .XIRQ (XIRQ),
- `endif
- .XXDREQ (XDREQ),
- .XXADDR (XADDR),
- .XXATAI (XATAIMUX[XADDR[31:30]]),
- .XXATAO (XATAO),
- .XXRD (XRD),
- .XXWR (XWR),
- .XXBE (XBE),
- .XXDACK (XDACKMUX[XADDR[31:30]]),
- `ifdef __HARVARD__
- .YDREQ (IDREQ),
- .YADDR (IADDR),
- .YDATA (IDATA),
- .YDACK (IDACK),
- `endif
- `ifdef SIMULATION
- .ESIMREQ(ESIMREQ),
- .ESIMACK(ESIMACK),
- `endif
- .DEBUG (KDEBUG)
- );
- // bram memory w/ CS==0
- darkram bram0
- (
- .CLK (CLK),
- .RES (RES),
- .HLT (HLT),
-
- .IDREQ (IDREQ),
- .IADDR (IADDR),
- .IDATA (IDATA),
- .IDACK (IDACK),
-
- .XDREQ (XDREQMUX[0]),
- .XRD (XRD),
- .XWR (XWR),
- .XBE (XBE),
- .XADDR (XADDR),
- .XATAI (XATAO),
- .XATAO (XATAIMUX[0]),
- .XDACK (XDACKMUX[0])
- );
- // io block w/ CS==1
- wire [3:0] IODEBUG;
- darkio io0
- (
- .CLK (CLK),
- .RES (RES),
- .HLT (HLT),
- `ifdef __INTERRUPT__
- .XIRQ (XIRQ),
- `endif
-
- .XDREQ (XDREQMUX[1]),
- .XRD (XRD),
- .XWR (XWR),
- .XBE (XBE),
- .XADDR (XADDR),
- .XATAI (XATAO),
- .XATAO (XATAIMUX[1]),
- .XDACK (XDACKMUX[1]),
-
- .RXD (UART_RXD),
- .TXD (UART_TXD),
- .LED (LED),
- `ifdef SIMULATION
- .ESIMREQ(ESIMREQ),
- .ESIMACK(ESIMACK),
- `endif
- .DEBUG (IODEBUG)
- );
- // sdram w/ CS==2
-
- `ifdef __SDRAM__
- // sdram interface, thanks to my good friend Hirosh Dabui!
- wire READY,T_CLK;
- mt48lc16m16a2_ctrl
- #(
- .SDRAM_CLK_FREQ(`BOARD_CK/1000000)
- )
- sdram0
- (
- .clk (CLK),
- .resetn (!RES),
-
- .addr (XADDR[24:0]),
- .din (XATAO),
- .dout (XATAIMUX[2]),
- .wmask (XWR ? XBE : 4'b0000),
- .valid (XDREQMUX[2]),
- .ready (READY),
- .sdram_clk (T_CLK),
- .sdram_cke (S_CKE),
- .sdram_dqm (S_DQM),
- .sdram_addr (S_A),
- .sdram_ba (S_BA),
- .sdram_csn (S_NCS),
- .sdram_wen (S_NWE),
- .sdram_rasn (S_NRAS),
- .sdram_casn (S_NCAS),
- .sdram_dq (S_DB)
- );
- reg [1:0] TS_CLK = 2'b00;
- always@(posedge CLK) TS_CLK[0] <= RES ? 0: !TS_CLK[0];
- always@(negedge CLK) TS_CLK[1] <= RES ? 0: !TS_CLK[1];
- assign S_CLK = ^TS_CLK;
- assign XDACKMUX[2] = READY;
- `else
- reg [3:0] DTACK2 = 0;
- always@(posedge CLK)
- begin
- DTACK2 <= RES ? 0 : DTACK2 ? DTACK2-1 : XDREQMUX[2] ? 13 : 0;
- if(XDREQMUX[2]) $display("sdram: unmapped addr=%x",XADDR);
- end
- assign XATAIMUX[2] = 32'hdeadbeef;
- assign XDACKMUX[2] = DTACK2==1;
- `endif
- // unmapped area w/ CS==3
- reg [3:0] DTACK3 = 0;
- always@(posedge CLK)
- begin
- DTACK3 <= RES ? 0 : DTACK3 ? DTACK3-1 : XDREQMUX[3] ? 1 : 0;
- if(XDREQMUX[3]) $display("sdram: unmapped addr=%x",XADDR);
- end
- assign XATAIMUX[3] = 32'hdeadbeef;
- assign XDACKMUX[3] = DTACK3==1;
-
- assign DEBUG = KDEBUG;
- endmodule
复制代码
设备上电内存模块就会把指令缓存的数据通过 IDATA 向外输出然后通过darkbridge模块的YDATA引脚输入darkbridge模块,之后通过L1缓存模块的XATAI缓存到L1指令缓存,然后核心模块通过给L1指令缓存发送地址来读取L1缓存的指令数据。数据通过L1指令缓存的DATAP引脚输入CPU核心模块。然后再时钟上沿时赋值给寄存器 IDATA2,在之后通过 wire[31:0] IDATAX = XRES ? 0 : HLT2 ? IDATA2 : IDATA; 赋值给IDATAX。之后就是时钟上沿时把指令解码出来,代码如下
- <blockquote>always@(posedge CLK)
复制代码 在一系列解码指令之后就是开始解码数据
- wire [31:0] LDATA = FCT3[1:0]==0 ? { FCT3[2]==0&&DATAI[ 7] ? ALL1[31: 8]:ALL0[31: 8] , DATAI[ 7: 0] } :
- FCT3[1:0]==1 ? { FCT3[2]==0&&DATAI[15] ? ALL1[31:16]:ALL0[31:16] , DATAI[15: 0] } :
- DATAI;
复制代码 之后就是寄存器重置或赋值
- `ifdef __RV32E__
- REGS[DPTR] <= XRES||DPTR[3:0]==0 ? 0 : // reset x0
- `else
- REGS[DPTR] <= XRES||DPTR[4:0]==0 ? 0 : // reset x0
- `endif
- HLT ? REGS[DPTR] : // halt
- LCC ? LDATA :
- AUIPC ? PCSIMM :
- JAL||
- JALR ? NXPC :
- LUI ? SIMM :
- MCC||RCC ? RMDATA:
复制代码
在下一个时钟周期把通用寄存器分拆
- // source-1 and source-1 register selection
- wire [31:0] U1REG = REGS[S1PTR];
- wire [31:0] U2REG = REGS[S2PTR];
- wire signed [31:0] S1REG = U1REG;
- wire signed [31:0] S2REG = U2REG;
复制代码 之后就是一系列的数据处理
|