<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def step(self, disable_interrupts=True, start=0, end=0):
 """ perform an instruction level step. This function preserves the previous interrupt mask state """

        # Was 'if self.get_state() != TARGET_HALTED:'
        # but now value of dhcsr is saved
        dhcsr = self.read_memory(CortexM.DHCSR)
        if not (dhcsr & (CortexM.C_STEP | CortexM.C_HALT)):
            logging.error('cannot step: target not halted')
            return

        self.notify(Notification(event=Target.EVENT_PRE_RUN, source=self, data=Target.RUN_TYPE_STEP))

        self.clear_debug_cause_bits()

        # Save previous interrupt mask state
        interrupts_masked = (CortexM.C_MASKINTS & dhcsr) != 0

        # Mask interrupts - C_HALT must be set when changing to C_MASKINTS
        if not interrupts_masked and disable_interrupts:
            self.write_memory(CortexM.DHCSR, CortexM.DBGKEY | CortexM.C_DEBUGEN | CortexM.C_HALT | CortexM.C_MASKINTS)

        # Single step using current C_MASKINTS setting
        while True:
            if disable_interrupts or interrupts_masked:
                self.write_memory(CortexM.DHCSR, CortexM.DBGKEY | CortexM.C_DEBUGEN | CortexM.C_MASKINTS | CortexM.C_STEP)
            else:
                self.write_memory(CortexM.DHCSR, CortexM.DBGKEY | CortexM.C_DEBUGEN | CortexM.C_STEP)

            # Wait for halt to auto set (This should be done before the first read)
            while not self.read_memory(CortexM.DHCSR) & CortexM.C_HALT:
                pass

            # Range is empty, 'range step' will degenerate to 'step'
            if start == end:
                break

            # Read program counter and compare to [start, end)
            program_counter = self.read_core_register(CORE_REGISTER['pc'])
            if program_counter < start or end <= program_counter:
                break

            # Check other stop reasons
            if self.read_memory(CortexM.DFSR) & (CortexM.DFSR_DWTTRAP | CortexM.DFSR_BKPT):
                break
	
        # Restore interrupt mask state
        if not interrupts_masked and disable_interrupts:
            # Unmask interrupts - C_HALT must be set when changing to C_MASKINTS
            self.write_memory(CortexM.DHCSR, CortexM.DBGKEY | CortexM.C_DEBUGEN | CortexM.C_HALT)

        self.flush()

        self._run_token += 1

        self.notify(Notification(event=Target.EVENT_POST_RUN, source=self, data=Target.RUN_TYPE_STEP))