GENWiki

Premier IT Outsourcing and Support Services within the UK

User Tools

Site Tools


archive:programming:desdebug
    ====================================================================
DR  6502    AER 201S Engineering Design 6502 Execution Simulator
    ====================================================================
    Supplementary Notes                                   By: M.J.Malone
    
    	 Suggested Programming Style and Debugging Methods Using DR6502
    	 ==============================================================
    
   So  far  in  the documentation, you have been introduced to the
    6502,  its  assembly  language,  the  project  board  and  the  6502
    simulator.   Several times there have been references to 'proper' or
    'suggested'  programming  style.   These  suggestions  are  for  the
    purpose  of  making debugging easier.  Learning and writing assembly
    language is not difficult since the commands are limited to a finite
    set each performing very simple manipulations.   Debugging  assembly
    language  is  THE  hardest  problem.  Even with a software simulator
    with extensive program monitoring, finding bugs in a  code  is  very
    difficult.   By following certain programming methods, bugs are more
    easily located.
    
    'Bottom Up' vs 'Top Down'
    -------------------------

Much discussion has been spent on the 'Bottom up' and 'Top

    down'   programming  styles;  each  has  its  merits  for  different
    applications.  The 'Top down' strategy involves writing the  highest
    logic  level  of the program first and then the subroutines and then
    the subroutines of subroutines etc until the task is complete.   The
    'Bottom up' strategy involves writing basic functions first and then
    building  on  them  to  produce  a  the  code from the bottom of the
    pyramid.

The 'Top down' method has advantages especially if several

    people  are  working  on  the  same  code.   The main logic could be
    decided and the task divided into modules which could be distributed
    among  the  team  members.   The  data  structure  and  the  calling
    parameters  for  each  module  would  have  to  be  fixed  to assure
    compatibility.  Problems can arise if the early  definition  of  the
    problem  and  its  division into modules leads to some unanticipated
    difficulties at  the  level  of  the  elementary  subroutines.   For
    example,  duplication  of  tasks  can  occur  when  two  modules are
    designed  that  require  (because  of  their  definition)   slightly
    different  subroutines  that  perform essentially the same function.
    As a result of the duplication, the program is longer and  has  more
    parts  to  debug.  This is not a problem since there are more people
    to debug the  program  and  computer  memories  are  usually  not  a
    limiting  factor.   The  entire  task,  with  a  team  at work, when
    programming 'Top down' can be completed quickly.

The 'Bottom up' method has advantages especially when starting

    at  machine  level applications.  The basic capabilities required to
    manipulate data are identified and  are  written.   From  there  the
    program  develops  as ever more complex manipulations until the main
    program can be written to perform the required task.   Problems  can
    occur  in  'Bottom  up'  style  if  a  clear idea of the goal of the
    program is not kept in mind.  For example when advancing to a higher

page 2

level manipulation it may be realised that a poorly defined storage

    method  for  some  critical  data  element  may  have to be changed.
    Reprogramming would have  to  begin  at  the  lowest  level  of  the
    occurrence  of  the problem.  'Reaching the top' may seem impossible
    when working on the manipulation of  basic  items.   A  'Bottom  up'
    strategy  does  not  duplicate  low level functions and will lead to
    smaller and probably faster  code.   'Bottom  up'  strategy  is  not
    easily  allocated  to  a  team  and  is more difficult to develop in
    parallel.  'Bottom up' strategy  allows  early  debugging  of  basic
    functions before they are obscured by higher level manipulations.

There is a history of 'Bottom up' programming in computer

    control applications especially with the  FORTH  computer  language.
    FORTH  is  a bottom up language where you MUST enter basic functions
    first  and  these  are  compiled  as  entered.   When  higher  level
    functions  are entered, their calls to the lower level functions are
    converted to pointers to the already compiled block of code.  As the
    code is developed the higher level functions are appended to the end
    of the code until the main program  module  is  entered.   The  code
    executes  very  fast  like  a compiled language but is entered as an
    interpreted  language.  There are in fact even FORTH processors that
    operate in the FORTH  language  instead  of  assembly  language  and
    execute computation and control programs very quickly.  At the FORTH
    prompt,  the  user  can  type a function call with its arguments and
    test the operation of that function.

Recommended Methods

  1. ——————

It is recommended that students use a 'Top Down' strategy when

    planning the data structures and general program flow in the form of
    a  block  diagram.   From this diagram, the range of basic functions
    required  can  be  listed.   The  student  should  then  set   about
    programming  the  software  in  a  bottom  up  fashion, testing each
    subroutine as it is coded.  Strong use of subroutines should be made
    to reduce the length of the code.  The reason for this is  not  that
    it is likely that a student will run out of memory with a maximum of
    16K of program space on a project board.  The reason is, the shorter
    a  program is, the less there is to debug.  The more a subroutine is
    used, the more is gained by proving it correct.  Once  the  core  of
    basic  subroutines  are  proven, the student can advance to the next
    tier of nesting with confidence in what has been done thus far.

The first routines programmed will likely be the basic

    multibyte mathematics subroutines.  Since values sometimes cannot be
    expressing  in  one byte and often these quantities must be added or
    subtracted, there are few software subsystems that will not  require
    some  math  routines.  Other routines that are likely to be required
    are a delay loop of a controlled  length  and  basic  I/O  interface
    routines.

After each routine has been written, the student should use

    DR6502 in the software mode to test the response of the  routine  to
    inputs.   For  example if the routine adds, then make it add several

page 3

numbers and check to see if its answers are correct. Check I/O

    routines  in  software  mode  first and then if the actual interface
    circuitry is ready and  tested,  the  integration  of  software  and
    interface  should be attempted either with a test EPROM or using the
    simulator in hardware mode.

Often students will give their code to DR6502 without providing

    any input data.  DR6502 executes the instructions, the screen  flips
    and  the  program  reaches its end.  The mistaken conclusion is that
    the routine or program works.  The simulator does not check  to  see
    if  the  algorithm  of  the  program  conforms  to  any proper model
    intended by the student.  The simulator does not  check  to  see  if
    data  was  processed  properly.   The only error conditions that the
    simulator will flag and actually stop the execution over  fall  into
    the  category  of  dumb  mistakes.  If a program executes and DR6502
    does not complain it just means there are no  writes  to  EPROM,  no
    reads from a location that was never set and no reads or writes from
    unallocated  memory  spaces.   It  is  very  important  therefore to
    provide input data, check intermediate values  and  check  responses
    and  output  values  before  any  conclusions can be reached about a
    particular piece of code.

After and only after the basic routines are tested, should the

    higher  level routines be tested.  Because higher level routines may
    not test as wide a range of input values to the lower level routines
    under simulated conditions, it is never wise to test several  levels
    of  the  program  at  once.   This  is  the  most common problem for
    students.  Many students will very often write  the  entire  program
    and  then  test  it  as a whole, hoping it will all work.  Often the
    student will not input as great range of inputs into the program  as
    would  be  in  the  actual  prototype  and  the tests will appear to
    succeed.  Since such full tests are difficult and time consuming  to
    stage  without  the hardware present there will be little motivation
    to go on and do more.  Toward the end  of  the  term,  students  are
    sometimes  afraid  to  test  their software more extensively in case
    they do find a terrible bug that would take longer to fix  then  the
    time  available.   Unfortunately,  in  the  final design and testing
    these undiscovered or ignored bugs will  crop  up  leading  to  some
    tough  questions from instructors and group members.  Make sure that
    all tests are carefully controlled, testing the performance  of  one
    routine.   Any  routines  called in the testing of the routine under
    investigation are thoroughly tested before hand.

Often students will test a routine and go on to test another.

    When  problems are found in the second routine and the reason is not
    apparent, the student may begin to  doubt  the  performance  of  the
    first routine.  At this point it becomes important for there to have
    been  notes  on  the tests performed on each routine.  By consulting
    these notes, the  student  will  be  sure  whether  the  routine  is
    functioning  or  if  some  aspect  of it being used that was in fact
    never tested.  To help in this matter, the DR6502 program outputs  a
    history  file providing a record of all work done during a simulator
    session.  The log file is called DR_6502.HST.  Though notes in a lab
    book are still necessary, after a simulator session, the student may
    wish to rename the history file to a name  indicative  of  the  test
    performed  and copy it onto a floppy or into a a different directory

page 4

where it can be consulted if necessary. In discussions with

    instructors  or  group  members,  these  records are good sources of
    information on what problems were encountered  and  solved  and  how
    they were solved.

In summary, the program should be planned from the highest

    logic downward and then coded from the lowest  level  upward.   Well
    designed  tests  should  be  performed  on  each  routine  as  it is
    completed.  Tests should provide a wide range of input values to the
    routine, monitor intermediate values responses and outputs.   It  is
    wise to keep extensive records of the tests performed.

Using DR 6502 to Test Software

  1. —————————–

DR 6502 is a tool that is versatile but has no options like

    'test  everything  and see if it works.' To prepare for the software
    testing stage of the design, the user of DR  6502  should  read  the
    DR6502.DOC  file and try hacking up and running the example program.
    Performing a test on the software will also require a firm  idea  of
    what  the  goals  of  the  test  are  to  be.   Once  this  has been
    established, the steps in a test should be:

1) Prepare the subroutine or segment of the program to be tested

    (including  the reset vector and a start up routine initializing the
    stack), assemble with TASM and create a symbol file with DRSYM.EXE.

2) Start the simulator, provide all requested information and

    proceed to the 'stopped' status screen.

3) Prepare any input data required for the program's execution.

4) Set any output options that are necessary to monitor the progress

    of the program.

5) Begin execution of the program, monitoring its progress.

6) Upon completion of the test, examine the output data and save it

    to disk if necessary.

7) Modify the program and repeat or exit the simulator and copy the

    history file to your records disk.

In the case of testing a 2 byte addition subroutine the user

    may do the following.  As above, the program is prepared, assembled,
    the symbol file is  created  and  the  simulator  is  started.   The
    specification  of this routine includes that, as input variables, it
    takes one 16 bit number passed  into  the  subroutine  call  by  the
    values  of  the  .X  and  .Y registers representing the high and low
    bytes respectively.  The other 16 bit number is  present  in  memory
    locations  $00  and  $01  as  low byte, high byte respectively.  The
    routine is designed for doing a 'running total' type addition  where
    the  answer  is  stored  back  into  the memory location $00 and $01
    before the routine executes an RTS.  The output  variables  of  this
    subroutine  are  a copy of the contents of $00 and $01 in the .Y and

page 5

.X registers respectively, the answer. Also returned by this

    routine  is  the  value  of  the  carry  flag:  set  if there was an
    overflow, clear otherwise.  The overflow flag was not  used  because
    the programmer is using it as a quick input port (with the SO pin of
    the processor) in another routine.
   The  user  selects  the  'p' option to poke initial values into
    the $00 and $01 memory locations, and inputs '$00 00'  to  set  both
    locations  to  zero.  The user then selects the 'r' option to modify
    the .X and .Y registers and sets each to zero as  well.   The  first
    test  will  be  to  see if the routine can add zero and zero and get
    zero.  This is essentially testing to  see  if  any  obvious  errors
    exist  in the way the routine handles the carry flag.  The user then
    selects the output options: 'H' to select full history mode, 'm'  to
    monitor  the  address  $00  as  a two byte variable and 'b' to set a
    break point after the addition of the least significant bytes of the
    arguments.  The user then executes the subroutine  by  pressing  the
    's'  key for each program step or 'g' for continuous execution.  The
    user carefully observes the screen  outputs  and  when  the  RTS  is
    reached  if  the  code  found  0+0=0  then  another  test  would  be
    prepared.  When the testing of this routine  is  complete  the  user
    exits  the  simulator  and enters the DOS command: 'copy dr_6502.hst
    a:\tests\2byteadd.rec' to  copy  the  history  file  into  the  test
    records directory.

Testing I/O Routines

  1. ——————-

In the above example, the subroutine processes input data and

    produces output data all internal to the  6502  address  space.   In
    such cases DR 6502 is sufficient, in its software form, for complete
    debugging  of  routines.   In  the case of I/O subroutines, there is
    information that originates outside the 6502 address space  involved
    in  the manipulation.  The problem can be divided into to classes of
    subroutines: those that include hardware input  and  those  that  do
    not.
   If the subroutine is an output subroutine only, with monitoring
    of  the  appropriate output port address, a software simulation with
    DR6502 would be sufficient to check the algorithm.  To check to  see
    if the routine would 'work' in the global sense, IE be sufficient to
    drive  the  external device in the manner required, then the project
    hardware must be brought into the loop, either through the  hardware
    simulator or by burning an EPROM and trying it on the target system.
   If  the  subroutine contains hardware input then the simulation
    becomes more difficult.  Naturally, working in  hardware  simulation
    mode,  with  the  target  system  present  or  with  an EPROM on the
    completed target would test input subroutines.  If  the  user  would
    like  to  test  the routine with the simulator in software mode, the
    task is more complex.  The user must use the 'b' break point  option
    to  halt  the  simulation and do inputs manually.  The user may halt
    the execution before the input read and put the data  in  the  input
    port with the 'p' poke memory location option.  The user may wish to
    use  the  'b'  break  point  option and set it to the port location.
    When the simulator executes and reads the port, the simulation would
    stop.  The user could then put the NEXT value  on  the  port.   This
    method  is  superior  especially  when the subroutine next reads the
    port at several points in the code depending on the last value  read
    in.

page 6

Hardware testing is essential to development of the software.

    For example the control of a stepper motor requires a certain series
    of  bits  or  combinations  to  be  sent  to  the  output port.  The
    programmer may easily program these combinations and make sure  they
    are  sent  to the port in the correct order but the system may still
    not work as a whole.  The programmer may have  neglected  or  chosen
    the  time constants, in this case the waiting periods before sending
    the next bit  code,  incorrectly.   A  few  tests  with  a  function
    generator  and  a few logic circuits may give the programmer an idea
    of the time delays between  sending  each  impulse.   Unfortunately,
    using a function generator is not  always  fool-proof  either.   The
    maximum frequency, as read on the generator, that the motor will run
    at  and the frequency it will start at are two different values.  An
    acceleration routine would be required that starts  the  motor  with
    time  constants  corresponding  to  the  lower  frequency and slowly
    shifts them to the values required for the  higher  frequency.   The
    motor   would   then   appear   to   start   and   them  accelerate.
    Unfortunately, this is often not adequate either.   Once  the  motor
    has  been  mounted  in  its  final configuration and attached to the
    final mechanism with all the  masses  required  to  be  moving,  the
    torque  required  from  the  motor  and  the  momentum changes these
    constants.  Usually the motor must be run more slowly however in the
    case of a high angular momentum and a small running  torque  like  a
    flywheel,  the maximum frequency of the motor may actually increase.
    Factors like mass and inertia that lead to time constants.  Friction
    alters those time constants and is found in all  practical  systems.
    Such  factors  must be considered in the design of software and only
    testing on the physical hardware can  prove  that  the  software  is
    adequate.
   Unfortunately, the hardware simulator does execute instructions
    as  quickly  as an actual 6502.  As a result, the hardware simulator
    is not well suited to determining time constants.   Testing  on  the
    actually  hardware with a test EPROM would be required in this case.
    For additional suggestions on how to determine time constants with a
    test EPROM see file 'TRICKS65.DOC' Section 3) 'The Reburnable EPROM'
    particularly the 'Vector Jump Method'.

More Advanced Testing

  1. ——————–

After the basic subroutines have been tested, the student will

    then  move  on  to  testing the more advanced routines that call the
    lower level subroutines.  After a while the purpose of the  routines
    moves  away from the basic manipulation of data and on to the higher
    level logic of which routines are called in what order to perform  a
    task.   There  are  user  selectable  modes  of  operation where the
    simulator does not produce as much extraneous output.   The  methods
    involve the output to the screen and the history file records.
   The  history file can be set in one of three modes of output to
    limit the quantity of unnecessary output  not  of  interest  to  the
    user.   The  total  output  mode,  outputs  instructions, arguments,
    register values and monitored address values.  When the flow of  the
    code   is   important   but  the  register  values  are  superfluous
    information, there is a second mode (default) where the history file
    can be made to contain only  the  instructions  and  arguments.   In

page 7

addition, if only the call structure of the program is important

    then the history file can be set to more  brief  output  mode  where
    only  program  steps  involving  the JSR, RTS, IRQ, NMI, BRK and RTI
    instructions are recorded.
   Consider the following call tree typical of a  mobile  reactive
    robotics system:

Main

    				   |
    		 -------------------------------------
    		/                  |                  \
    	      Sense              Record              React
    	       |                   |                  |
    						      |
    						      |
    				   ----------------------------
    				  /                            \
    			       Compute                       Execute
    				 |                              |
    				 |
    				 |
    	 -----------------------------------------------------------
    	/        |            |           |             |           \
     Add    Subtract     Multiply     Divide     Square Root    Arctan

Let it be assumed that the code has been designed from the top

    down and is being programmed and tested from the bottom  up  (though
    this  is  not  necessary).   After the basic math routines have been
    programmed and tested and the 'Compute' algorithm has been  written,
    the  user would like to next test the 'Compute' algorithm.  When the
    simulator executes, it would normally display all the program  steps
    (full  output  mode), none of the steps (silent mode) or none of the
    steps up until a break point.  If the user is confident of the  math
    routines  and  is  really  only  interested  in the behaviour of the
    'Compute' subroutine then a mode that limits the screen output based
    on the position of the execution in the call tree is required.  Just
    such a mode is available in the simulator as  the  subroutine  trace
    option.   In  the  above  example  the  user would execute the trace
    option at any time that execution was in the  'Compute'  subroutine.
    From  that point on, none of the steps of the math routines would be
    displayed nor would any steps of subroutines called by 'Execute'  be
    displayed.   If  the  entire  program  were  present  and  execution
    continued to other areas of the calling tree, all subroutines at  or
    above  the  level  of  'Compute' would be displayed.  Since limiting
    screen output also limits history file output, the two methods above
    can be used in combination.  When  this  option  is  selected,  only
    program  steps  at  the  'traced'  level  of  nesting  or higher are
    displayed and hence are eligible to be recorded in the history  file
    depending on its output mode.  The user may chose at any time to end
    the trace option.

page 8

Recommendations for Testing

  1. ————————–

When testing the subroutines of the code, make sure the purpose

    of  the test is clearly laid out, the progress of the execution well
    monitored and the  results  of  the  test  recorded  in  appropriate
    detail.   If  the  simulator  is  used, use all options available to
    monitor and record the progress of the code.  If the code is run  on
    an EPROM, make sure that adequate output is given to whatever output
    device is available to follow the execution of the program.  Use LCD
    displays  whenever  possible, connect LEDs to any unused output bits
    and program the code to give  signals  to  indicate  the  course  of
    important decisions.



/data/webs/external/dokuwiki/data/pages/archive/programming/desdebug.txt · Last modified: 2000/12/16 02:37 by 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki