hw/vendor/pulp_riscv_dbg/src/dm_mem.sv Cov: 99.3%

   1: /* Copyright 2018 ETH Zurich and University of Bologna.
   2: * Copyright and related rights are licensed under the Solderpad Hardware
   3: * License, Version 0.51 (the “License”); you may not use this file except in
   4: * compliance with the License.  You may obtain a copy of the License at
   5: * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
   6: * or agreed to in writing, software, hardware and materials distributed under
   7: * this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
   8: * CONDITIONS OF ANY KIND, either express or implied. See the License for the
   9: * specific language governing permissions and limitations under the License.
  10: *
  11: * File:   dm_mem.sv
  12: * Author: Florian Zaruba 
  13: * Date:   11.7.2018
  14: *
  15: * Description: Memory module for execution-based debug clients
  16: *
  17: */
  18: 
  19: module dm_mem #(
  20:   parameter int unsigned        NrHarts          =  1,
  21:   parameter int unsigned        BusWidth         = 32,
  22:   parameter logic [NrHarts-1:0] SelectableHarts  = {NrHarts{1'b1}}
  23: ) (
  24:   input  logic                             clk_i,       // Clock
  25:   input  logic                             rst_ni,      // debug module reset
  26: 
  27:   output logic [NrHarts-1:0]               debug_req_o,
  28:   input  logic [19:0]                      hartsel_i,
  29:   // from Ctrl and Status register
  30:   input  logic [NrHarts-1:0]               haltreq_i,
  31:   input  logic [NrHarts-1:0]               resumereq_i,
  32:   input  logic                             clear_resumeack_i,
  33: 
  34:   // state bits
  35:   output logic [NrHarts-1:0]               halted_o,    // hart acknowledge halt
  36:   output logic [NrHarts-1:0]               resuming_o,  // hart is resuming
  37: 
  38:   input  logic [dm::ProgBufSize-1:0][31:0] progbuf_i,    // program buffer to expose
  39: 
  40:   input  logic [dm::DataCount-1:0][31:0]   data_i,       // data in
  41:   output logic [dm::DataCount-1:0][31:0]   data_o,       // data out
  42:   output logic                             data_valid_o, // data out is valid
  43:   // abstract command interface
  44:   input  logic                             cmd_valid_i,
  45:   input  dm::command_t                     cmd_i,
  46:   output logic                             cmderror_valid_o,
  47:   output dm::cmderr_e                      cmderror_o,
  48:   output logic                             cmdbusy_o,
  49:   // data interface
  50: 
  51:   // SRAM interface
  52:   input  logic                             req_i,
  53:   input  logic                             we_i,
  54:   input  logic [BusWidth-1:0]              addr_i,
  55:   input  logic [BusWidth-1:0]              wdata_i,
  56:   input  logic [BusWidth/8-1:0]            be_i,
  57:   output logic [BusWidth-1:0]              rdata_o
  58: );
  59:   localparam int unsigned DbgAddressBits = 12;
  60:   localparam int unsigned HartSelLen     = (NrHarts == 1) ? 1 : $clog2(NrHarts);
  61:   localparam int unsigned NrHartsAligned = 2**HartSelLen;
  62:   localparam int unsigned MaxAar         = (BusWidth == 64) ? 4 : 3;
  63: 
  64:   localparam logic [DbgAddressBits-1:0] DataBaseAddr        = (dm::DataAddr);
  65:   localparam logic [DbgAddressBits-1:0] DataEndAddr         = (dm::DataAddr + 4*dm::DataCount);
  66:   localparam logic [DbgAddressBits-1:0] ProgBufBaseAddr     = (dm::DataAddr - 4*dm::ProgBufSize);
  67:   localparam logic [DbgAddressBits-1:0] ProgBufEndAddr      = (dm::DataAddr - 1);
  68:   localparam logic [DbgAddressBits-1:0] AbstractCmdBaseAddr = (ProgBufBaseAddr - 4*10);
  69:   localparam logic [DbgAddressBits-1:0] AbstractCmdEndAddr  = (ProgBufBaseAddr - 1);
  70: 
  71:   localparam logic [DbgAddressBits-1:0] WhereToAddr   = 'h300;
  72:   localparam logic [DbgAddressBits-1:0] FlagsBaseAddr = 'h400;
  73:   localparam logic [DbgAddressBits-1:0] FlagsEndAddr  = 'h7FF;
  74: 
  75:   localparam logic [DbgAddressBits-1:0] HaltedAddr    = 'h100;
  76:   localparam logic [DbgAddressBits-1:0] GoingAddr     = 'h104;
  77:   localparam logic [DbgAddressBits-1:0] ResumingAddr  = 'h108;
  78:   localparam logic [DbgAddressBits-1:0] ExceptionAddr = 'h10C;
  79: 
  80:   logic [dm::ProgBufSize/2-1:0][63:0]   progbuf;
  81:   logic [7:0][63:0]   abstract_cmd;
  82:   logic [NrHarts-1:0] halted_d, halted_q;
  83:   logic [NrHarts-1:0] resuming_d, resuming_q;
  84:   logic               resume, go, going;
  85: 
  86:   logic exception;
  87:   logic unsupported_command;
  88: 
  89:   logic [63:0] rom_rdata;
  90:   logic [63:0] rdata_d, rdata_q;
  91:   logic        word_enable32_q;
  92: 
  93:   // this is needed to avoid lint warnings related to array indexing
  94:   // resize hartsel to valid range
  95:   logic [HartSelLen-1:0] hartsel, wdata_hartsel;
  96: 
  97:   assign hartsel       = hartsel_i[HartSelLen-1:0];
  98:   assign wdata_hartsel = wdata_i[HartSelLen-1:0];
  99: 
 100:   logic [NrHartsAligned-1:0] resumereq_aligned, haltreq_aligned,
 101:                              halted_d_aligned, halted_q_aligned,
 102:                              halted_aligned, resumereq_wdata_aligned,
 103:                              resuming_d_aligned, resuming_q_aligned;
 104: 
 105:   assign resumereq_aligned       = NrHartsAligned'(resumereq_i);
 106:   assign haltreq_aligned         = NrHartsAligned'(haltreq_i);
 107:   assign resumereq_wdata_aligned = NrHartsAligned'(resumereq_i);
 108: 
 109:   assign halted_q_aligned        = NrHartsAligned'(halted_q);
 110:   assign halted_d                = NrHarts'(halted_d_aligned);
 111:   assign resuming_q_aligned      = NrHartsAligned'(resuming_q);
 112:   assign resuming_d              = NrHarts'(resuming_d_aligned);
 113: 
 114:   // distinguish whether we need to forward data from the ROM or the FSM
 115:   // latch the address for this
 116:   logic fwd_rom_d, fwd_rom_q;
 117:   dm::ac_ar_cmd_t ac_ar;
 118: 
 119:   // Abstract Command Access Register
 120:   assign ac_ar       = dm::ac_ar_cmd_t'(cmd_i.control);
 121:   assign debug_req_o = haltreq_i;
 122:   assign halted_o    = halted_q;
 123:   assign resuming_o  = resuming_q;
 124: 
 125:   // reshape progbuf
 126:   assign progbuf = progbuf_i;
 127: 
 128:   typedef enum logic [1:0] { Idle, Go, Resume, CmdExecuting } state_e;
 129:   state_e state_d, state_q;
 130: 
 131:   // hart ctrl queue
 132:   always_comb begin : p_hart_ctrl_queue
 133:     cmderror_valid_o = 1'b0;
 134:     cmderror_o       = dm::CmdErrNone;
 135:     state_d          = state_q;
 136:     go               = 1'b0;
 137:     resume           = 1'b0;
 138:     cmdbusy_o        = 1'b1;
 139: 
 140:     unique case (state_q)
 141:       Idle: begin
 142:         cmdbusy_o = 1'b0;
 143:         if (cmd_valid_i && halted_q_aligned[hartsel] && !unsupported_command) begin
 144:           // give the go signal
 145:           state_d = Go;
 146:         end else if (cmd_valid_i) begin
 147:           // hart must be halted for all requests
 148:           cmderror_valid_o = 1'b1;
 149:           cmderror_o = dm::CmdErrorHaltResume;
 150:         end
 151:         // CSRs want to resume, the request is ignored when the hart is
 152:         // requested to halt or it didn't clear the resuming_q bit before
 153:         if (resumereq_aligned[hartsel] && !resuming_q_aligned[hartsel] &&
 154:             !haltreq_aligned[hartsel] && halted_q_aligned[hartsel]) begin
 155:           state_d = Resume;
 156:         end
 157:       end
 158: 
 159:       Go: begin
 160:         // we are already busy here since we scheduled the execution of a program
 161:         cmdbusy_o = 1'b1;
 162:         go        = 1'b1;
 163:         // the thread is now executing the command, track its state
 164:         if (going) begin
 165:             state_d = CmdExecuting;
 166:         end
 167:       end
 168: 
 169:       Resume: begin
 170:         cmdbusy_o = 1'b1;
 171:         resume = 1'b1;
 172:         if (resuming_q_aligned[hartsel]) begin
 173:           state_d = Idle;
 174:         end
 175:       end
 176: 
 177:       CmdExecuting: begin
 178:         cmdbusy_o = 1'b1;
 179:         go        = 1'b0;
 180:         // wait until the hart has halted again
 181:         if (halted_aligned[hartsel]) begin
 182:           state_d = Idle;
 183:         end
 184:       end
 185: 
 186:       default: ;
 187:     endcase
 188: 
 189:     // only signal once that cmd is unsupported so that we can clear cmderr
 190:     // in subsequent writes to abstractcs
 191:     if (unsupported_command && cmd_valid_i) begin
 192:       cmderror_valid_o = 1'b1;
 193:       cmderror_o = dm::CmdErrNotSupported;
 194:     end
 195: 
 196:     if (exception) begin
 197:       cmderror_valid_o = 1'b1;
 198:       cmderror_o = dm::CmdErrorException;
 199:     end
 200:   end
 201: 
 202:   // word mux for 32bit and 64bit buses
 203:   logic [63:0] word_mux;
 204:   assign word_mux = (fwd_rom_q) ? rom_rdata : rdata_q;
 205: 
 206:   if (BusWidth == 64) begin : gen_word_mux64
 207:     assign rdata_o = word_mux;
 208:   end else begin : gen_word_mux32
 209:     assign rdata_o = (word_enable32_q) ? word_mux[32 +: 32] : word_mux[0 +: 32];
 210:   end
 211: 
 212:   // read/write logic
 213:   logic [63:0] data_bits;
 214:   logic [7:0][7:0] rdata;
 215:   always_comb begin : p_rw_logic
 216: 
 217:     halted_d_aligned   = NrHartsAligned'(halted_q);
 218:     resuming_d_aligned = NrHartsAligned'(resuming_q);
 219:     rdata_d        = rdata_q;
 220:     // convert the data in bits representation
 221:     data_bits      = data_i;
 222:     rdata          = '0;
 223: 
 224:     // write data in csr register
 225:     data_valid_o   = 1'b0;
 226:     exception      = 1'b0;
 227:     halted_aligned     = '0;
 228:     going          = 1'b0;
 229: 
 230:     // The resume ack signal is lowered when the resume request is deasserted
 231:     if (clear_resumeack_i) begin
 232:       resuming_d_aligned[hartsel] = 1'b0;
 233:     end
 234:     // we've got a new request
 235:     if (req_i) begin
 236:       // this is a write
 237:       if (we_i) begin
 238:         unique case (addr_i[DbgAddressBits-1:0]) inside
 239:           HaltedAddr: begin
 240:             halted_aligned[wdata_hartsel] = 1'b1;
 241:             halted_d_aligned[wdata_hartsel] = 1'b1;
 242:           end
 243:           GoingAddr: begin
 244:             going = 1'b1;
 245:           end
 246:           ResumingAddr: begin
 247:             // clear the halted flag as the hart resumed execution
 248:             halted_d_aligned[wdata_hartsel] = 1'b0;
 249:             // set the resuming flag which needs to be cleared by the debugger
 250:             resuming_d_aligned[wdata_hartsel] = 1'b1;
 251:           end
 252:           // an exception occurred during execution
 253:           ExceptionAddr: exception = 1'b1;
 254:           // core can write data registers
 255:           [(dm::DataAddr):DataEndAddr]: begin
 256:             data_valid_o = 1'b1;
 257:             for (int i = 0; i < $bits(be_i); i++) begin
 258:               if (be_i[i]) begin
 259:                 data_bits[i*8+:8] = wdata_i[i*8+:8];
 260:               end
 261:             end
 262:           end
 263:           default ;
 264:         endcase
 265: 
 266:       // this is a read
 267:       end else begin
 268:         unique case (addr_i[DbgAddressBits-1:0]) inside
 269:           // variable ROM content
 270:           WhereToAddr: begin
 271:             // variable jump to abstract cmd, program_buffer or resume
 272:             if (resumereq_wdata_aligned[wdata_hartsel]) begin
 273:               rdata_d = {32'b0, dm::jal('0, 21'(dm::ResumeAddress[11:0])-21'(WhereToAddr))};
 274:             end
 275: 
 276:             // there is a command active so jump there
 277:             if (cmdbusy_o) begin
 278:               // transfer not set is shortcut to the program buffer if postexec is set
 279:               // keep this statement narrow to not catch invalid commands
 280:               if (cmd_i.cmdtype == dm::AccessRegister &&
 281:                   !ac_ar.transfer && ac_ar.postexec) begin
 282:                 rdata_d = {32'b0, dm::jal('0, 21'(ProgBufBaseAddr)-21'(WhereToAddr))};
 283:               // this is a legit abstract cmd -> execute it
 284:               end else begin
 285:                 rdata_d = {32'b0, dm::jal('0, 21'(AbstractCmdBaseAddr)-21'(WhereToAddr))};
 286:               end
 287:             end
 288:           end
 289: 
 290:           [DataBaseAddr:DataEndAddr]: begin
 291:             rdata_d = {
 292:                       data_i[$clog2(dm::ProgBufSize)'(addr_i[DbgAddressBits-1:3] -
 293:                           DataBaseAddr[DbgAddressBits-1:3] + 1'b1)],
 294:                       data_i[$clog2(dm::ProgBufSize)'(addr_i[DbgAddressBits-1:3] -
 295:                           DataBaseAddr[DbgAddressBits-1:3])]
 296:                       };
 297:           end
 298: 
 299:           [ProgBufBaseAddr:ProgBufEndAddr]: begin
 300:             rdata_d = progbuf[$clog2(dm::ProgBufSize)'(addr_i[DbgAddressBits-1:3] -
 301:                           ProgBufBaseAddr[DbgAddressBits-1:3])];
 302:           end
 303: 
 304:           // two slots for abstract command
 305:           [AbstractCmdBaseAddr:AbstractCmdEndAddr]: begin
 306:             // return the correct address index
 307:             rdata_d = abstract_cmd[3'(addr_i[DbgAddressBits-1:3] -
 308:                            AbstractCmdBaseAddr[DbgAddressBits-1:3])];
 309:           end
 310:           // harts are polling for flags here
 311:           [FlagsBaseAddr:FlagsEndAddr]: begin
 312:             // release the corresponding hart
 313:             if (({addr_i[DbgAddressBits-1:3], 3'b0} - FlagsBaseAddr[DbgAddressBits-1:0]) ==
 314:               (DbgAddressBits'(hartsel) & {{(DbgAddressBits-3){1'b1}}, 3'b0})) begin
 315:               rdata[DbgAddressBits'(hartsel) & DbgAddressBits'(3'b111)] = {6'b0, resume, go};
 316:             end
 317:             rdata_d = rdata;
 318:           end
 319:           default: ;
 320:         endcase
 321:       end
 322:     end
 323: 
 324:     data_o = data_bits;
 325:   end
 326: 
 327:   always_comb begin : p_abstract_cmd_rom
 328:     // this abstract command is currently unsupported
 329:     unsupported_command = 1'b0;
 330:     // default memory
 331:     // if ac_ar.transfer is not set then we can take a shortcut to the program buffer
 332:     abstract_cmd[0][31:0]  = dm::illegal();
 333:     // load debug module base address into a0, this is shared among all commands
 334:     abstract_cmd[0][63:32] = dm::auipc(5'd10, '0);
 335:     abstract_cmd[1][31:0]  = dm::srli(5'd10, 5'd10, 6'd12); // clr lowest 12b -> DM base offset
 336:     abstract_cmd[1][63:32] = dm::slli(5'd10, 5'd10, 6'd12);
 337:     abstract_cmd[2][31:0]  = dm::nop();
 338:     abstract_cmd[2][63:32] = dm::nop();
 339:     abstract_cmd[3][31:0]  = dm::nop();
 340:     abstract_cmd[3][63:32] = dm::nop();
 341:     abstract_cmd[4][31:0]  = dm::csrr(dm::CSR_DSCRATCH1, 5'd10);
 342:     abstract_cmd[4][63:32] = dm::ebreak();
 343:     abstract_cmd[7:5]      = '0;
 344: 
 345:     // this depends on the command being executed
 346:     unique case (cmd_i.cmdtype)
 347:       // --------------------
 348:       // Access Register
 349:       // --------------------
 350:       dm::AccessRegister: begin
 351:         if (32'(ac_ar.aarsize) < MaxAar && ac_ar.transfer && ac_ar.write) begin
 352:           // store a0 in dscratch1
 353:           abstract_cmd[0][31:0] = dm::csrw(dm::CSR_DSCRATCH1, 5'd10);
 354:           // this range is reserved
 355:           if (ac_ar.regno[15:14] != '0) begin
 356:             abstract_cmd[0][31:0] = dm::ebreak(); // we leave asap
 357:             unsupported_command = 1'b1;
 358:           // A0 access needs to be handled separately, as we use A0 to load
 359:           // the DM address offset need to access DSCRATCH1 in this case
 360:           end else if (ac_ar.regno[12] && (!ac_ar.regno[5]) &&
 361:                       (ac_ar.regno[4:0] == 5'd10)) begin
 362:             // store s0 in dscratch
 363:             abstract_cmd[2][31:0]  = dm::csrw(dm::CSR_DSCRATCH0, 5'd8);
 364:             // load from data register
 365:             abstract_cmd[2][63:32] = dm::load(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
 366:             // and store it in the corresponding CSR
 367:             abstract_cmd[3][31:0]  = dm::csrw(dm::CSR_DSCRATCH1, 5'd8);
 368:             // restore s0 again from dscratch
 369:             abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8);
 370:           // GPR/FPR access
 371:           end else if (ac_ar.regno[12]) begin
 372:             // determine whether we want to access the floating point register or not
 373:             if (ac_ar.regno[5]) begin
 374:               abstract_cmd[2][31:0] =
 375:                   dm::float_load(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
 376:             end else begin
 377:               abstract_cmd[2][31:0] =
 378:                   dm::load(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
 379:             end
 380:           // CSR access
 381:           end else begin
 382:             // data register to CSR
 383:             // store s0 in dscratch
 384:             abstract_cmd[2][31:0]  = dm::csrw(dm::CSR_DSCRATCH0, 5'd8);
 385:             // load from data register
 386:             abstract_cmd[2][63:32] = dm::load(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
 387:             // and store it in the corresponding CSR
 388:             abstract_cmd[3][31:0]  = dm::csrw(dm::csr_reg_t'(ac_ar.regno[11:0]), 5'd8);
 389:             // restore s0 again from dscratch
 390:             abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8);
 391:           end
 392:         end else if (32'(ac_ar.aarsize) < MaxAar && ac_ar.transfer && !ac_ar.write) begin
 393:           // store a0 in dscratch1
 394:           abstract_cmd[0][31:0]  = dm::csrw(dm::CSR_DSCRATCH1, 5'd10);
 395:           // this range is reserved
 396:           if (ac_ar.regno[15:14] != '0) begin
 397:               abstract_cmd[0][31:0] = dm::ebreak(); // we leave asap
 398:               unsupported_command = 1'b1;
 399:           // A0 access needs to be handled separately, as we use A0 to load
 400:           // the DM address offset need to access DSCRATCH1 in this case
 401:           end else if (ac_ar.regno[12] && (!ac_ar.regno[5]) &&
 402:                       (ac_ar.regno[4:0] == 5'd10)) begin
 403:             // store s0 in dscratch
 404:             abstract_cmd[2][31:0]  = dm::csrw(dm::CSR_DSCRATCH0, 5'd8);
 405:             // read value from CSR into s0
 406:             abstract_cmd[2][63:32] = dm::csrr(dm::CSR_DSCRATCH1, 5'd8);
 407:             // and store s0 into data section
 408:             abstract_cmd[3][31:0]  = dm::store(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
 409:             // restore s0 again from dscratch
 410:             abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8);
 411:           // GPR/FPR access
 412:           end else if (ac_ar.regno[12]) begin
 413:             // determine whether we want to access the floating point register or not
 414:             if (ac_ar.regno[5]) begin
 415:               abstract_cmd[2][31:0] =
 416:                   dm::float_store(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
 417:             end else begin
 418:               abstract_cmd[2][31:0] =
 419:                   dm::store(ac_ar.aarsize, ac_ar.regno[4:0], 5'd10, dm::DataAddr);
 420:             end
 421:           // CSR access
 422:           end else begin
 423:             // CSR register to data
 424:             // store s0 in dscratch
 425:             abstract_cmd[2][31:0]  = dm::csrw(dm::CSR_DSCRATCH0, 5'd8);
 426:             // read value from CSR into s0
 427:             abstract_cmd[2][63:32] = dm::csrr(dm::csr_reg_t'(ac_ar.regno[11:0]), 5'd8);
 428:             // and store s0 into data section
 429:             abstract_cmd[3][31:0]  = dm::store(ac_ar.aarsize, 5'd8, 5'd10, dm::DataAddr);
 430:             // restore s0 again from dscratch
 431:             abstract_cmd[3][63:32] = dm::csrr(dm::CSR_DSCRATCH0, 5'd8);
 432:           end
 433:         end else if (32'(ac_ar.aarsize) >= MaxAar || ac_ar.aarpostincrement == 1'b1) begin
 434:           // this should happend when e.g. ac_ar.aarsize >= MaxAar
 435:           // Openocd will try to do an access with aarsize=64 bits
 436:           // first before falling back to 32 bits.
 437:           abstract_cmd[0][31:0] = dm::ebreak(); // we leave asap
 438:           unsupported_command = 1'b1;
 439:         end
 440: 
 441:         // Check whether we need to execute the program buffer. When we
 442:         // get an unsupported command we really should abort instead of
 443:         // still trying to execute the program buffer, makes it easier
 444:         // for the debugger to recover
 445:         if (ac_ar.postexec && !unsupported_command) begin
 446:           // issue a nop, we will automatically run into the program buffer
 447:           abstract_cmd[4][63:32] = dm::nop();
 448:         end
 449:       end
 450:       // not supported at the moment
 451:       // dm::QuickAccess:;
 452:       // dm::AccessMemory:;
 453:       default: begin
 454:         abstract_cmd[0][31:0] = dm::ebreak();
 455:         unsupported_command = 1'b1;
 456:       end
 457:     endcase
 458:   end
 459: 
 460:   logic [63:0] rom_addr;
 461:   assign rom_addr = 64'(addr_i);
 462:   debug_rom i_debug_rom (
 463:     .clk_i,
 464:     .req_i,
 465:     .addr_i  ( rom_addr  ),
 466:     .rdata_o ( rom_rdata )
 467:   );
 468: 
 469:   // ROM starts at the HaltAddress of the core e.g.: it immediately jumps to
 470:   // the ROM base address
 471:   assign fwd_rom_d = logic'(addr_i[DbgAddressBits-1:0] >= dm::HaltAddress[DbgAddressBits-1:0]);
 472: 
 473:   always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
 474:     if (!rst_ni) begin
 475:       fwd_rom_q       <= 1'b0;
 476:       rdata_q         <= '0;
 477:       state_q         <= Idle;
 478:       word_enable32_q <= 1'b0;
 479:     end else begin
 480:       fwd_rom_q       <= fwd_rom_d;
 481:       rdata_q         <= rdata_d;
 482:       state_q         <= state_d;
 483:       word_enable32_q <= addr_i[2];
 484:     end
 485:   end
 486: 
 487:   always_ff @(posedge clk_i or negedge rst_ni) begin
 488:     if (!rst_ni) begin
 489:       halted_q   <= 1'b0;
 490:       resuming_q <= 1'b0;
 491:     end else begin
 492:       halted_q   <= SelectableHarts & halted_d;
 493:       resuming_q <= SelectableHarts & resuming_d;
 494:     end
 495:   end
 496: 
 497: endmodule : dm_mem
 498: