Macro help?

Programming the 6502 microprocessor and its relatives in assembly and other languages.
User avatar
floobydust
Posts: 1394
Joined: 05 Mar 2013

Macro help?

Post by floobydust »

I'm looking at the CBM 1581 Source code. There's a Macro used that precedes every access to the WD1772 Status register. It's a simple entry but without knowing what all of the characters mean, I'm having difficulty deciphering how it works. In use, it may or may not insert a NOP before accessing the WD1772. I've tried using it with the WDC Tools package... no error is produced but it doesn't function either, so I'm missing some golden rule for whatever package was originally used to assembler the 1581 source code.

Code: Select all

  messg "mfmmacro"
	subttl "mfmmacro"
	page
WDTEST	macro
	if <*!.$03>
	nop
	endif
	endm
Any ideas on this would be appreciated.
User avatar
BigDumbDinosaur
Posts: 9425
Joined: 28 May 2009
Location: Midwestern USA (JB Pritzker’s dystopia)
Contact:

Re: Macro help?

Post by BigDumbDinosaur »

floobydust wrote:

Code: Select all

  messg "mfmmacro"
	subttl "mfmmacro"
	page
WDTEST	macro
	if <*!.$03>
	nop
	endif
	endm
That appears to be part of the macro language of Commodore's DEVPAK 128 assembler. While I used DEVPAK a lot in the latter 1980s and early 1990s, I have not looked at it since c. 1993 and no longer recall the details. I do recall that a notation such as $03 referred to a local label in the source code and * referred to the program counter. As for !., dunno if that is symbology for "not equal to" or what.

—————————————————————————
EDIT: Shows you how much I've forgotten about DEVPAK. :oops: Local labels are written with a trailing dollars sign, like a BASIC string variable. So $03 in the above example would be a hex value.
Last edited by BigDumbDinosaur on Mon Jan 16, 2017 5:50 pm, edited 1 time in total.
x86?  We ain't got no x86.  We don't NEED no stinking x86!
John West
Posts: 383
Joined: 03 Sep 2002

Re: Macro help?

Post by John West »

The same expression appears in the source for the 1571 firmware, but this time with comments:

Code: Select all

wdtest  .macro  
    .ife <*!.$03    ; lower two bits cannot be zero
    nop               ; fill address error
    .endif	
    .endm
My guess is < takes the low byte of *, the current address. !. is used to and, and $03 has the bottom two bits set. ife assembles the nop only if that expression equals zero.

The macro is used before every access of the WD1772 registers. Why it doesn't like certain instruction alignments, I don't know.
User avatar
Dr Jefyll
Posts: 3526
Joined: 11 Dec 2009
Location: Ontario, Canada
Contact:

Re: Macro help?

Post by Dr Jefyll »

John West wrote:
Why it doesn't like certain instruction alignments, I don't know.
I think John's on the right track. I believe the NOP is for alignment. (It's not a timing thing, for instance.) I suggest you look at the 1572 schematic and see if there are any clues.

I'm half guessing, but here's an example of the sort of thing you might find. There's a hardware trick I've used where A0 (the LS address line) is used as an output bit. You do your memory-mapped I/O, and of course the alignment of the I/O instruction (alignment which you explicitly control) determines the state of A0 when the instruction is fetched. Hardware captures A0 during the instruction fetch and uses it to control whatever. It's a rather obscure but powerful technique. And it's not limited to A0; you can control two or more of the LS address lines as long as you're willing to do the necessary alignment.
Last edited by Dr Jefyll on Mon Jan 16, 2017 5:24 pm, edited 1 time in total.
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
User avatar
floobydust
Posts: 1394
Joined: 05 Mar 2013

Re: Macro help?

Post by floobydust »

Thanks to both of for the insight. It is pretty strange. The WD1772 is used in polled I/O mode apparently in the 1581 as the IRQ, DRQ lines are left un-connected, so it is gong to be timing dependent on accesses. Maybe It's a hardware anomaly in the way the designed it? Hoping I can figure out how to manage it in WDC Tools.
User avatar
Dr Jefyll
Posts: 3526
Joined: 11 Dec 2009
Location: Ontario, Canada
Contact:

Re: Macro help?

Post by Dr Jefyll »

Maybe I'm mistaken to say it's not a timing thing. Polled I/O mode implies that, before an instruction that reads or writes data, there'll be a loop that reads Status and conditionally branches back, never proceeding until the chip is ready for a transfer. You don't want that backward branch to cross a page boundary because it'll add one cycle to the wait loop.

You said the macro precedes every access to the WD1772 Status register, and that's puzzling since not all reads of Status are time-sensitive. Those before a data transfer certainly are, but those in preparation for mundane stuff like a head seek aren't.

It's worth remembering some of the clues may be misleading. Perhaps the person who put in the macros used more than were necessary. And as for page crossings, you'd expect the macro to look for an address ending in $FF, not $03 -- but the latter would still work.
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
User avatar
floobydust
Posts: 1394
Joined: 05 Mar 2013

Re: Macro help?

Post by floobydust »

Thanks Jeff, missed your first post before I replied. It's still not clear what the macro is doing. I did modify the 1581 source code and got it assemble with the WDC Tools package, but had to nix the macro as it shows an unknown expression pointing to the < character. I basically inserted the NOP based on the actual ROM contents. Even looking at what the actual address is when the 1772 status register is read is not obvious (at least not to me yet). Either way, if you change the code, the NOPs might be placed incorrectly. I did some testing and if you insert a NOP before every SR read, the drive doesn't work. So there is some strange requirement for the macro to make a determination to insert the NOP or leave it out.
User avatar
Dr Jefyll
Posts: 3526
Joined: 11 Dec 2009
Location: Ontario, Canada
Contact:

Re: Macro help?

Post by Dr Jefyll »

Looks like the hardware trick I mentioned is not present. It would need to use SYNC to qualify the clock of the flipflop that captures A0, and according to the 1581 schematic I found here SYNC is a no-connect. (And FWIW the SO\ pin attaches only to a pullup resistor.)
Quote:
I did some testing and if you insert a NOP before every SR read, the drive doesn't work.
Interesting puzzle! How many SR reads are there? Can you get away with defeating the macro in cases where the SR read does NOT precede a data transfer? (Just thinking out loud. There are lots of different experiments you may wish to try.)
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
User avatar
Hobbit1972
Posts: 80
Joined: 10 Feb 2015
Location: Germany

Re: Macro help?

Post by Hobbit1972 »

It would be good to know the full source - is it online somewhere?
User avatar
floobydust
Posts: 1394
Joined: 05 Mar 2013

Re: Macro help?

Post by floobydust »

Yes, I found the source at:

http://www.zimmers.net/anonftp/pub/cbm/ ... index.html

I had to make some large changes to a few files (IODEF, RAM, EQUATE) and had to do a handful of minor edits for some of the auto label bits scattered in lots of different files. Basically I have a version of the code that assembles/links with WDC tools and makes a prefect replica of the ROM image. However, trying to make any changes gets ugly fast... as the WDTEST macro is apparently required but it's logic isn't clear on how it decides when to add the NOP.

Replying to Jeff, there's about 27 uses of the WDTEST macro... all precede the loading of the status register as:

Code: Select all

	WDTEST		; chk address
cmd70   lda  wdstat
	and  #3
	lsr  a
	bcc  v1	
The code above gets the status register, masks off the lower 2 bits, which are DRQ and BUSY. By shifting the first bit into the carry flag (which is the BUSY flag) it's checking to see if the 1772 is busy and branching if it is. The WDTEST macro is adding the NOP before the read of the status register. In some cases there is a command sent to the 1772 before reading the status register. The core routines that access the 1772 are in MROUT and MSUB. Here's a longer code snippet:

Code: Select all

	ldx  #32
	WDTEST		; chk address
cmd7    lda  wdstat
	and  #3
	lsr  a
v6	bcc  v1	
	beq  cmd7

	lda  #$4e
	sta  wddat	; give him the $4E data
	dex
	bne  cmd7

main7	ldx  #12
	WDTEST		; chk address
cmd70   lda  wdstat
	and  #3
	lsr  a
	bcc  v1	
	beq  cmd70

	lda  #0
	sta  wddat
	dex
	bne  cmd70

	ldx  #3		
	WDTEST		; chk address
cmd71   lda  wdstat
	and  #3
	lsr  a
v1	bcc  v2	
	beq  cmd71
John West
Posts: 383
Joined: 03 Sep 2002

Re: Macro help?

Post by John West »

1581 source: ftp://www.zimmers.net/pub/cbm/firmware/ ... index.html
1581 service manual (schematics at the end of the pdf): ftp://www.zimmers.net/pub/cbm/schematic ... index.html
1571 source with that helpful comment: ftp://www.zimmers.net/pub/cbm/firmware/ ... index.html
WD1772 datasheet: http://dev-docs.atariforge.org/files/WD1772.pdf

When I said that every access of the WD1772 registers was preceded with this macro, I hadn't checked all of them. And it turns out that many of them don't. For example, there are two writes to WDCMD in msub.src. One has the macro, the other doesn't.

Every access of WDSTAT uses it. It can't be for timing, as some of these reads are in loops, with the macro before the start of the loop. Confusingly WDCMD and WDSTAT are the same address. You get WDSTAT when you read, WDCMD when you write.

No access of WDTRK, WDSEC, or WDDAT uses it.

I can't see anything unusual in the schematic. Nothing that would suggest any dependence on the address of instructions.
User avatar
floobydust
Posts: 1394
Joined: 05 Mar 2013

Re: Macro help?

Post by floobydust »

Well, I found a listing file for 1581 DOS, apparently during the initial development, as it shows 150 errors and not complete, albeit for the same code level:

ftp://ftp.zimmers.net/pub/cbm/src/drives/serlib.zip

According to the listing, it's using: "(c)1987 CBM Commodore 6502ASM B0.0" as the assembler. The macro definition is slightly changed as:
Quote:
WDTEST .macro
.ife <*!.$03
nop
.endif
.endm
During assembly, it seems to test to see if the instruction is going to start on an address where either bits 0 or 1 active. If not, the test results in a zero and it adds the NOP to ensure that the start address has either or both bits active as part of the address. The burning question now is why??

I also included a snippet of the assembly listing:

Code: Select all

 C428               11765+  	WDTEST		; chk address
            =0000       11766A  	.ife <*!.$03
     C428   EA          11767A  	nop
                        11768A  	.endif
     C429   AD 6000     11769   cmd7n   lda  wdstat
     C42C   29 03       11770   	and  #3
     C42E   4A          11771   	lsr  a
     C42F   90 3E       11772   	bcc  v2
     C431   F0 F6       11773   	beq  cmd7n
                        11774   
     C433   A9 FE       11775   	lda  #$fe   	; id address mark
     C435   8D 6003     11776   	sta  wddat
                        11777   
                        11778   
     C438               11779+  	WDTEST		; chk address
            =0000       11780A  	.ife <*!.$03
     C438   EA          11781A  	nop
                        11782A  	.endif
     C439   AD 6000     11783   cmd7f   lda  wdstat
     C43C   29 03       11784   	and  #3
     C43E   4A          11785   	lsr  a
     C43F   90 2E       11786   	bcc  v2
     C441   F0 F6       11787   	beq  cmd7f
                        11788   
     C443   AD 6001     11789   	lda  wdtrk	; give him the track
     C446   8D 6003     11790   	sta  wddat
                        11791   
     C449               11792+  	WDTEST		; chk address
            =0001       11793A  	.ife <*!.$03
                        11794A  	nop
                        11795A  	.endif
     C449   AD 6000     11796   cmd7e   lda  wdstat
Now that the concept is known (pretty much by accident on my part), how does one use WDC Tools macro capabilities to implement it? BTW - I'm terrible at macros, yet another reason I never use them.
User avatar
floobydust
Posts: 1394
Joined: 05 Mar 2013

Re: Macro help?

Post by floobydust »

I think I have the macro working properly now as:

Code: Select all

WDTEST	.macro
	.if *&$03=0
	nop
	.endif
	.endm
I do get some odd entries in the lower status window of TIDE which I didn't get before that make no sense, basically calling out every include file in the assembly, some with garbage characters, but TIDE isn't exactly a great front end.

I'm going to try and do some additional testing with some changed code and see how it works out. Thanks to everyone for taking the time and sharing some knowledge and ideas. I still don't know the "why" of doing this however.
User avatar
floobydust
Posts: 1394
Joined: 05 Mar 2013

Re: Macro help?

Post by floobydust »

So, all seems good. I made some changes to the code:

- integrated the patch file updates into the core routines so no need to include it.
- integrated the -02 ROM updates into the core routines
- re-wrote the MSUB1 routine to use a simple loop instead of twice 256 times to move track cache to/from buffers (saves over 2KB)
- removed the page boundary equates which takes several voids in the ROM code

Code size now is at 20KB. Have done some testing and everything on the drive seems to work fine. Have run some of my ancient C64 Macro Assembler code that runs through 30+ source files and takes ~12 minutes to assemble. Drive appears to perform the same as a stock drive. Having the working Macro makes it easier to modify the code. With the -02 ROM upgrade the initial ROM checksum was disabled, but there is still a ROM test utility that should fail if run, haven't bothered to try that yet. Still, it shouldn't be difficult to get the initial ROM checksum working again.

I still need to clean up a few pieces of code... but if anyone is interested to play around with it, you're welcome to it. As the HW design is quite simple, it should be easy to build a drive up provided you can get an 8520A (or possibly a 6526) and the WD1772 chip. Everything else is readily available.
User avatar
BigDumbDinosaur
Posts: 9425
Joined: 28 May 2009
Location: Midwestern USA (JB Pritzker’s dystopia)
Contact:

Re: Macro help?

Post by BigDumbDinosaur »

floobydust wrote:
I still need to clean up a few pieces of code... but if anyone is interested to play around with it, you're welcome to it. As the HW design is quite simple, it should be easy to build a drive up provided you can get an 8520A (or possibly a 6526) and the WD1772 chip. Everything else is readily available.
The only significant architectural difference between the 6526 and the 65C22 is the former has a time-of-day clock driven by the mains frequency. The 6526 was used in the Commodore 1571 and 1581 floppy drives so CP/M files could be time-stamped. If you can live without that feature I suppose the 65C22 would be usable.
x86?  We ain't got no x86.  We don't NEED no stinking x86!
Post Reply