[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: 6502 Delay Loops using Applesoft



Allen Bong wrote:
On Dec 3, 1:12 am, sc...@alfter.DIESPAMMERSDIE.us (Scott Alfter)
wrote:

In article <02b1803a-1471-40cb-a69f-37dbab581...@o23g2000prh.googlegroups.com>,
Allen Bong  <allenbsf6...@gmail.com> wrote:


Has anyone written a gereral delay loop calculating program in
Applesoft, to calculate the constants required to gererate the
required time delays in 6502 codes?

The handful of times I've needed timing-critical delays (in an audio player
way back in the day, and more recently in some hardware bit-banging code),
it was easy enough to do them manually.  The 6502 datasheet tells you how
many cycles each instruction needs to execute:

http://archive.6502.org/datasheets/rockwell_r650x_r651x.pdf
(go to page 10; it's the number in the lower right corner for each
instruction)

The Apple II runs at approximately 1 MHz (it's actually a smidge faster than
that), so one cycle takes about one microsecond.  The shortest run time for
any instruction is two cycles, or about two microseconds.  For short delays
(small multiples of 2 us), a block of NOPs will do.  For longer delays, the
math to calculate how long a loop will take is fairly simple.  Consider
this:

       LDY #10
]1      DEY
       BNE [1

The first two instructions take 2 cycles each.  The branch takes 3 cycles if
the branch is taken to the same page, 4 if the branch is taken to a
different page, or 2 if the branch isn't taken.  Assuming that the code is
all on the same page (which it will be most of the time, but you'd want to
verify where the assembler decides to place your code), LDY executes once,
DEY executes 10 times, and BNE is taken nine times and not taken once.

   2 LDY
10*2 DEY
 9*3 BNE taken
+   2 BNE not taken
=====
  51 cycles total

For nested loops, you'd want to calculate the runtime for the inner loop and
plug that into your calculation for the outer loop.

I suppose if I had a regular need for calculating delay loops, I might've
knocked together an app to do that.  As shown above, though, they're simple
enough to put together by hand as you need them.

 _/_
/ v \ Scott Alfter (remove the obvious to send mail)
(IIGS(http://alfter.us/           Top-posting!
\_^_/ rm -rf /bin/laden            >What's the most annoying thing on Usenet?

--- news://freenews.netfront.net/ - complaints: n...@netfront.net ---


Hi Scott,

Actually, I was thinking something of a more general purpose form of
delay-loop calculator.  Not just for use by Apple 2 only.  For example
you might design a 6502 SBC running at 1.5MHz or 2MHz using 6502A or
6502B or 65C02 (CMOS).

Something like this one for the PIC would be most helpful.  Just enter
the oscillator frequency used by 6502, how much delay time you wanted
in uS, mS or S, then just press "calculate", and a subroutine is
produced.  Very cool, isn't?

Like the ones here:

http://www.golovchenko.org/cgi-bin/delay

http://www.biltronix.com/picloops.html

I don't expect to have the convenient of that but at least one written
in Applesoft would be highly appreciated.  If no one had done that, I
might try to roll one out myself in Applesoft.

This would be an interesting and instructive exercise, but I predict
that it will seldom be "useful", even to you.  This is one of those
cases where real "generality" is only achieved by implementing a
choice among a host of specialized approaches.

There are two great design pitfalls:  too much generality and too
much specialization.  ;-)  And the sweet spot is different for every
different application and context.

I've written several macros to generate <n cycles> or <n milliseconds>
of delay, but, like Scott, I find that a general purpose delay generator
is seldom useful.  In NadaNet, I find application for two delay macros
that are more specialized and useful in the context of NadaNet, but
particular situations often arise that offer (or require) custom
timing approaches.

For example, there is often "work" to be done which occupies some part
of the delay needed, and the cycles required for the work must be
computed accurately and subtracted from the total delay requirement
before executing the padding routine.  The process of computing this
"work delay" and the effort of making it require the same time in spite
of any conditional branches involved, is typically much more effort than
writing the padding routine, so very little effort is saved.  (I've
often wished for an assembler that kept the current cycle count, just
like it keeps the current program counter, but it should be a *dynamic*
cycle count, and there's the rub ;-).

Further, it is common that certain registers or flags are important at
the point that the delay must occur, and a "standard" method will often
conflict with that requirement.

If you work with several situations requiring sometimes a few, sometimes
several, and sometimes many cycles of delay, you will find that while a
few "templates" are useful, no single approach or even a small set of
approaches is optimal.

-michael

NadaNet 3.1 for Apple II parallel computing!
Home page:  http://home.comcast.net/~mjmahon/

"The wastebasket is our most important design
tool--and it's seriously underused."