the unofficial comp.dsp home page

DSP Trick: Single-Stepping a SHARC


From: John Chambers <JohnC@ihr.mrc.ac.uk>
Subject: Single-Stepping Trick
Date: 24 Mar 2000 00:00:00 GMT
Newsgroups: comp.dsp
THIS WORK IS PLACED IN THE PUBLIC DOMAIN

Name: Single Stepping a SHARC

Category: DSP instruction trick

Application: Useful for making a debugger or watching your code blow up in slow motion

Advantages: Allows single stepping with interrupts enabled

Introduction: Emulators are expensive and not always too useful. This trick allows execution of a single instruction under control of a PC

The Trick:

The basis of the trick is that an delayed branch requires 3 cycles to execute and an interrupt requires 3 cycles to be recognised. So if we set an interrupt flag in software (say the USER3 interrupt on the SHARC) just after an RTI(DB) instruction, one cycle of the program is executed and then control returns to the USER3 ISR. This ISR copies all the register values to an shared area of memory where the PC reads it. The return value of the PC stack is the program counter (next address to be executed).

The following program illustrates the point. Toggling control_count from 1 to zero and back will single step through user_code.

I've used this to make a debugger for the sharc but it's designed to interface through the printer port to my own hardware. However it should be easy to port. If there is any interest I'll put the code on a web site somewhere (but be warned it's pre alpha!)

John

/*---------------------------------------------------------------------------*/
/*
Monitor Program to allow single stepping of code
     TARGET:  ADDS-21061-EZ-LAB
To assemble and link:
    asm21k init
    asm21k monitor
    ld21k  -a ezkit init.o monitor.o
*/
/*---------------------------------------------------------------------------*/
/* ADSP-21060 System Register bit definitions */
#include "def21060.h"
/* Preprocessor definitions */
#define BUFLEN 1024
#define SAMPLES 1000
#define USER3 SFT3I
//init.asm calls monitor_step from SFT3I
/*---------------------------------------------------------------------------*/
.segment /dm    seg_knld;
.var    control_count;
.var    step_count;
.var    register_store[64];
.endseg;
/*---------------------------------------------------------------------------*/
.segment /pm seg_knlc;
.global monitor_main;
.global monitor_step;
/*---------------------------------------------------------------------------*/
monitor_main:
// A delayed branch takes 3 cycles to execute, and an iterrupt takes 3
// cycles to be recognised. So if we set the interrupt flag in software then
// just after an rti(DB) intstruction, one cycle of the program is executed
// before the code returns.  The return address from the PC stack is the
// value of the program counter.  The rest of the registers are stored
// in memory locations so the PC can read them.  Thats the theory anyway.
    r3 = 0;
    dm(control_count) = r3;
    dm(step_count)= r3;
    bit set mode1 IRPTEN;               //enable global ints and nesting
    bit set imask USER3;                //enable USER3 int
    jump    user_code (db);
    bit set irptl USER3;                //cause a software USER3 INT
    nop;
    nop;
    nop;
    nop;
    nop;
monitor_step:
    dm(register_store) = PCSTK;        //Store value of the program counter
    dm(register_store+1) = r0;         //And the int values of the regs
    dm(register_store+2) = r1;
    dm(register_store+3) = r2;
    dm(register_store+4) = r3;
    dm(register_store+5) = r4;
    dm(register_store+6) = r5;
    dm(register_store+7) = r6;
    r1 = dm(step_count);               //Incr the count of steps completed
    r1 = r1 + 1;
    dm (step_count) = r1;
wait_for_zero:
     r0 = dm(control_count);           //Wait for the control number to go
to 0
     btst r0 by 0;
     if sz jump wait_for_zero;
wait_for_one:
    r0 = dm(control_count);            //Then wait for it to go to 1
    btst r0 by 0;
    if not sz jump wait_for_one;
    r0 = dm(register_store+1);
    r1 = dm(register_store+2);
    rti(db);                           //Return to the user code
    bit set irptl USER3;               //cause a software USER3 INT
    nop;
/*---------------------------------------------------------------------------*/
.endseg;
.segment  /pm seg_pmco;
user_code:
    r3=21;
    r3=22;
    jump  full_stop;
    r3=24;
    r3=25;
    r3=26;
    r3=27;
    r3=28;
    nop;
    nop;
    nop;
    nop;
full_stop:
    nop;
    jump    full_stop;
.endseg;

Home   |   Up

Iowegian International Corp. Terms of Use and Legal Notices