Jump to content
IGNORED

6502 machine language delay loop


Recommended Posts

Hi guys,

 

Could someone explain to me how this delay loop work ?

 

251 DELAY
252 LDX #15
253 LP1 LDY #255
254 LP2 DEY
255 BNE LP2
256 DEX
257 BNE LP1
260 RTS
As far as I understood these are two nested counters to delay speed of execution (needed in ML coding to the speed of operations). X and Y registers are firstly loaded with respectively 15 and 255 but then I do not catch the meaning of the BNE statement. What is used to compare the Branch Not Equal statement? So Y and X registers values are both compared by default ? Sounds fuzzy to me.
:?
Link to comment
Share on other sites

The DEC opcode (in it's various forms) affect the S (sign of result) and Z (result=0) processor flags. So you don't actually need to do the compare - the branch opcode always just checks the relevant processor flags (BNE means Z not set) and acts accordingly.

 

The CMP opcode mostly acts like a throw-the-result-away subtraction opcode. If you "CMP #13" before a branch, it subtracts 13 from A. If A is holding 13, the result will be "0" (processor flags are updated) and a following BEQ will branch.

 

All of this essentially means that "CMP #0", "CPX #0", and "CPY #0" are always redundant, and can be skipped.

  • Like 1
Link to comment
Share on other sites

Ok Reveng this sounds more clear to me :) . So the BNE is referring to the CMP of X and Y registers to the #0 value which is set by default and as you said there is no need to code a CMP #0.

Pretty much, but I like to think of it the other way around. CMP is something extra you need to do when you require a result/value/state that isn't already covered by the existing processor flags. These flags get set by decrementing, incrementing, shifting, etc., so often enough you don't need CMP, especially if you plan for it. When you can skip the CMP, your loops are a little bit quicker and are a couple bytes smaller.

 

Nothing to get too religious over and waste a lot of time on - your coding time is probably your most precious resource - but something to keep in mind.

Link to comment
Share on other sites

One of the keys to learning 6502 and most assembly languages is to know how the flags are affected by various instructions.

It saves doing unnecessary compare and other test instructions sometimes.

And in some cases you can just use the flags as input to future operations, e.g. carry flag after bitshift to an ADC instruction.

  • Like 2
Link to comment
Share on other sites

The first loop will though run for 15 * 255 = 3825 iterations, while the second loop will run for 15 * 256 = 3840 iterations. Small difference, and in practise one probably would wait for a raster interrupt or whichever similar construct there is rather than have a delay loop if your timing needs to be very precise.

 

The first loop is easy to change so it runs for e.g. 14 * 193 = 2702 iterations, the second loop would always run in a multiple of 256 iterations.

Link to comment
Share on other sites

Hi have tried to code a small routine to cycle through border and background colors :

 

10 ;*******************************
20 ;* BACKGRND AND BORDER COLORS *
30 ;*******************************
40 ;
50 .OPT OBJ
60 *= $8000
70 CLR LDA 53770
80 STA 712
85 JMP DELAY
90 LDA 53770
0100 STA 710
0105 JMP DELAY
0110 JMP CLR
0251 DELAY
0252 LDX #15
0253 LDY #0
0254 LP1 DEY
0255 BNE LP1
0256 DEX
0257 BNE LP1
0260 RTS
Actually I have a different behaviour when testing it with M65 DDT command :
- without the delay loop the program will cycle colors at high speed in an endless loop
- with the delay subroutine the program stops immediately and will display only one set of colors
Cannot understand where I am wrong here. I would like to have colors being displayed slowly in an endless loop.
Link to comment
Share on other sites

Alternatively, you could set an interrupt, then forget about it. Once the countdown timer reaches zero, your interrupt would be executed. Ideally, your interrupt routine would reset the timer for you as well, so it would trigger again... and again... and again...

Link to comment
Share on other sites

OS copy value from shadow registers to hardware registers every VBLK interrupt (every 1/50 sek PAL or 1/60 sek in NTSC). If you wrote something to this registers you see change only after VBLK interrupt (one time on all screen draw)

712 is shadow of register 53274

710 is shadow of register 53272

 

Try wrote something to this registers without delay, you see difference.

Edited by shanti77
Link to comment
Share on other sites

Shadow colour registers are only copied once per frame. To do colour bar effects you should hit the GTIA registers directly.

In cases of doing such video related stuff, delay loops are a poor way to synchronise things. The WSync register on Antic is the way to do as it halts the CPU until near the end of a scanline. Also once you get into such things, it's usually easiest doing them in a DLI.

Link to comment
Share on other sites

10 ;

20 .OPT OBJ

30 *= $8000

40 CLR LDA 53770

50 STA 53274

60 LDA 53770

70 STA 53272

80 JMP CLR


Yep this will give like the classic loading pattern of a C64 tape :-D . How is that big difference? Ok I see, the VBLK act like a delay so when using the shadow register the video refresh is slower.

Edited by repetto74
Link to comment
Share on other sites

  • 3 months later...

I have a lot of tips of this kind in the Tips For Programming the 65(c )02 chapter of my 6502 primer. The following is one of them.

 

An automatic compare-to-zero instruction is built into the following 65(C )02 instructions: LDA, LDX, LDY, INC, INX, INY, DEC, DEX, DEY, INA, DEA, AND, ORA, EOR, ASL, LSR, ROL, ROR, PLA, PLX, PLY, SBC, ADC, TAX, TXA, TAY, TYA, and TSX. This means that, for example, a CMP #0 after an LDA is redundant, a wasted instruction. The only time a 65c02 (CMOS) needs a compare-to-zero instruction after one of these is if you want to compare a register that was not involved in the previous instruction; for example,

 

        DEY
        CPX  #0

(Note the Y and the X are not the same register.) If you can spare a register to which you can transfer the one you want to test, you can save a byte with the transfer instead of a compare instruction. The example above, if the contents of A don't need to be kept, could be changed to:

 

        DEY
        TXA

and then you can branch on the N or Z flag which tell if X was negative or zero. The TXA isn't any faster (both TXA and CPX# take two clocks); but TXA takes only one byte, whereas the CPX #0 takes two bytes.

 

The NMOS 6502 did have a bug in that the flags weren't always correct after a decimal-mode operation like ADC; so then you might have to follow it with the CMP #0 to get the N and Z flags right. It's best to just use the CMOS processor when possible.

 

Note to admin: I have PM'ed about this kind of thing before, and gotten no answer. Whether in BBCode mode or otherwise, I can't find any way to keep the "#0" black in the code section, or put the C in 65C02 in parentheses without a space after it and keep it from turning it into the copyright sign, or other things I want to do. In BBCode mode, there's no line wrap as I'm writing. This kind of thing is why I don't post much on this forum. It's too discouraging. Please give the option to just do like the phpBB forums where we manually tell it everything we want, or even html as done in a plain text editor where we manually write all the tags..

Link to comment
Share on other sites

  • 1 year later...
On 9/17/2017 at 11:56 PM, GarthW said:

I have a lot of tips of this kind in the Tips For Programming the 65(c )02 chapter of my 6502 primer.  The following is one of them.
 
An automatic compare-to-zero instruction is built into the following 65(C )02 instructions: LDA, LDX, LDY, INC, INX, INY, DEC, DEX, DEY, INA, DEA, AND, ORA, EOR, ASL, LSR, ROL, ROR, PLA, PLX, PLY, SBC, ADC, TAX, TXA, TAY, TYA, and TSX.  This means that, for example, a CMP #0 after an LDA is redundant, a wasted instruction.  The only time a 65c02 (CMOS) needs a compare-to-zero instruction after one of these is if you want to compare a register that was not involved in the previous instruction; for example,
 


        DEY
        CPX  #0

 
(Note the Y and the X are not the same register.)  If you can spare a register to which you can transfer the one you want to test, you can save a byte with the transfer instead of a compare instruction.  The example above, if the contents of A don't need to be kept, could be changed to:
 


        DEY
        TXA

 
and then you can branch on the N or Z flag which tell if X was negative or zero.  The TXA isn't any faster (both TXA and CPX# take two clocks); but TXA takes only one byte, whereas the CPX #0 takes two bytes.

The NMOS 6502 did have a bug in that the flags weren't always correct after a decimal-mode operation like ADC; so then you might have to follow it with the CMP #0 to get the N and Z flags right.  It's best to just use the CMOS processor when possible.
 
Note to admin:  I have PM'ed about this kind of thing before, and gotten no answer.  Whether in BBCode mode or otherwise, I can't find any way to keep the "#0" black in the code section, or put the C in 65C02 in parentheses without a space after it and keep it from turning it into the copyright sign, or other things I want to do.  In BBCode mode, there's no line wrap as I'm writing.  This kind of thing is why I don't post much on this forum.  It's too discouraging.  Please give the option to just do like the phpBB forums where we manually tell it everything we want, or even html as done in a plain text editor where we manually write all the tags..


10 ;*******************************

20 ;* BACKGRND AND BORDER COLORS  *

30 ;*******************************

40 ;

50       .OPT OBJ

60       *=  $8000

70 CLR   LDA 53770

80       STA 712

85       JMP DELAY

90       LDA 53770

0100     STA 710

0105     JMP DELAY

0110     JMP CLR

0251 DELAY

0252     LDX #15

0253     LDY #0

0254 LP1 DEY

0255     BNE LP1

0256     DEX

0257     BNE LP1

0260     RTS

65(C)02

Link to comment
Share on other sites

if you need longer and more precise delays you can also use RTCLOK $12,$13 and $14

$14 increments by one every Vblank up to 255, then $13 increments by one etc. etc.

Think I'm right in saying 50 counts/second for PAL and 60 counts/second NSTC

 

sample code

 1  ; Delay time is in the X register

10  DELAY LDA #0

20  STA $14

30 LOOP CPX $14

40  BNE LOOP

50  RTS

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...