Files
Toooba/src_Core/Debug_Module/Debug_Module.bsv
Peter Rugg 1cfc58c2cc Fix debug module reset state machine
dmactive should only go low when the debug module has successfully
reset. Approximate this by waiting for 1024 cycles, allowing any
register access requests and system bus requests to come back.
2024-09-16 23:15:24 +01:00

354 lines
11 KiB
Plaintext

// Copyright (c) 2017-2019 Bluespec, Inc. All Rights Reserved.
//
//-
// RVFI_DII + CHERI modifications:
// Copyright (c) 2020 Alexandre Joannou
// Copyright (c) 2020 Peter Rugg
// Copyright (c) 2020 Jonathan Woodruff
// All rights reserved.
//
// This software was developed by SRI International and the University of
// Cambridge Computer Laboratory (Department of Computer Science and
// Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
// DARPA SSITH research programme.
//
// This work was supported by NCSC programme grant 4212611/RFA 15971 ("SafeBet").
//-
package Debug_Module;
// ================================================================
// This is the top-level package of a collection that implements the
// "Debug Module" specified in:
//
// "RISC-V External Debug Support"
// Version 0.13
// 7c760b0151e43523ab3d2180e7852cd6f27d942c
// Mon Jul 3 17:04:59 2017 -0700
// Note: the spec actually represents three (almost) completely
// independent functionalities:
// Run Control: to start/stop harts, query their start/stop status, etc.
// Abstract Commands: to read/write RISC-V registers and RISC-V CSRs
// System Bus Access: to read/write RISC-V memory/devices
// The only exception to complete independence is that the Run Control
// part has a 'reset' for the Debug Module itself, which includes all
// three parts.
// Unfortunately the spec is not written to make this three-part
// organization clear--aspects of the three parts are completely
// intermingled. Even the address map mixes registers from the three
// parts.
// Here, this top-level package is merely a wrapper that dispatches
// DMI requests to the three packages that implement the three parts:
// DM_Run_Control
// DM_Abstract_Commands
// DM_System_Bus
// DM_Common contains common spec-level (implementation-independent) definitions.
// ================================================================
// Our Debug Module (DM) has a two sides:
// - GDB/Host-facing
// - CPU/Platform-facing
// The GDB/Host-facing side is called DMI (Debug Module Interface) in
// the spec, and is a simple memory-like read/write interface, into a
// debug module address space (unrelated to the RISC-V memory address
// space).
// The CPU/Platform-facing side has request/response interfaces for
// CPU run-control, CPU register/CSR access and RISC-V system memory
// access.
// ================================================================
// BSV library imports
import Memory :: *;
import FIFO :: *;
import GetPut :: *;
import ClientServer :: *;
import SpecialFIFOs :: *;
import Vector :: *;
// ----------------
// Other library imports
import Semi_FIFOF :: *;
import Cur_Cycle :: *;
import AXI4 :: *;
// ================================================================
// Project imports
import ISA_Decls :: *;
import Fabric_Defs :: *;
import ProcTypes :: *;
import DM_Common :: *;
import DM_CPU_Req_Rsp :: *;
import DM_Run_Control :: *;
import DM_Abstract_Commands :: *;
import DM_System_Bus :: *;
// ================================================================
export DM_Common :: *;
export Debug_Module_IFC (..);
export mkDebug_Module;
// ================================================================
// Interface to the Debug Module
interface Debug_Module_IFC;
// ----------------
// DMI (Debug Module Interface) facing remote debugger
interface DMI dmi;
// ----------------
// Facing CPU
// This section replicated for additional harts.
// Reset and run-control
interface Vector #(CoreNum, Client #(Bool, Bool)) harts_reset_client;
interface Vector #(CoreNum, Client #(Bool, Bool)) harts_client_run_halt;
interface Vector #(CoreNum, Get #(Bit #(4))) harts_get_other_req;
interface Vector #(CoreNum, Put #(Bool)) harts_is_running;
// GPR access
interface Vector #(CoreNum, Client #(DM_CPU_Req #(5, XLEN), DM_CPU_Rsp #(XLEN))) harts_gpr_mem_client;
// FPR access
`ifdef ISA_F
interface Vector #(CoreNum, Client #(DM_CPU_Req #(5, FLEN), DM_CPU_Rsp #(FLEN))) harts_fpr_mem_client;
`endif
// CSR access
interface Vector #(CoreNum, Client #(DM_CPU_Req #(12, XLEN), DM_CPU_Rsp #(XLEN))) harts_csr_mem_client;
// ----------------
// Facing Platform
// Non-Debug-Module Reset (reset all except DM)
// Bool indicates 'running' hart state.
interface Client #(Bool, Bool) ndm_reset_client;
// Read/Write RISC-V memory
interface AXI4_Master #( Wd_CoreW_Bus_MId, Wd_Addr, Wd_Data_Periph
, Wd_AW_User_Periph, Wd_W_User_Periph, Wd_B_User_Periph
, Wd_AR_User_Periph, Wd_R_User_Periph) master;
endinterface
// ================================================================
(* synthesize *)
module mkDebug_Module (Debug_Module_IFC);
// Local verbosity: 0 = quiet; 1 = print DMI transactions
Integer verbosity = 0;
Reg #(Maybe#(DM_Reset_Count)) rg_reset_count <- mkReg(Valid(~0));
// The three parts
DM_Run_Control_IFC dm_run_control <- mkDM_Run_Control;
DM_Abstract_Commands_IFC dm_abstract_commands <- mkDM_Abstract_Commands;
DM_System_Bus_IFC dm_system_bus <- mkDM_System_Bus;
FIFO#(DM_Addr) f_read_addr <- mkFIFO1;
// ================================================================
// Reset all three parts: triggered when dm_run_control.dmactive is low
rule rl_reset_start (dm_run_control.dmactive_cleared && rg_reset_count == Invalid);
rg_reset_count <= Valid(~0);
endrule
rule rl_reset_wait (rg_reset_count matches tagged Valid .c &&& c != 0);
rg_reset_count <= Valid(c - 1);
endrule
rule rl_reset_done (rg_reset_count == Valid(0));
$display ("%0d: Debug_Module reset complete", cur_cycle);
dm_run_control.reset;
dm_abstract_commands.reset;
dm_system_bus.reset;
rg_reset_count <= Invalid;
endrule
// ================================================================
// INTERFACE
// ----------------
// Facing GDB/DMI (Debug Module Interface)
interface DMI dmi;
method Action read_addr (DM_Addr dm_addr);
f_read_addr.enq(dm_addr);
if (verbosity != 0)
$display ("%0d: %m.DMI read: dm_addr 0x%0h", cur_cycle, dm_addr);
endmethod
method ActionValue #(DM_Word) read_data;
let dm_addr = f_read_addr.first;
f_read_addr.deq;
DM_Word dm_word = ?;
if ( (dm_addr == dm_addr_dmcontrol)
|| (dm_addr == dm_addr_dmstatus)
|| (dm_addr == dm_addr_hartinfo)
|| (dm_addr == dm_addr_haltsum0)
|| (dm_addr == dm_addr_hawindowsel)
|| (dm_addr == dm_addr_hawindow)
|| (dm_addr == dm_addr_devtreeaddr0)
|| (dm_addr == dm_addr_authdata)
|| (dm_addr == dm_addr_verbosity))
dm_word <- dm_run_control.av_read (dm_addr);
else if ( (dm_addr == dm_addr_abstractcs)
|| (dm_addr == dm_addr_command)
|| (dm_addr == dm_addr_data0)
|| (dm_addr == dm_addr_data1)
|| (dm_addr == dm_addr_data2)
|| (dm_addr == dm_addr_data3)
|| (dm_addr == dm_addr_data4)
|| (dm_addr == dm_addr_data5)
|| (dm_addr == dm_addr_data6)
|| (dm_addr == dm_addr_data7)
|| (dm_addr == dm_addr_data8)
|| (dm_addr == dm_addr_data9)
|| (dm_addr == dm_addr_data10)
|| (dm_addr == dm_addr_data11)
|| (dm_addr == dm_addr_abstractauto)
|| (dm_addr == dm_addr_progbuf0))
dm_word <- dm_abstract_commands.av_read (dm_addr);
else if ( (dm_addr == dm_addr_sbcs)
|| (dm_addr == dm_addr_sbaddress0)
|| (dm_addr == dm_addr_sbaddress1)
|| (dm_addr == dm_addr_sbaddress2)
|| (dm_addr == dm_addr_sbdata0)
|| (dm_addr == dm_addr_sbdata1)
|| (dm_addr == dm_addr_sbdata2)
|| (dm_addr == dm_addr_sbdata3))
dm_word <- dm_system_bus.av_read (dm_addr);
else begin
// TODO: set error status?
dm_word = 0;
end
if (verbosity != 0)
$display ("%0d: %m.DMI read response: dm_addr 0x%0h, dm_word 0x%0h",
cur_cycle, dm_addr, dm_word);
return dm_word;
endmethod
method Action write (DM_Addr dm_addr, DM_Word dm_word);
Bool handled = False;
if (rg_reset_count == Invalid) begin
if ( (dm_addr == dm_addr_dmcontrol)
|| (dm_addr == dm_addr_dmstatus)
|| (dm_addr == dm_addr_hartinfo)
|| (dm_addr == dm_addr_haltsum0)
|| (dm_addr == dm_addr_hawindowsel)
|| (dm_addr == dm_addr_hawindow)
|| (dm_addr == dm_addr_devtreeaddr0)
|| (dm_addr == dm_addr_authdata)
|| (dm_addr == dm_addr_verbosity)) begin
dm_run_control.write (dm_addr, dm_word);
handled = True;
end
if ( (dm_addr == dm_addr_dmcontrol)
|| (dm_addr == dm_addr_abstractcs)
|| (dm_addr == dm_addr_command)
|| (dm_addr == dm_addr_data0)
|| (dm_addr == dm_addr_data1)
|| (dm_addr == dm_addr_data2)
|| (dm_addr == dm_addr_data3)
|| (dm_addr == dm_addr_data4)
|| (dm_addr == dm_addr_data5)
|| (dm_addr == dm_addr_data6)
|| (dm_addr == dm_addr_data7)
|| (dm_addr == dm_addr_data8)
|| (dm_addr == dm_addr_data9)
|| (dm_addr == dm_addr_data10)
|| (dm_addr == dm_addr_data11)
|| (dm_addr == dm_addr_abstractauto)
|| (dm_addr == dm_addr_progbuf0)) begin
dm_abstract_commands.write (dm_addr, dm_word);
handled = True;
end
if ( (dm_addr == dm_addr_sbcs)
|| (dm_addr == dm_addr_sbaddress0)
|| (dm_addr == dm_addr_sbaddress1)
|| (dm_addr == dm_addr_sbaddress2)
|| (dm_addr == dm_addr_sbdata0)
|| (dm_addr == dm_addr_sbdata1)
|| (dm_addr == dm_addr_sbdata2)
|| (dm_addr == dm_addr_sbdata3)) begin
dm_system_bus.write (dm_addr, dm_word);
handled = True;
end
end
if (! handled) begin
// TODO: set error status?
noAction;
end
if (verbosity != 0)
$display ("%0d: %m.DMI write: dm_addr 0x%0h, dm_word 0x%0h",
cur_cycle, dm_addr, dm_word);
endmethod
endinterface
// ----------------
// Facing CPU/harts
// Reset and run-control
interface harts_reset_client = dm_run_control.harts_reset_client;
interface harts_client_run_halt = dm_run_control.harts_client_run_halt;
interface harts_get_other_req = dm_run_control.harts_get_other_req;
interface harts_is_running = dm_run_control.harts_is_running;
// GPR access
interface harts_gpr_mem_client = dm_abstract_commands.harts_gpr_mem_client;
// FPR access
`ifdef ISA_F
interface harts_fpr_mem_client = dm_abstract_commands.harts_fpr_mem_client;
`endif
// CSR access
interface harts_csr_mem_client = dm_abstract_commands.harts_csr_mem_client;
// ----------------
// Facing Platform
// Non-Debug-Module Reset (reset all except DM)
interface Client ndm_reset_client = dm_run_control.ndm_reset_client;
// Read/Write RISC-V memory
interface master = dm_system_bus.master;
endmodule
// ================================================================
endpackage