mirror of
				https://github.com/openhwgroup/cvw
				synced 2025-02-11 06:05:49 +00:00 
			
		
		
		
	Implement progbuf and attempt to halt/resume using existing trap logic (very broken)
This commit is contained in:
		
							parent
							
								
									5c593c3321
								
							
						
					
					
						commit
						9514eab75e
					
				| @ -38,7 +38,13 @@ random_order = False | ||||
| 
 | ||||
| def prog_buff_test(cvw): | ||||
|     cvw.halt() | ||||
|     cvw.write_dmi("0x20", "0x7ee7beef") | ||||
|     cvw.write_dmi("0x20", "0x00100073") | ||||
|     #cvw.write_dmi("0x21", "0xf00daedd") | ||||
|     #cvw.write_dmi("0x22", "0xdaede105") | ||||
|     #cvw.write_dmi("0x23", "0x00100073") # ebreak | ||||
| 
 | ||||
|     cvw.write_data("DPC", "0x00002000") # Progbuf addr | ||||
|     cvw.resume() | ||||
|     print() | ||||
| 
 | ||||
| 
 | ||||
| @ -46,10 +52,13 @@ def flow_control_test(cvw): | ||||
|     #time.sleep(70)  # wait for OpenSBI | ||||
| 
 | ||||
|     cvw.halt() | ||||
|     cvw.read_data("DCSR") | ||||
|     time.sleep(1) | ||||
|     #cvw.read_data("DCSR") | ||||
|     for _ in range(50): | ||||
|         cvw.step() | ||||
|         print(cvw.read_data("PCM")) | ||||
|         cvw.resume() | ||||
|         cvw.halt() | ||||
|         #cvw.step() | ||||
|         #print(cvw.read_data("PCM")) | ||||
|     cvw.resume() | ||||
| 
 | ||||
| 
 | ||||
| @ -154,11 +163,11 @@ def random_hex(reg_name): | ||||
| 
 | ||||
| 
 | ||||
| with OpenOCD() as cvw: | ||||
|     print(cvw.read_dmi("0x16")) | ||||
|     cvw.trst() | ||||
|     #cvw.trst() | ||||
|     cvw.reset_dm() | ||||
|     time.sleep(1) | ||||
|     cvw.reset_hart() | ||||
|     quit() | ||||
|     time.sleep(1) | ||||
|     #register_rw_test(cvw) | ||||
|     flow_control_test(cvw) | ||||
|     #prog_buff_test(cvw) | ||||
|     #flow_control_test(cvw) | ||||
|     prog_buff_test(cvw) | ||||
|  | ||||
| @ -114,6 +114,12 @@ class OpenOCD: | ||||
|             raise Exception("Error: Hart failed to reset") | ||||
|         self.write_dmi("0x10", "0x10000001")  # ack HaveReset | ||||
| 
 | ||||
|     def write_progbuf(self, data): | ||||
|         #TODO query progbuf size and error is len(data) is greater | ||||
|         baseaddr = 0x20 | ||||
|         for idx, instr in enumerate(data): | ||||
|             self.write_dmi(hex(baseaddr+idx), instr) | ||||
| 
 | ||||
|     def set_haltonreset(self): | ||||
|         self.write_dmi("0x10", "0x9") | ||||
| 
 | ||||
| @ -139,7 +145,7 @@ class OpenOCD: | ||||
|             dcsr |= 0x4 | ||||
|             self.write_data("DCSR", hex(dcsr)) | ||||
|         # Resume once | ||||
|         self.resume() | ||||
|         self.write_dmi("0x10", "0x40000001") | ||||
|         # Unset step bit | ||||
|         dcsr &= ~0x4 | ||||
|         self.write_data("DCSR", hex(dcsr)) | ||||
| @ -153,7 +159,7 @@ class OpenOCD: | ||||
|         data += int(math.log2(addr_size // 8)) << 20 | ||||
|         data += write << 16 | ||||
|         data += regno | ||||
|         self.write_dmi("0x17", hex(data)) | ||||
|         self.write_dmi("0x17", hex(data))   | ||||
| 
 | ||||
|     def write_data(self, register, data): | ||||
|         """Write data to specified register""" | ||||
|  | ||||
| @ -186,6 +186,9 @@ localparam logic [63:0] SDC_RANGE        = 64'h0000007F; | ||||
| localparam logic SPI_SUPPORTED = 1; | ||||
| localparam logic [63:0] SPI_BASE         = 64'h10040000; | ||||
| localparam logic [63:0] SPI_RANGE        = 64'h00000FFF; | ||||
| // Debug program buffer support is enabled with DEBUG_SUPPORTED | ||||
| localparam logic [63:0] PROGBUF_BASE     = 64'h00002000; | ||||
| localparam logic [63:0] PROGBUF_RANGE    = 64'h0000000F; | ||||
| 
 | ||||
| // Bus Interface width | ||||
| localparam AHBW = (XLEN); | ||||
|  | ||||
| @ -48,6 +48,21 @@ | ||||
| `define ABSTRACTAUTO `ADDR_WIDTH'h18 | ||||
| `define NEXTDM       `ADDR_WIDTH'h1d | ||||
| `define PROGBUF0     `ADDR_WIDTH'h20 | ||||
| `define PROGBUF1     `ADDR_WIDTH'h21 | ||||
| `define PROGBUF2     `ADDR_WIDTH'h22 | ||||
| `define PROGBUF3     `ADDR_WIDTH'h23 | ||||
| `define PROGBUF4     `ADDR_WIDTH'h24 | ||||
| `define PROGBUF5     `ADDR_WIDTH'h25 | ||||
| `define PROGBUF6     `ADDR_WIDTH'h26 | ||||
| `define PROGBUF7     `ADDR_WIDTH'h27 | ||||
| `define PROGBUF8     `ADDR_WIDTH'h28 | ||||
| `define PROGBUF9     `ADDR_WIDTH'h29 | ||||
| `define PROGBUFA     `ADDR_WIDTH'h2A | ||||
| `define PROGBUFB     `ADDR_WIDTH'h2B | ||||
| `define PROGBUFC     `ADDR_WIDTH'h2C | ||||
| `define PROGBUFD     `ADDR_WIDTH'h2D | ||||
| `define PROGBUFE     `ADDR_WIDTH'h2E | ||||
| `define PROGBUFF     `ADDR_WIDTH'h2F | ||||
| //`define dmcs2        `ADDR_WIDTH'h32 | ||||
| `define SBCS         `ADDR_WIDTH'h38 | ||||
| 
 | ||||
|  | ||||
| @ -85,6 +85,8 @@ localparam cvw_t P = '{ | ||||
|   SPI_SUPPORTED :        SPI_SUPPORTED, | ||||
|   SPI_BASE :        SPI_BASE, | ||||
|   SPI_RANGE :        SPI_RANGE, | ||||
|   PROGBUF_BASE : PROGBUF_BASE, | ||||
|   PROGBUF_RANGE : PROGBUF_RANGE, | ||||
|   GPIO_LOOPBACK_TEST :        GPIO_LOOPBACK_TEST, | ||||
|   SPI_LOOPBACK_TEST :        SPI_LOOPBACK_TEST, | ||||
|   UART_PRESCALE :        UART_PRESCALE , | ||||
| @ -200,5 +202,5 @@ localparam cvw_t P = '{ | ||||
|   DURLEN      : DURLEN, | ||||
|   DIVb        : DIVb, | ||||
|   DIVBLEN     : DIVBLEN, | ||||
|   DEBUG_SUPPORTED : DEBUG_SUPPORTED			 | ||||
|   DEBUG_SUPPORTED : DEBUG_SUPPORTED | ||||
| }; | ||||
|  | ||||
| @ -140,6 +140,9 @@ typedef struct packed { | ||||
|   logic         SPI_SUPPORTED; | ||||
|   logic [63:0]  SPI_BASE; | ||||
|   logic [63:0]  SPI_RANGE; | ||||
|   // Debug program buffer support is enabled with DEBUG_SUPPORTED
 | ||||
|   logic [63:0]  PROGBUF_BASE; | ||||
|   logic [63:0]  PROGBUF_RANGE; | ||||
| 
 | ||||
|   // Test modes
 | ||||
| 
 | ||||
|  | ||||
| @ -74,12 +74,14 @@ module dm import cvw::*; #(parameter cvw_t P) ( | ||||
|   output logic            DebugRegUpdate, // writes values from scan register after scanning in			
 | ||||
|    | ||||
|   // Program Buffer
 | ||||
|   output logic [3:0]      ProgBufAddr, | ||||
|   output logic            ProgBuffScanEn, | ||||
|   output logic            ProgBuffScanOut, | ||||
|   output logic            ExecProgBuff | ||||
| ); | ||||
|   `include "debug.vh" | ||||
| 
 | ||||
|   localparam PROGBUF_SIZE = (P.PROGBUF_RANGE+1)/4; | ||||
| 
 | ||||
|   // DMI Signals
 | ||||
|   logic                   ReqReady; | ||||
|   logic                   ReqValid; | ||||
| @ -93,7 +95,7 @@ module dm import cvw::*; #(parameter cvw_t P) ( | ||||
| 
 | ||||
|   // JTAG ID for Wally:  
 | ||||
|   // Version [31:28] = 0x1 : 0001
 | ||||
|   // PartNumber [27:12] = 0x2A : 00000000_00101010
 | ||||
|   // PartNumber [27:12] = 0x2A : Wally (00000000_00101010)
 | ||||
|   // JEDEC number [11:1] = 0x602 : Bank 13 (1100) Open HW Group (0000010) 
 | ||||
|   // [0] = 1
 | ||||
|   localparam JTAG_DEVICE_ID = 32'h1002AC05;  | ||||
| @ -151,7 +153,7 @@ module dm import cvw::*; #(parameter cvw_t P) ( | ||||
|   // DMStatus
 | ||||
|   const logic        NdmResetPending = 0; | ||||
|   const logic        StickyUnavail = 0; | ||||
|   const logic        ImpEBreak = 1; | ||||
|   const logic        ImpEBreak = 0; | ||||
|   logic              AllHaveReset; | ||||
|   logic              AnyHaveReset; | ||||
|   logic              AllResumeAck; | ||||
| @ -170,7 +172,7 @@ module dm import cvw::*; #(parameter cvw_t P) ( | ||||
|   const logic        ConfStrPtrValid = 0; // Used with SysBusAccess
 | ||||
|   const logic [3:0]  Version = 3;    // DM Version
 | ||||
|   // AbstractCS
 | ||||
|   const logic [4:0]  ProgBufSize = 1; | ||||
|   const logic [4:0]  ProgBufSize = PROGBUF_SIZE; | ||||
|   logic              Busy; | ||||
|   const logic        RelaxedPriv = 1; | ||||
|   logic [2:0]        CmdErr; | ||||
| @ -233,27 +235,27 @@ module dm import cvw::*; #(parameter cvw_t P) ( | ||||
|         IDLE : begin | ||||
|           if (ReqValid) | ||||
|             case ({ReqOP, ReqAddress}) inside | ||||
|               {`OP_WRITE,`DATA0}                       : State <= W_DATA; | ||||
|               {`OP_READ,`DATA0}                        : State <= R_DATA; | ||||
|               {`OP_WRITE,`DATA1}                       : State <= (P.LLEN >= 64) ? W_DATA : INVALID; | ||||
|               {`OP_READ,`DATA1}                        : State <= (P.LLEN >= 64) ? R_DATA : INVALID; | ||||
|               [{`OP_WRITE,`DATA2}:{`OP_WRITE,`DATA3}]  : State <= (P.LLEN >= 128) ? W_DATA : INVALID; | ||||
|               [{`OP_READ,`DATA2}:{`OP_READ,`DATA3}]    : State <= (P.LLEN >= 128) ? R_DATA : INVALID; | ||||
|               {`OP_WRITE,`DMCONTROL}                   : State <= W_DMCONTROL; | ||||
|               {`OP_READ,`DMCONTROL}                    : State <= R_DMCONTROL; | ||||
|               {`OP_READ,`DMSTATUS}                     : State <= DMSTATUS; | ||||
|               {`OP_WRITE,`ABSTRACTCS}                  : State <= W_ABSTRACTCS; | ||||
|               {`OP_READ,`ABSTRACTCS}                   : State <= R_ABSTRACTCS; | ||||
|               {`OP_WRITE,`COMMAND}                     : State <= ABST_COMMAND; | ||||
|               {`OP_READ,`COMMAND}                      : State <= READ_ZERO; | ||||
|               {`OP_WRITE,`SBCS}                        : State <= READ_ZERO; | ||||
|               {`OP_READ,`SBCS}                         : State <= R_SYSBUSCS; | ||||
|               {`OP_WRITE,`PROGBUF0}                    : State <= W_PROGBUF; | ||||
|               {`OP_READ,`PROGBUF0}, | ||||
|               {`OP_WRITE,`DATA0}                            : State <= W_DATA; | ||||
|               {`OP_READ,`DATA0}                             : State <= R_DATA; | ||||
|               {`OP_WRITE,`DATA1}                            : State <= (P.LLEN >= 64) ? W_DATA : INVALID; | ||||
|               {`OP_READ,`DATA1}                             : State <= (P.LLEN >= 64) ? R_DATA : INVALID; | ||||
|               [{`OP_WRITE,`DATA2}:{`OP_WRITE,`DATA3}]       : State <= (P.LLEN >= 128) ? W_DATA : INVALID; | ||||
|               [{`OP_READ,`DATA2}:{`OP_READ,`DATA3}]         : State <= (P.LLEN >= 128) ? R_DATA : INVALID; | ||||
|               {`OP_WRITE,`DMCONTROL}                        : State <= W_DMCONTROL; | ||||
|               {`OP_READ,`DMCONTROL}                         : State <= R_DMCONTROL; | ||||
|               {`OP_READ,`DMSTATUS}                          : State <= DMSTATUS; | ||||
|               {`OP_WRITE,`ABSTRACTCS}                       : State <= W_ABSTRACTCS; | ||||
|               {`OP_READ,`ABSTRACTCS}                        : State <= R_ABSTRACTCS; | ||||
|               {`OP_WRITE,`COMMAND}                          : State <= ABST_COMMAND; | ||||
|               {`OP_READ,`COMMAND}                           : State <= READ_ZERO; | ||||
|               {`OP_WRITE,`SBCS}                             : State <= READ_ZERO; | ||||
|               {`OP_READ,`SBCS}                              : State <= R_SYSBUSCS; | ||||
|               [{`OP_WRITE,`PROGBUF0}:{`OP_WRITE,`PROGBUF3}] : State <= W_PROGBUF; // TODO: update decode range dynamically using PROGBUF_RANGE
 | ||||
|               [{`OP_READ,`PROGBUF0}:{`OP_READ,`PROGBUFF}], | ||||
|               {2'bx,`HARTINFO}, | ||||
|               {2'bx,`ABSTRACTAUTO}, | ||||
|               {2'bx,`NEXTDM}                           : State <= READ_ZERO; | ||||
|               default                                  : State <= READ_ZERO;//INVALID;
 | ||||
|               {2'bx,`NEXTDM}                                : State <= READ_ZERO; | ||||
|               default                                       : State <= INVALID; | ||||
|             endcase | ||||
|         end | ||||
| 
 | ||||
| @ -369,8 +371,10 @@ module dm import cvw::*; #(parameter cvw_t P) ( | ||||
|         W_PROGBUF : begin | ||||
|           if (Busy) | ||||
|             CmdErr <= ~|CmdErr ? `CMDERR_BUSY : CmdErr; | ||||
|           else | ||||
|           else begin | ||||
|             NewAcState <= PROGBUFF_WRITE; | ||||
|             ProgBufAddr <= ReqAddress[$clog2(PROGBUF_SIZE)-1:0]; | ||||
|           end | ||||
|           RspOP <= `OP_SUCCESS; | ||||
|           State <= ACK; | ||||
|         end | ||||
| @ -441,7 +445,6 @@ module dm import cvw::*; #(parameter cvw_t P) ( | ||||
| 
 | ||||
|   // Program Buffer
 | ||||
|   assign ProgBuffScanEn = (AcState == PROGBUFF_WRITE); | ||||
|   assign ProgBuffScanOut = ScanReg[0]; | ||||
| 
 | ||||
|   // Scan Chain
 | ||||
|   assign DebugScanOut = ScanReg[0]; | ||||
|  | ||||
| @ -27,12 +27,28 @@ | ||||
| // and limitations under the License.
 | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| // Note: This module controls all of the per-hart debug state.
 | ||||
| // In a multihart system, this module should be instantiated under wallypipelinedcore
 | ||||
| // On HaltReq/eBreak:
 | ||||
| // store value of NextPC in DPC
 | ||||
| // trigger trap (flush pipe)
 | ||||
| // stall pipe
 | ||||
| 
 | ||||
| // On Step:
 | ||||
| // unstall pipe until instruction receaches M stage
 | ||||
| // goto: HaltReq/eBreak
 | ||||
| 
 | ||||
| // On exec_progbuf
 | ||||
| // change NextPC to progbuf_address (using DPC?)
 | ||||
| // goto: resume (implicic ebreak will return to debug mode)
 | ||||
| 
 | ||||
| // On Resume:
 | ||||
| // update NextPC from DPC
 | ||||
| // Unstall pipe
 | ||||
| 
 | ||||
| module dmc ( | ||||
|   input  logic       clk, reset, | ||||
|   input  logic       Step, | ||||
|   input  logic       ebreakM,      // ebreak instruction
 | ||||
|   input  logic       ebreakEn,     // DCSR: enter debug mode on ebreak
 | ||||
|   input  logic       HaltReq,      // Initiates core halt
 | ||||
|   input  logic       ResumeReq,    // Initiates core resume
 | ||||
|   input  logic       HaltOnReset,  // Halts core immediately on hart reset
 | ||||
| @ -46,14 +62,14 @@ module dmc ( | ||||
| 
 | ||||
|   output logic       EnterDebugMode, // Store PCNextF in DPC when entering Debug Mode
 | ||||
|   output logic       ExitDebugMode,  // Updates PCNextF with the current value of DPC
 | ||||
|   output logic       ForceNOP        // Fills the pipeline with NOP
 | ||||
|   output logic       ForceBreakPoint // Causes artificial ebreak that puts core in debug mode
 | ||||
| ); | ||||
|   `include "debug.vh" | ||||
| 
 | ||||
|   enum logic [1:0] {RUNNING, FLUSH, HALTED, RESUME} State; | ||||
|    enum logic [2:0] {RUNNING, HALTED, RESUME, STEP, PROGBUF} State; | ||||
| 
 | ||||
|   localparam NOP_CYCLE_DURATION = 0; | ||||
|   logic [$clog2(NOP_CYCLE_DURATION+1)-1:0] Counter; | ||||
|   localparam E2M_CYCLE_COUNT = 3; | ||||
|   logic [$clog2(E2M_CYCLE_COUNT+1)-1:0] Counter; | ||||
| 
 | ||||
|   always_ff @(posedge clk) begin | ||||
|     if (reset) | ||||
| @ -62,12 +78,13 @@ module dmc ( | ||||
|       HaveReset <= 0; | ||||
|   end | ||||
| 
 | ||||
|   assign DebugMode = (State != RUNNING); | ||||
|   assign DebugStall = (State == HALTED); | ||||
|   assign ForceBreakPoint = (State == RUNNING) & HaltReq | (State == STEP) & ~|Counter; | ||||
| 
 | ||||
|   assign EnterDebugMode = (State == FLUSH) & ~|Counter; | ||||
|   assign DebugMode = (State != RUNNING); | ||||
|   assign DebugStall = (State == HALTED) | (State == RESUME); | ||||
| 
 | ||||
|   assign EnterDebugMode = (State == RUNNING) & (ebreakM & ebreakEn) | ForceBreakPoint; | ||||
|   assign ExitDebugMode = (State == HALTED) & ResumeReq; | ||||
|   assign ForceNOP = (State == FLUSH); | ||||
| 
 | ||||
|   always_ff @(posedge clk) begin | ||||
|     if (reset) begin | ||||
| @ -77,34 +94,38 @@ module dmc ( | ||||
|       case (State) | ||||
|         RUNNING : begin | ||||
|           if (HaltReq) begin | ||||
|             Counter <= NOP_CYCLE_DURATION; | ||||
|             State <= FLUSH; | ||||
|             DebugCause <= `CAUSE_HALTREQ; | ||||
|           end  | ||||
|           //else if (eBreak) TODO: halt on ebreak if DCSR bit is set
 | ||||
|           // DebugCause <= `CAUSE_EBREAK;
 | ||||
|         end | ||||
| 
 | ||||
|         // fill the pipe with NOP before halting
 | ||||
|         FLUSH : begin | ||||
|           if (~|Counter) | ||||
|             State <= HALTED; | ||||
|           else | ||||
|             Counter <= Counter - 1; | ||||
|             DebugCause <= `CAUSE_HALTREQ; | ||||
|           end else if (ebreakM & ebreakEn) begin | ||||
|             State <= HALTED; | ||||
|             DebugCause <= `CAUSE_EBREAK; | ||||
|           end | ||||
|         end | ||||
| 
 | ||||
|         HALTED : begin | ||||
|           if (ResumeReq) begin | ||||
|             if (Step) begin | ||||
|               Counter <= NOP_CYCLE_DURATION; | ||||
|               State <= FLUSH; | ||||
|               DebugCause <= `CAUSE_STEP; | ||||
|             end else begin | ||||
|               State <= RUNNING; | ||||
|               ResumeAck <= 1; | ||||
|             end | ||||
|           if (ResumeReq) | ||||
|             State <= RESUME; | ||||
|         end | ||||
| 
 | ||||
|         // Wait a cycle to load PCF from DPC before resuming
 | ||||
|         // TODO: test without resume stage
 | ||||
|         RESUME : begin | ||||
|           if (Step) begin | ||||
|             Counter <= E2M_CYCLE_COUNT; | ||||
|             State <= STEP; | ||||
|           end else begin | ||||
|             State <= RUNNING; | ||||
|             ResumeAck <= 1; | ||||
|           end | ||||
|         end | ||||
| 
 | ||||
|         STEP : begin | ||||
|           if (~|Counter) begin | ||||
|             DebugCause <= `CAUSE_STEP; | ||||
|             State <= HALTED; | ||||
|           end else | ||||
|             Counter <= Counter - 1; | ||||
|         end | ||||
|       endcase | ||||
|     end | ||||
|   end | ||||
|  | ||||
| @ -108,9 +108,8 @@ module hazard import cvw::*;  #(parameter cvw_t P) ( | ||||
|   assign LatestUnstalledW = ~StallW & StallM; | ||||
|    | ||||
|   // Each stage flushes if the previous stage is the last one stalled (for cause) or the system has reason to flush
 | ||||
|   // Do not flush if halted for Debug
 | ||||
|   assign FlushD = ~DebugStall & (LatestUnstalledD | FlushDCause); | ||||
|   assign FlushE = ~DebugStall & (LatestUnstalledE | FlushECause); | ||||
|   assign FlushM = ~DebugStall & (LatestUnstalledM | FlushMCause); | ||||
|   assign FlushW = ~DebugStall & (LatestUnstalledW | FlushWCause); | ||||
|   assign FlushD = (LatestUnstalledD | FlushDCause); | ||||
|   assign FlushE = (LatestUnstalledE | FlushECause); | ||||
|   assign FlushM = (LatestUnstalledM | FlushMCause); | ||||
|   assign FlushW = (LatestUnstalledW | FlushWCause); | ||||
| endmodule | ||||
|  | ||||
| @ -98,11 +98,13 @@ module ifu import cvw::*;  #(parameter cvw_t P) ( | ||||
|   output logic                 ICacheAccess,                             // Report I$ read to performance counters
 | ||||
|   output logic                 ICacheMiss,                               // Report I$ miss to performance counters
 | ||||
|   // Debug Mode logic
 | ||||
|   output logic [P.XLEN-1:0]    PCNextF,                                  // Next PCF, selected from Branch predictor, Privilege, or PC+2/4
 | ||||
|   input  logic                 ExitDebugMode, | ||||
|   input  logic [P.XLEN-1:0]    DPC, | ||||
|   output logic [P.XLEN-1:0]    PCNextF,                                  // Next PCF, selected from Branch predictor, Privilege, or PC+2/4
 | ||||
|   input  logic                 ForceNOP, | ||||
|   input  logic                 ProgBuffScanEn, | ||||
|   // Debug scan chain
 | ||||
|   input  logic [3:0]           ProgBufAddr, | ||||
|   input  logic                 ProgBufScanIn, | ||||
|   input  logic                 DebugScanEn, | ||||
|   input  logic                 DebugScanIn, | ||||
|   output logic                 DebugScanOut | ||||
| @ -111,7 +113,6 @@ module ifu import cvw::*;  #(parameter cvw_t P) ( | ||||
|   localparam [31:0]            nop = 32'h00000013;                       // instruction for NOP
 | ||||
|   localparam            LINELEN = P.ICACHE_SUPPORTED ? P.ICACHE_LINELENINBITS : P.XLEN; | ||||
| 
 | ||||
|   logic [P.XLEN-1:0]           PCNextFM;                                 // (muxed for debug) Next PCF, selected from Branch predictor, Privilege, or PC+2/4
 | ||||
|   logic [P.XLEN-1:0]           PC1NextF;                                 // Branch predictor next PCF
 | ||||
|   logic [P.XLEN-1:0]           PC2NextF;                                 // Selected PC between branch prediction and next valid PC if CSRWriteFence
 | ||||
|   logic [P.XLEN-1:0]           UnalignedPCNextF;                         // The next PCF, but not aligned to 2 bytes. 
 | ||||
| @ -128,6 +129,7 @@ module ifu import cvw::*;  #(parameter cvw_t P) ( | ||||
|   logic [31:0]                 IROMInstrF;                               // Instruction from the IROM
 | ||||
|   logic [31:0]                 ICacheInstrF;                             // Instruction from the I$
 | ||||
|   logic [31:0]                 InstrRawF;                                // Instruction from the IROM, I$, or bus
 | ||||
|   logic [31:0]                 ProgBufInstrF;                            // Instruction from the ProgBuf
 | ||||
|   logic                        CompressedF, CompressedE;                 // The fetched instruction is compressed
 | ||||
|   logic [31:0]                 PostSpillInstrRawF;                       // Fetch instruction after merge two halves of spill
 | ||||
|   logic [31:0]                 InstrRawD;                                // Non-decompressed instruction in the Decode stage
 | ||||
| @ -146,6 +148,7 @@ module ifu import cvw::*;  #(parameter cvw_t P) ( | ||||
|   logic                        BusCommittedF;                            // Bus memory operation in flight, delay interrupts
 | ||||
|   logic                        CacheCommittedF;                          // I$ memory operation started, delay interrupts
 | ||||
|   logic                        SelIROM;                                  // PMA indicates instruction address is in the IROM
 | ||||
|   logic                        SelProgBuf;                               // PMA indicates instruction address is in Program Buffer
 | ||||
|   logic [15:0]                 InstrRawE, InstrRawM; | ||||
|   logic [LINELEN-1:0]          FetchBuffer; | ||||
|   logic [31:0]                 ShiftUncachedInstr; | ||||
| @ -196,7 +199,7 @@ module ifu import cvw::*;  #(parameter cvw_t P) ( | ||||
|          .TLBFlush, | ||||
|          .PhysicalAddress(PCPF), | ||||
|          .TLBMiss(ITLBMissF), | ||||
|          .Cacheable(CacheableF), .Idempotent(), .SelTIM(SelIROM), | ||||
|          .Cacheable(CacheableF), .Idempotent(), .SelTIM(SelIROM), .SelProgBuf, | ||||
|          .InstrAccessFaultF, .LoadAccessFaultM(), .StoreAmoAccessFaultM(), | ||||
|          .InstrPageFaultF, .LoadPageFaultM(), .StoreAmoPageFaultM(), | ||||
|          .LoadMisalignedFaultM(), .StoreAmoMisalignedFaultM(), | ||||
| @ -209,6 +212,7 @@ module ifu import cvw::*;  #(parameter cvw_t P) ( | ||||
|     assign PCPF = PCFExt[P.PA_BITS-1:0]; | ||||
|     assign CacheableF = 1'b1; | ||||
|     assign SelIROM = '0; | ||||
|     assign SelProgBuf = '0; | ||||
|   end | ||||
| 
 | ||||
|   ////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| @ -218,7 +222,7 @@ module ifu import cvw::*;  #(parameter cvw_t P) ( | ||||
|   // CommittedM tells the CPU's privileged unit the current instruction
 | ||||
|   // in the memory stage is a memory operaton and that memory operation is either completed
 | ||||
|   // or is partially executed. Partially completed memory operations need to prevent an interrupts.
 | ||||
|   // There is not a clean way to restore back to a partial executed instruction.  CommiteedM will
 | ||||
|   // There is not a clean way to restore back to a partial executed instruction.  CommittedM will
 | ||||
|   // delay the interrupt until the LSU is in a clean state.
 | ||||
|   assign CommittedF = CacheCommittedF | BusCommittedF; | ||||
| 
 | ||||
| @ -314,7 +318,14 @@ module ifu import cvw::*;  #(parameter cvw_t P) ( | ||||
|   assign IFUStallF = IFUCacheBusStallF | SelSpillNextF; | ||||
|   assign GatedStallD = StallD & ~SelSpillNextF; | ||||
|    | ||||
|   flopenl #(32) AlignedInstrRawDFlop(clk, reset | FlushD, ~StallD, PostSpillInstrRawF, nop, InstrRawD); | ||||
|   if (P.DEBUG_SUPPORTED) begin | ||||
|     logic [31:0] PostSpillInstrRawFM; | ||||
|     progbuf #(P) progbuf(.clk, .reset, .Addr(PCNextF[3:0]), .ProgBufInstrF, .ScanAddr(ProgBufAddr), .Scan(ProgBuffScanEn), .ScanIn(ProgBufScanIn)); | ||||
|     assign PostSpillInstrRawFM = SelProgBuf ? ProgBufInstrF : PostSpillInstrRawF; | ||||
|     flopenl #(32) AlignedInstrRawDFlop(clk, reset | FlushD, ~StallD, PostSpillInstrRawFM, nop, InstrRawD); | ||||
|   end else begin | ||||
|     flopenl #(32) AlignedInstrRawDFlop(clk, reset | FlushD, ~StallD, PostSpillInstrRawF, nop, InstrRawD); | ||||
|   end | ||||
| 
 | ||||
|   ////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
|   // PCNextF logic
 | ||||
| @ -324,10 +335,11 @@ module ifu import cvw::*;  #(parameter cvw_t P) ( | ||||
|     mux2 #(P.XLEN) pcmux2(.d0(PC1NextF), .d1(NextValidPCE), .s(CSRWriteFenceM),.y(PC2NextF)); | ||||
|   else assign PC2NextF = PC1NextF; | ||||
| 
 | ||||
| 
 | ||||
|   mux3 #(P.XLEN) pcmux3(PC2NextF, EPCM, TrapVectorM, {TrapM, RetM}, UnalignedPCNextF); | ||||
| 
 | ||||
|   if (P.DEBUG_SUPPORTED) begin | ||||
|     mux2 #(P.XLEN) pcresetmux({UnalignedPCNextF[P.XLEN-1:1], 1'b0}, P.RESET_VECTOR[P.XLEN-1:0], reset, PCNextFM); | ||||
|     assign PCNextF = ExitDebugMode ? DPC : PCNextFM; | ||||
|     mux3 #(P.XLEN) pcresetmux(.d2(P.RESET_VECTOR[P.XLEN-1:0]), .d1(DPC), .d0({UnalignedPCNextF[P.XLEN-1:1], 1'b0}), .s({reset,ExitDebugMode}), .y(PCNextF)); | ||||
|     flopen #(P.XLEN) pcreg(clk, ~StallF | reset | ExitDebugMode, PCNextF, PCF); | ||||
|   end else begin | ||||
|     mux2 #(P.XLEN) pcresetmux({UnalignedPCNextF[P.XLEN-1:1], 1'b0}, P.RESET_VECTOR[P.XLEN-1:0], reset, PCNextF); | ||||
|  | ||||
							
								
								
									
										69
									
								
								src/ifu/progbuf.sv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								src/ifu/progbuf.sv
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | ||||
| ///////////////////////////////////////////
 | ||||
| // progbuf.sv
 | ||||
| //
 | ||||
| // Written: matthew.n.otto@okstate.edu
 | ||||
| // Created: 18 June 2024
 | ||||
| //
 | ||||
| // Purpose: Holds small programs to be executed in debug mode
 | ||||
| //          This module acts like a small ROM except it can be written by serial Scanning via the Debug Module
 | ||||
| //
 | ||||
| // A component of the CORE-V-WALLY configurable RISC-V project.
 | ||||
| // https://github.com/openhwgroup/cvw
 | ||||
| // 
 | ||||
| // Copyright (C) 2021-24 Harvey Mudd College & Oklahoma State University
 | ||||
| //
 | ||||
| // SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
 | ||||
| //
 | ||||
| // Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file 
 | ||||
| // except in compliance with the License, or, at your option, the Apache License Version 2.0. You 
 | ||||
| // may obtain a copy of the License at
 | ||||
| //
 | ||||
| // https://solderpad.org/licenses/SHL-2.1/
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, any work distributed under the 
 | ||||
| // License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
 | ||||
| // either express or implied. See the License for the specific language governing permissions 
 | ||||
| // and limitations under the License.
 | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| module progbuf import cvw::*;  #(parameter cvw_t P) ( | ||||
|     input  logic        clk, reset, | ||||
|     input  logic [3:0]  Addr, | ||||
|     output logic [31:0] ProgBufInstrF, | ||||
| 
 | ||||
|     input  logic [3:0]  ScanAddr, | ||||
|     input  logic        Scan, | ||||
|     input  logic        ScanIn | ||||
| ); | ||||
| 
 | ||||
|   localparam PROGBUF_SIZE = (P.PROGBUF_RANGE+1)/4; | ||||
|   localparam ADDR_WIDTH = $clog2(PROGBUF_SIZE); | ||||
|    | ||||
|   bit [31:0] RAM [PROGBUF_SIZE-1:0]; | ||||
| 
 | ||||
|   logic EnPrevClk; | ||||
|   logic WriteProgBuf; | ||||
|   logic [32:0] WriteData; | ||||
|   logic [ADDR_WIDTH-1:0] AddrM; | ||||
| 
 | ||||
|   flopr #(1) Scanenhist (.clk, .reset, .d(Scan), .q(EnPrevClk)); | ||||
|   assign WriteProgBuf = ~Scan & EnPrevClk; | ||||
| 
 | ||||
|   assign WriteData[32] = ScanIn; | ||||
|   genvar i; | ||||
|   for (i=0; i<32; i=i+1) begin | ||||
|     flopenr #(1) Scanreg (.clk, .reset, .en(Scan), .d(WriteData[i+1]), .q(WriteData[i])); | ||||
|   end | ||||
| 
 | ||||
|   assign AddrM = WriteProgBuf ? ScanAddr[ADDR_WIDTH-1:0] : Addr[ADDR_WIDTH-1:0]; | ||||
| 
 | ||||
|   always_ff @(posedge clk) begin | ||||
|     if (WriteProgBuf) | ||||
|       RAM[AddrM] <= WriteData; | ||||
|     if (reset) | ||||
|       ProgBufInstrF <= 0; | ||||
|     else | ||||
|       ProgBufInstrF <= RAM[AddrM]; | ||||
|   end | ||||
| 
 | ||||
| endmodule | ||||
| @ -33,7 +33,7 @@ module adrdecs import cvw::*;  #(parameter cvw_t P) ( | ||||
|   input  logic [P.PA_BITS-1:0] PhysicalAddress, | ||||
|   input  logic                 AccessRW, AccessRX, AccessRWXC, | ||||
|   input  logic [1:0]           Size, | ||||
|   output logic [11:0]          SelRegions | ||||
|   output logic [12:0]          SelRegions | ||||
| ); | ||||
| 
 | ||||
|   localparam logic [3:0]       SUPPORTED_SIZE = (P.LLEN == 32 ? 4'b0111 : 4'b1111); | ||||
| @ -49,6 +49,7 @@ module adrdecs import cvw::*;  #(parameter cvw_t P) ( | ||||
|   adrdec #(P.PA_BITS) plicdec(PhysicalAddress, P.PLIC_BASE[P.PA_BITS-1:0], P.PLIC_RANGE[P.PA_BITS-1:0], P.PLIC_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[9]); | ||||
|   adrdec #(P.PA_BITS) sdcdec(PhysicalAddress, P.SDC_BASE[P.PA_BITS-1:0], P.SDC_RANGE[P.PA_BITS-1:0], P.SDC_SUPPORTED, AccessRW, Size, SUPPORTED_SIZE & 4'b1100, SelRegions[10]);  | ||||
|   adrdec #(P.PA_BITS) spidec(PhysicalAddress, P.SPI_BASE[P.PA_BITS-1:0], P.SPI_RANGE[P.PA_BITS-1:0], P.SPI_SUPPORTED, AccessRW, Size, 4'b0100, SelRegions[11]); | ||||
|   adrdec #(P.PA_BITS) progbufdec(PhysicalAddress, P.PROGBUF_BASE[P.PA_BITS-1:0], P.PROGBUF_RANGE[P.PA_BITS-1:0], P.DEBUG_SUPPORTED, AccessRX, Size, SUPPORTED_SIZE, SelRegions[12]); | ||||
| 
 | ||||
|   assign SelRegions[0] = ~|(SelRegions[11:1]); // none of the regions are selected
 | ||||
| endmodule | ||||
|  | ||||
| @ -50,6 +50,7 @@ module mmu import cvw::*;  #(parameter cvw_t P, | ||||
|   output logic                 Cacheable,          // PMA indicates memory address is cachable
 | ||||
|   output logic                 Idempotent,         // PMA indicates memory address is idempotent
 | ||||
|   output logic                 SelTIM,             // Select a tightly integrated memory
 | ||||
|   output logic                 SelProgBuf,         // Select ProgBuf
 | ||||
|   // Faults
 | ||||
|   output logic                 InstrAccessFaultF, LoadAccessFaultM, StoreAmoAccessFaultM, // access fault sources
 | ||||
|   output logic                 InstrPageFaultF, LoadPageFaultM, StoreAmoPageFaultM,       // page fault sources
 | ||||
| @ -112,7 +113,7 @@ module mmu import cvw::*;  #(parameter cvw_t P, | ||||
| 
 | ||||
|   pmachecker #(P) pmachecker(.PhysicalAddress, .Size, .CMOpM,  | ||||
|     .AtomicAccessM, .ExecuteAccessF, .WriteAccessM, .ReadAccessM, .PBMemoryType, | ||||
|     .Cacheable, .Idempotent, .SelTIM,  | ||||
|     .Cacheable, .Idempotent, .SelTIM, .SelProgBuf, | ||||
|     .PMAInstrAccessFaultF, .PMALoadAccessFaultM, .PMAStoreAmoAccessFaultM); | ||||
|   | ||||
|   if (P.PMP_ENTRIES > 0) begin : pmp | ||||
|  | ||||
| @ -38,7 +38,7 @@ module pmachecker import cvw::*;  #(parameter cvw_t P) ( | ||||
|   input  logic                 WriteAccessM,   // Write access 
 | ||||
|   input  logic                 ReadAccessM,    // Read access
 | ||||
|   input  logic [1:0]           PBMemoryType,     // PBMT field of PTE during TLB hit, or 00 otherwise
 | ||||
|   output logic                 Cacheable, Idempotent, SelTIM, | ||||
|   output logic                 Cacheable, Idempotent, SelTIM, SelProgBuf, | ||||
|   output logic                 PMAInstrAccessFaultF, | ||||
|   output logic                 PMALoadAccessFaultM, | ||||
|   output logic                 PMAStoreAmoAccessFaultM | ||||
| @ -46,7 +46,7 @@ module pmachecker import cvw::*;  #(parameter cvw_t P) ( | ||||
| 
 | ||||
|   logic                        PMAAccessFault; | ||||
|   logic                        AccessRW, AccessRWXC, AccessRX; | ||||
|   logic [11:0]                 SelRegions; | ||||
|   logic [12:0]                 SelRegions; | ||||
|   logic                        AtomicAllowed; | ||||
|   logic                        CacheableRegion, IdempotentRegion; | ||||
| 
 | ||||
| @ -72,6 +72,9 @@ module pmachecker import cvw::*;  #(parameter cvw_t P) ( | ||||
|   // Check if tightly integrated memories are selected
 | ||||
|   assign SelTIM = SelRegions[1] | SelRegions[2]; // exclusion-tag: unused-tim
 | ||||
| 
 | ||||
|   // Debug program buffer
 | ||||
|   assign SelProgBuf = SelRegions[12]; | ||||
| 
 | ||||
|   // Detect access faults
 | ||||
|   assign PMAAccessFault          = SelRegions[0] & AccessRWXC | AtomicAccessM & ~AtomicAllowed;   | ||||
|   assign PMAInstrAccessFaultF    = ExecuteAccessF & PMAAccessFault; | ||||
|  | ||||
| @ -96,9 +96,9 @@ module csr import cvw::*;  #(parameter cvw_t P) ( | ||||
|   // Debug Mode output
 | ||||
|   input  logic                     DebugMode, | ||||
|   input  logic [2:0]               DebugCause, | ||||
|   output logic                     ebreakEn, | ||||
|   output logic                     Step, | ||||
|   output logic [P.XLEN-1:0]        DPC, | ||||
|   input  logic [P.XLEN-1:0]        PCNextF, | ||||
|   input  logic                     EnterDebugMode, | ||||
|   // Debug scan chain
 | ||||
|   input  logic                     DebugSel, | ||||
| @ -215,10 +215,10 @@ module csr import cvw::*;  #(parameter cvw_t P) ( | ||||
|   ///////////////////////////////////////////
 | ||||
| 
 | ||||
|   assign CSRAdrM = InstrM[31:20]; | ||||
|   assign UnalignedNextEPCM = TrapM ? PCM : CSRWriteValDM; | ||||
|   assign UnalignedNextEPCM = TrapM ? PCM : CSRWriteValM; | ||||
|   assign NextEPCM = P.ZCA_SUPPORTED ? {UnalignedNextEPCM[P.XLEN-1:1], 1'b0} : {UnalignedNextEPCM[P.XLEN-1:2], 2'b00}; // 3.1.15 alignment
 | ||||
|   assign NextCauseM = TrapM ? {InterruptM, CauseM}: {CSRWriteValDM[P.XLEN-1], CSRWriteValDM[3:0]}; | ||||
|   assign NextMtvalM = TrapM ? NextFaultMtvalM : CSRWriteValDM; | ||||
|   assign NextCauseM = TrapM ? {InterruptM, CauseM}: {CSRWriteValM[P.XLEN-1], CSRWriteValM[3:0]}; | ||||
|   assign NextMtvalM = TrapM ? NextFaultMtvalM : CSRWriteValM; | ||||
|   assign UngatedCSRMWriteM = CSRWriteDM & (PrivilegeModeW == P.M_MODE); | ||||
|   assign CSRMWriteM = UngatedCSRMWriteM & InstrValidNotFlushedM; | ||||
|   assign CSRSWriteM = CSRWriteDM & (|PrivilegeModeW) & InstrValidNotFlushedM; | ||||
| @ -305,7 +305,7 @@ module csr import cvw::*;  #(parameter cvw_t P) ( | ||||
|   if (P.DEBUG_SUPPORTED) begin:csrd | ||||
|     csrd #(P) csrd(.clk, .reset, .DebugMode, .PrivilegeModeW, | ||||
|     .CSRWriteDM, .CSRAdrM(CSRAdrDM), .CSRWriteValM(CSRWriteValDM), .CSRDReadValM, .IllegalCSRDAccessM, | ||||
|     .DebugCause, .Step, .DPC, .PCNextF, .EnterDebugMode); | ||||
|     .DebugCause, .ebreakEn, .Step, .DPC, .PCM, .EnterDebugMode); | ||||
|   end else begin | ||||
|     assign CSRDReadValM = '0; | ||||
|     assign IllegalCSRDAccessM = 1'b1; // Debug isn't supported
 | ||||
|  | ||||
| @ -35,12 +35,12 @@ module csrd import cvw::*;  #(parameter cvw_t P) ( | ||||
|   input  logic [P.XLEN-1:0] CSRWriteValM, | ||||
|   output logic [P.XLEN-1:0] CSRDReadValM, | ||||
|   output logic              IllegalCSRDAccessM, | ||||
| 
 | ||||
|   input  logic [P.XLEN-1:0] PCM, | ||||
|   input  logic              EnterDebugMode, | ||||
|   input  logic [2:0]        DebugCause, | ||||
|   output logic              ebreakEn, | ||||
|   output logic              Step, | ||||
|   output logic [P.XLEN-1:0] DPC, | ||||
|   input  logic [P.XLEN-1:0] PCNextF, | ||||
|   input  logic              EnterDebugMode | ||||
|   output logic [P.XLEN-1:0] DPC | ||||
| ); | ||||
|   `include "debug.vh" | ||||
| 
 | ||||
| @ -58,8 +58,8 @@ module csrd import cvw::*;  #(parameter cvw_t P) ( | ||||
|   const logic       ebreakVS = 0; | ||||
|   const logic       ebreakVU = 0; | ||||
|   logic             ebreakM; | ||||
|   logic             ebreakS; | ||||
|   logic             ebreakU; | ||||
|   const logic       ebreakS = 0; | ||||
|   const logic       ebreakU = 0; | ||||
|   const logic       StepIE = 0; | ||||
|   const logic       StopCount = 0; | ||||
|   const logic       StopTime = 0; | ||||
| @ -69,7 +69,8 @@ module csrd import cvw::*;  #(parameter cvw_t P) ( | ||||
|   logic             NMIP;      // pending non-maskable interrupt
 | ||||
|   logic [1:0]       Prv; | ||||
| 
 | ||||
| 
 | ||||
|    | ||||
|   assign ebreakEn = ebreakM; // Only support ebreak from M mode
 | ||||
|   assign CSRDWriteM = CSRWriteDM & (PrivilegeModeW == P.M_MODE) & DebugMode; | ||||
| 
 | ||||
|   assign WriteDCSRM = CSRDWriteM & (CSRAdrM == DCSR_ADDR); | ||||
| @ -85,15 +86,13 @@ module csrd import cvw::*;  #(parameter cvw_t P) ( | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   flopenr #(4) DCSRreg (clk, reset, WriteDCSRM,  | ||||
|     {CSRWriteValM[`EBREAKM], CSRWriteValM[`EBREAKS], CSRWriteValM[`EBREAKU], CSRWriteValM[`STEP]},  | ||||
|     {ebreakM, ebreakS, ebreakU, Step}); | ||||
|   flopenr #(4) DCSRreg (clk, reset, WriteDCSRM, {CSRWriteValM[`EBREAKM], CSRWriteValM[`STEP]}, {ebreakM, Step}); | ||||
| 
 | ||||
|   assign DCSR = {DebugVer, 10'b0, ebreakVS, ebreakVU, ebreakM, 1'b0, ebreakS, ebreakU, StepIE, | ||||
|                       StopCount, StopTime, Cause, V, MPrvEn, NMIP, Step, Prv}; | ||||
| 
 | ||||
|   assign DPCWriteVal = EnterDebugMode ? PCNextF : CSRWriteValM; | ||||
|   flopenr #(P.XLEN) DPCreg (clk, reset, WriteDPCM | EnterDebugMode, DPCWriteVal, DPC); | ||||
|   assign DPCWriteVal = EnterDebugMode ? PCM : CSRWriteValM; | ||||
|   flopenr #(P.XLEN) DPCreg (clk, reset, WriteDPCM | EnterDebugMode, DPCWriteVal, DPC); // TODO: reset to something sane (0x80000000?)
 | ||||
| 
 | ||||
|   always_comb begin | ||||
|     CSRDReadValM = '0; | ||||
|  | ||||
| @ -30,7 +30,8 @@ | ||||
| 
 | ||||
| module privdec import cvw::*;  #(parameter cvw_t P) ( | ||||
|   input  logic         clk, reset, | ||||
|   input  logic         StallW, FlushW,  | ||||
|   input  logic         StallW, FlushW, | ||||
|   input  logic         ForceBreakPoint,                             // Debug Module initiated break to debug mode
 | ||||
|   input  logic [31:15] InstrM,                              // privileged instruction function field
 | ||||
|   input  logic         PrivilegedM,                         // is this a privileged instruction (from IEU controller)
 | ||||
|   input  logic         IllegalIEUFPUInstrM,                 // Not a legal IEU instruction
 | ||||
| @ -40,13 +41,14 @@ module privdec import cvw::*;  #(parameter cvw_t P) ( | ||||
|   output logic         IllegalInstrFaultM,                  // Illegal instruction
 | ||||
|   output logic         EcallFaultM, BreakpointFaultM,       // Ecall or breakpoint; must retire, so don't flush it when the trap occurs
 | ||||
|   output logic         sretM, mretM, RetM,                  // return instructions
 | ||||
|   output logic         wfiM, wfiW, sfencevmaM               // wfi / sfence.vma / sinval.vma instructions
 | ||||
|   output logic         wfiM, wfiW, sfencevmaM,              // wfi / sfence.vma / sinval.vma instructions
 | ||||
|   output logic         ebreakM                              // ebreak instruction
 | ||||
| ); | ||||
| 
 | ||||
|   logic                rs1zeroM;                            // rs1 field = 0
 | ||||
|   logic                IllegalPrivilegedInstrM;             // privileged instruction isn't a legal one or in legal mode
 | ||||
|   logic                WFITimeoutM;                         // WFI reaches timeout threshold
 | ||||
|   logic                ebreakM, ecallM;                     // ebreak / ecall instructions
 | ||||
|   logic                ecallM;                              // ecall instructions
 | ||||
|   logic                sinvalvmaM;                          // sinval.vma
 | ||||
|   logic                sfencewinvalM, sfenceinvalirM;       // sfence.w.inval, sfence.inval.ir
 | ||||
|   logic                invalM;                              // any of the svinval instructions
 | ||||
| @ -94,7 +96,10 @@ module privdec import cvw::*;  #(parameter cvw_t P) ( | ||||
|   // Extract exceptions by name and handle them 
 | ||||
|   ///////////////////////////////////////////
 | ||||
| 
 | ||||
|   assign BreakpointFaultM = ebreakM; // could have other causes from a debugger
 | ||||
|   if (P.DEBUG_SUPPORTED) | ||||
|     assign BreakpointFaultM = ebreakM | ForceBreakPoint; | ||||
|   else | ||||
|     assign BreakpointFaultM = ebreakM; | ||||
|   assign EcallFaultM = ecallM; | ||||
| 
 | ||||
|   ///////////////////////////////////////////
 | ||||
|  | ||||
| @ -97,12 +97,14 @@ module privileged import cvw::*;  #(parameter cvw_t P) ( | ||||
|   output logic              BigEndianM,                                     // Use big endian in current privilege mode
 | ||||
|   // Fault outputs                                                         
 | ||||
|   output logic              wfiM, IntPendingM,                              // Stall in Memory stage for WFI until interrupt pending or timeout
 | ||||
|   output logic              ebreakM,                                        // Notifies DM to enter debug mode
 | ||||
|   // Debuge Mode
 | ||||
|   output logic              ebreakEn, | ||||
|   input  logic              ForceBreakPoint, | ||||
|   input  logic              DebugMode, | ||||
|   input  logic [2:0]        DebugCause, | ||||
|   output logic              Step, | ||||
|   output logic [P.XLEN-1:0] DPC, | ||||
|   input  logic [P.XLEN-1:0] PCNextF, | ||||
|   input  logic              EnterDebugMode, | ||||
|   // Debug scan chain
 | ||||
|   input  logic              DebugSel, | ||||
| @ -142,9 +144,9 @@ module privileged import cvw::*;  #(parameter cvw_t P) ( | ||||
| 
 | ||||
|   // decode privileged instructions
 | ||||
|   privdec #(P) pmd(.clk, .reset, .StallW, .FlushW, .InstrM(InstrM[31:15]),  | ||||
|     .PrivilegedM, .IllegalIEUFPUInstrM, .IllegalCSRAccessM,  | ||||
|     .PrivilegedM, .IllegalIEUFPUInstrM, .IllegalCSRAccessM, .ForceBreakPoint, | ||||
|     .PrivilegeModeW, .STATUS_TSR, .STATUS_TVM, .STATUS_TW, .IllegalInstrFaultM,  | ||||
|     .EcallFaultM, .BreakpointFaultM, .sretM, .mretM, .RetM, .wfiM, .wfiW, .sfencevmaM); | ||||
|     .EcallFaultM, .BreakpointFaultM, .sretM, .mretM, .RetM, .wfiM, .wfiW, .sfencevmaM, .ebreakM); | ||||
| 
 | ||||
|   // Control and Status Registers
 | ||||
|   csr #(P) csr(.clk, .reset, .FlushM, .FlushW, .StallE, .StallM, .StallW, | ||||
| @ -163,7 +165,7 @@ module privileged import cvw::*;  #(parameter cvw_t P) ( | ||||
|     .SetFflagsM, .FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .ENVCFG_ADUE, | ||||
|     .EPCM, .TrapVectorM, | ||||
|     .CSRReadValW, .IllegalCSRAccessM, .BigEndianM, | ||||
|     .DebugMode, .DebugCause, .Step, .DPC, .PCNextF, .EnterDebugMode, | ||||
|     .DebugMode, .DebugCause, .ebreakEn, .Step, .DPC, .EnterDebugMode, | ||||
|     .DebugSel, .DebugRegAddr, .DebugCapture, .DebugRegUpdate, .DebugScanEn, .DebugScanIn, .DebugScanOut); | ||||
| 
 | ||||
|   // pipeline early-arriving trap sources
 | ||||
|  | ||||
| @ -53,6 +53,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( | ||||
|    output logic                  ResumeAck, | ||||
|    output logic                  HaveReset, | ||||
|    output logic                  DebugStall, | ||||
|    input  logic                  ExecProgBuff, | ||||
|    // Debug scan chain
 | ||||
|    input  logic                  DebugScanEn,    // puts scannable flops into scan mode
 | ||||
|    output logic                  DebugScanOut,   // (misc) scan chain data out
 | ||||
| @ -66,13 +67,16 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( | ||||
|    input  logic                  CSRSel,         // selects CSR scan chain
 | ||||
|    input  logic [11:0]           DebugRegAddr,   // address for scanable regfiles (GPR, FPR, CSR)
 | ||||
|    input  logic                  DebugCapture,   // latches values into scan register before scanning out
 | ||||
|    input  logic                  DebugRegUpdate  // writes values from scan register after scanning in							       							       
 | ||||
|    input  logic                  DebugRegUpdate,  // writes values from scan register after scanning in	
 | ||||
|    input  logic [3:0]            ProgBufAddr, | ||||
|    input  logic                  ProgBuffScanEn | ||||
| ); | ||||
| 
 | ||||
|   logic                          StallF, StallD, StallE, StallM, StallW; | ||||
|   logic                          FlushD, FlushE, FlushM, FlushW; | ||||
|   logic                          TrapM, RetM; | ||||
|   logic                          DebugMode, Step; | ||||
|   logic                          ebreakEn; | ||||
| 
 | ||||
|   //  signals that must connect through DP
 | ||||
|   logic                          IntDivE, W64E; | ||||
| @ -190,13 +194,14 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( | ||||
|   logic                          BranchD, BranchE, JumpD, JumpE; | ||||
|   logic                          DCacheStallM, ICacheStallF; | ||||
|   logic                          wfiM, IntPendingM; | ||||
|   logic                          ebreakM; | ||||
| 
 | ||||
|   // Debug mode logic
 | ||||
|   logic [P.XLEN-1:0]             DPC, PCNextF; | ||||
|   logic                          ExitDebugMode; | ||||
|   logic                          EnterDebugMode; | ||||
|   logic [2:0]                    DebugCause; | ||||
|   logic                          ForceNOP; | ||||
|   logic                          ForceBreakPoint; | ||||
|   // Debug register scan chain interconnects
 | ||||
|   logic [2:0]                    DebugScanReg; | ||||
| 
 | ||||
| @ -222,7 +227,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( | ||||
|     .STATUS_MPP, .ENVCFG_PBMTE, .ENVCFG_ADUE, .ITLBWriteF, .sfencevmaM, .ITLBMissF, | ||||
|     // pmp/pma (inside mmu) signals. 
 | ||||
|     .PMPCFG_ARRAY_REGW,  .PMPADDR_ARRAY_REGW, .InstrAccessFaultF, .InstrUpdateDAF, | ||||
|     .ExitDebugMode, .DPC, .PCNextF, .ForceNOP, | ||||
|     .ExitDebugMode, .DPC, .PCNextF, .ProgBuffScanEn, .ProgBufAddr, .ProgBufScanIn(DebugScanIn), | ||||
|     .DebugScanEn(DebugScanEn & MiscSel), .DebugScanIn(DebugScanReg[0]), .DebugScanOut(DebugScanReg[1])); | ||||
|      | ||||
|   // integer execution unit: integer register file, datapath and controller
 | ||||
| @ -320,9 +325,9 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( | ||||
|   if (P.DEBUG_SUPPORTED) begin | ||||
|     dmc debugcontrol( | ||||
|       .clk, .reset, | ||||
|       .Step, .HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset, | ||||
|       .Step, .ebreakM, .ebreakEn, .HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset, | ||||
|       .ResumeAck, .HaveReset, .DebugMode, .DebugCause, .DebugStall, | ||||
|       .EnterDebugMode, .ExitDebugMode, .ForceNOP); | ||||
|       .EnterDebugMode, .ExitDebugMode, .ForceBreakPoint); | ||||
|   end else begin | ||||
|     assign DebugStall = 1'b0; | ||||
|   end | ||||
| @ -349,8 +354,8 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( | ||||
|       .PrivilegeModeW, .SATP_REGW, | ||||
|       .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .STATUS_FS,  | ||||
|       .PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW,  | ||||
|       .FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .ENVCFG_ADUE, .wfiM, .IntPendingM, .BigEndianM, | ||||
|       .DebugMode, .DebugCause, .Step, .DPC, .PCNextF, .EnterDebugMode, | ||||
|       .FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .ENVCFG_ADUE, .wfiM, .IntPendingM, .BigEndianM, .ebreakM, | ||||
|       .ebreakEn, .ForceBreakPoint, .DebugMode, .DebugCause, .Step, .DPC, .EnterDebugMode, | ||||
|       .DebugSel(CSRSel), .DebugRegAddr, .DebugCapture, .DebugRegUpdate, .DebugScanEn(DebugScanEn & CSRSel), .DebugScanIn, .DebugScanOut(CSRScanOut)); | ||||
|     if (P.DEBUG_SUPPORTED) begin | ||||
|       flopenrs #(1) scantrapm (.clk, .reset, .en(DebugCapture), .d(TrapM), .q(), .scan(DebugScanEn), .scanin(DebugScanIn), .scanout(DebugScanReg[0])); | ||||
|  | ||||
| @ -82,6 +82,7 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P)  ( | ||||
|   logic                        ResumeAck; | ||||
|   logic                        HaveReset; | ||||
|   logic                        DebugStall; | ||||
|   logic                        ExecProgBuff; | ||||
|   // Debug Module signals
 | ||||
|   logic                        DebugScanEn; | ||||
|   logic                        DebugScanIn; | ||||
| @ -96,9 +97,8 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P)  ( | ||||
|   logic [11:0]                 DebugRegAddr; | ||||
|   logic                        DebugCapture; | ||||
|   logic                        DebugRegUpdate; | ||||
|   logic [3:0]                  ProgBufAddr; | ||||
|   logic                        ProgBuffScanEn; | ||||
|   logic                        ProgBuffScanOut; | ||||
|   logic                        ExecProgBuff; | ||||
| 
 | ||||
|   // synchronize reset to SOC clock domain
 | ||||
|   synchronizer resetsync(.clk, .d(reset_ext), .q(reset)); | ||||
| @ -108,9 +108,10 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P)  ( | ||||
|     .MTimerInt, .MExtInt, .SExtInt, .MSwInt, .MTIME_CLINT, | ||||
|     .HRDATA, .HREADY, .HRESP, .HCLK, .HRESETn, .HADDR, .HWDATA, .HWSTRB, | ||||
|     .HWRITE, .HSIZE, .HBURST, .HPROT, .HTRANS, .HMASTLOCK, | ||||
|     .HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset, .ResumeAck, .HaveReset, .DebugStall, | ||||
|     .HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset, .ResumeAck, .HaveReset, .DebugStall, .ExecProgBuff, | ||||
|     .DebugScanEn, .DebugScanOut(DebugScanIn), .GPRScanOut(GPRScanIn), .FPRScanOut(FPRScanIn), .CSRScanOut(CSRScanIn),  | ||||
|     .DebugScanIn(DebugScanOut), .MiscSel, .GPRSel, .FPRSel, .CSRSel, .DebugRegAddr, .DebugCapture, .DebugRegUpdate); | ||||
|     .DebugScanIn(DebugScanOut), .MiscSel, .GPRSel, .FPRSel, .CSRSel, .DebugRegAddr, .DebugCapture, .DebugRegUpdate, | ||||
|     .ProgBufAddr, .ProgBuffScanEn); | ||||
| 
 | ||||
|   // instantiate uncore if a bus interface exists
 | ||||
|   if (P.BUS_SUPPORTED) begin : uncoregen // Hack to work around Verilator bug https://github.com/verilator/verilator/issues/4769
 | ||||
| @ -130,7 +131,7 @@ module wallypipelinedsoc import cvw::*; #(parameter cvw_t P)  ( | ||||
|       .HaltReq, .ResumeReq, .HaltOnReset, .AckHaveReset, .ResumeAck, .HaveReset, .DebugStall, | ||||
|       .DebugScanEn, .DebugScanIn, .GPRScanIn, .FPRScanIn, .CSRScanIn, .DebugScanOut, | ||||
|       .MiscSel, .GPRSel, .FPRSel, .CSRSel, .RegAddr(DebugRegAddr), .DebugCapture, .DebugRegUpdate, | ||||
|       .ProgBuffScanEn, .ProgBuffScanOut, .ExecProgBuff); | ||||
|       .ProgBufAddr, .ProgBuffScanEn, .ExecProgBuff); | ||||
|   end | ||||
| 
 | ||||
| endmodule | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user