Merge pull request #212 from riscv/hartsel
[riscv-isa-sim.git] / debug_rom / debug_rom.S
index ca58ee475473dd53043e074ab3e253c7c63cb2f7..28c7076fda5c17dc2f46d1cf2fead993ba92b6f5 100755 (executable)
-# This code should be functional. Doesn't have to be optimal.
-# I'm writing it to prove that it can be done.
+// See LICENSE.SiFive for license details.
 
 #include "riscv/encoding.h"
+#include "riscv/debug_rom_defines.h"
 
-# TODO: Update these constants once they're finalized in the doc.
-
-#define DCSR                    0x790
-#define DCSR_CAUSE_DEBINT       3
-#define DCSR_HALT_OFFSET        3
-#define DCSR_DEBUGINT_OFFSET    10
-
-#define DSCRATCH                0x792
-
-# TODO: Should be 0x400
-#define DEBUG_RAM               (-0x400)
-#define DEBUG_RAM_SIZE          64
-
-# TODO: Should be 0x100, 0x108
-#define SETHALTNOT              (-0x100)
-#define CLEARDEBINT             (-0x108)
-
+        .option norvc
         .global entry
-        .global resume
-
-        # Automatically called when Debug Mode is first entered.
-entry:  j       _entry
-        # Should be called by Debug RAM code that has finished execution and
-        # wants to return to Debug Mode.
-resume:
-        # Clear debug interrupt.
-clear_debint:
-        csrr    s1, CSR_MHARTID
-        sw      s1, CLEARDEBINT(zero)
-clear_debint_loop:
-        csrr    s1, DCSR
-        andi    s1, s1, (1<<DCSR_DEBUGINT_OFFSET)
-        bnez    s1, clear_debint_loop
-
-        # Restore s1.
-        csrr    s1, CSR_MISA
-        bltz    s1, restore_not_32
-restore_32:
-        lw      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 4)(zero)
-        j       check_halt
-restore_not_32:
-        slli    s1, s1, 1
-        bltz    s1, restore_128
-restore_64:
-        ld      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 8)(zero)
-        j       check_halt
-restore_128:
-        nop     #lq      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 16)(zero)
+        .global exception
 
-check_halt:
-        csrr    s0, DCSR
-        andi    s0, s0, (1<<DCSR_HALT_OFFSET)
-        beqz    s0, exit
-        j       wait_for_interrupt
-
-exit:
-        # Restore s0.
-        csrr    s0, DSCRATCH
-        eret
+        // Entry location on ebreak, Halt, or Breakpoint
+        // It is the same for all harts. They branch when 
+        // their GO or RESUME bit is set.
 
+entry:
+       jal zero, _entry
+resume:
+       jal zero, _resume
+exception:
+       jal zero, _exception
 
 _entry:
-        # Save s0 in DSCRATCH
-        csrw    DSCRATCH, s0
-
-        # Check why we're here
-        csrr    s0, DCSR
-        # cause is in bits 2:0 of dcsr
-        andi    s0, s0, 7
-        addi    s0, s0, -DCSR_CAUSE_DEBINT
-        bnez    s0, spontaneous_halt
-
-jdebugram:
-        # Save s1 so that the debug program can use two registers.
-        csrr    s0, CSR_MISA
-        bltz    s0, save_not_32
-save_32:
-        sw      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 4)(zero)
-        jr      zero, DEBUG_RAM
-save_not_32:
-        slli    s0, s0, 1
-        bltz    s0, save_128
-save_64:
-        sd      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 8)(zero)
-        jr      zero, DEBUG_RAM
-save_128:
-        nop     #sq      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 16)(zero)
-        jr      zero, DEBUG_RAM
-
-spontaneous_halt:
-        csrr    s0, CSR_MHARTID
-        sw      s0, SETHALTNOT(zero)
-        csrsi   DCSR, (1<<DCSR_HALT_OFFSET)
-
-wait_for_interrupt:
-        csrr    s0, DCSR
-        andi    s0, s0, (1<<DCSR_DEBUGINT_OFFSET)
-        beqz    s0, wait_for_interrupt
-
-        j       jdebugram
+        // This fence is required because the execution may have written something
+        // into the Abstract Data or Program Buffer registers.
+        fence
+        csrw CSR_DSCRATCH, s0  // Save s0 to allow signaling MHARTID
+
+        // We continue to let the hart know that we are halted in order that
+        // a DM which was reset is still made aware that a hart is halted.
+        // We keep checking both whether there is something the debugger wants
+        // us to do, or whether we should resume.
+entry_loop:
+        csrr s0, CSR_MHARTID
+        sw   s0, DEBUG_ROM_HALTED(zero)
+        lbu  s0, DEBUG_ROM_FLAGS(s0) // 1 byte flag per hart. Only one hart advances here.
+        andi s0, s0, (1 << DEBUG_ROM_FLAG_GO)
+        bnez s0, going
+        csrr s0, CSR_MHARTID
+        lbu  s0, DEBUG_ROM_FLAGS(s0) // multiple harts can resume  here
+        andi s0, s0, (1 << DEBUG_ROM_FLAG_RESUME)
+        bnez s0, resume
+        jal  zero, entry_loop
+
+_exception:
+        sw      zero, DEBUG_ROM_EXCEPTION(zero) // Let debug module know you got an exception.
+        ebreak
+
+going:
+        csrr s0, CSR_DSCRATCH            // Restore s0 here
+        sw zero, DEBUG_ROM_GOING(zero)   // When debug module sees this write, the GO flag is reset.
+        fence
+        fence.i
+        jalr zero, zero, %lo(whereto)    // Debug module will put different instructions and data in the RAM, 
+                                         // so we use fence and fence.i for safety. (rocket-chip doesn't have this
+                                         // because jalr is special there)
+
+_resume:
+        csrr s0, CSR_MHARTID
+        sw   s0, DEBUG_ROM_RESUMING(zero) // When Debug Module sees this write, the RESUME flag is reset.
+        csrr s0, CSR_DSCRATCH   // Restore s0
+        dret
+
+        // END OF ACTUAL "ROM" CONTENTS. BELOW IS JUST FOR LINKER SCRIPT.
+
+.section .whereto
+whereto:
+        nop
+        // Variable "ROM" This is : jal x0 abstract, jal x0 program_buffer,
+        //                or jal x0 resume, as desired.
+        //                Debug Module state machine tracks what is 'desired'.
+        //                We don't need/want to use jalr here because all of the
+        //                Variable ROM contents are set by
+        //                Debug Module before setting the OK_GO byte.