Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!mailrus!csd4.milw.wisc.edu!indri!lll-winken!uunet!portal!cup.portal.com!Sullivan From: Sullivan@cup.portal.com (sullivan - segall) Newsgroups: comp.sys.amiga Subject: To macro, or not to macro? (LONG) ... a programming style. Message-ID: <18958@cup.portal.com> Date: 30 May 89 06:25:36 GMT Distribution: na Organization: The Portal System (TM) Lines: 402 I've been arguing out the fine points of whether or not macro assembly is good programming style on a local BBS (Digital Mail Box 408/258-5463.) Do macro enhance legibility, or decrease it? When should they be used, and when should one resort to subroutines instead? I felt that it would be better to open the question to a wider community. Below is an edited message tree as the discussion stands thus far. I would be very interested in other opinions. -kls _________________________________________________________________ /V\ Sullivan was the first to learn how to jump without moving. ' Is it not proper that the student should surpass the teacher? To Quote the immortal Socrates: "I drank what?" -Sullivan _________________________________________________________________ Mail to: ...sun!portal!cup.portal.com!Sullivan or Sullivan@cup.portal.com ---- From: Stephan To: Mr. Raster (X) Since when you boot up, the 68020 turn the cache off and you need to set it from 'softwar'.Look pretty simple to do, I might even do it know. The only thing is that I don't have a 68020 compiler:-( And I can't get the developer package from michtron for Devpac... Maybe setcpu can do the job.I heard that some user group order 13 board! They must be pretty happy with it.. Reply(s) #11625 #11628 Msg: #11628 Sec: 6 - the Amiga chulkboard 23-May-89 09:54 PM Subj: #11616 - ?! (R) From: Kevin Smathers To: Stephan (X) Don't let a lack of assemblers stop you. Just define a macro which is a dc.w with the correct words for turning on the cache. (If you want to distribute it you may prefer to actually check the CPU first.) All of the old Intel 8080 assemblers were updated to the expanded instruction set of the Z80 with macros when it first came out. Many people still prefer programming in extended Intel opcodes over Zilog opcodes. -kls Reply(s) #11633 #11730 Msg: #11633 Sec: 6 - the Amiga chulkboard 23-May-89 12:47 AM Subj: #11628 - ?! (R) From: Stephan To: Kevin Smathers (X) That's a idea for the cache, but I don't see myself making 200 macros or more! If you have the 68020 user manual you will se that it include more than maybe 600 opcode! will all those addresing mode.. But I really dind't of that for the cash.Even that need some reading... I wont think of it, untill I find that setcpu wont work...Hope not:-) Well you know the 65x0 INC instruction? well on the 68000 you can use a macro using addq #1, I like to see what go in the file, with macro it's alway stuff hiding from you -> the way to C:-) I like to C what I asem... Reply(s) #11674 (UA RE Q) (Delete): rr Msg: #11674 Sec: 6 - the Amiga chulkboard 24-May-89 10:13 PM Subj: #11633 - ?! (R) From: Kevin Smathers To: Stephan (X) 600 new opcodes on the 68020?!? Good god. There it would be a lot nicer to have a real 68020 assembler. Also macros aren't really capable of doing error checks on their parameters so bad code is hard to kick out. Increment, decrement, and clear are all common macros. MoveQ #0,Dx is a lot faster than CLR.L Dx. Also you could use a CLRA macro which invokes SUB.L Ax,Ax. Macros are just handy ways of extending the built in language. They shouldn't be used for whole subroutines, after all, that is what subroutines are for. In general if a macro is more than 10 instructions long I use a subroutine instead. My favourite macro is LDIR of Z80 fame, which moves a segment of memory Dx bytes long from (Ay) to (Az). Using macros is a lot easier than spelling out each load and branch individually, and the routine is too simple to make into a subroutine (that would be overkill.) -kls Reply(s) #11685 #11731 Msg: #11685 Sec: 6 - the Amiga chulkboard 24-May-89 11:42 PM Subj: #11674 - ?! (R) From: Stephan To: Kevin Smathers (X) Well I use moveq to clead data register, suba for addrss register But dont use macro. Well on the amiga you could use the blitter to copy data! not in a macro but in a librayr, Well great idea:-) next function in the nslibrary:-) You can make that macro. move.w #X,dx 1$ move.b (a0)+,(a1)+ dbeq d0,1$ That also put the 68010 in loop mode, faster... less bus cycle, when running in chip ram, still better in fast than a 68000. I don't like to use macro, Try to read other program with their own macro you need a copy of EACH macro to see whats going on, that's why I use ZERO macro in my programs. Reply(s) #11782 Msg: #11782 Sec: 6 - the Amiga chulkboard 27-May-89 12:57 PM Subj: #11685 - ?! (R) From: Kevin Smathers To: Stephan (X) Once you know what the macros are though it is a lot easier to read code written with them. For instance, it is easier to recognize ZERA A0 ZERD D0 than SUB.L A0,A0 MOVEQ #0,D0 Your memory move sequence is almost exactly what I use for LDIR and LDDR macros. Let me put it another way. To understand a program with lots of macros all you have to have is a good reference to what the macros mean. To understand a program written without them you likewise have to know what the opcodes mean, but you also have to remember lots of little bits of trivia, like what is the fastest way to clear a data register or an address register, how do you specify a loop which is short enough to put the 68010 into loop mode for memory moves, etcetera. Macro names are designed to be mnemonic and simple. If they don't make a program easier to read rather than more difficult then they shouldn't be used. I use macros for inline string compares. It is a lot easier to look at STRCMP A0,A1 than it is to look at the small subprogram required to do the string comparison, but for speed it is also much faster than using an entire subroutine call. (Think about it. Basically it is like adding string opcodes to the 68000 instruction set, only they are really just pseudo ops.) Reply(s) #11803 Msg: #11803 Sec: 6 - the Amiga chulkboard 27-May-89 06:12 PM Subj: #11782 - ?! (R) From: Stephan To: Kevin Smathers (X) :-) I have to disagrea with 90% of what you said... First for me CLR=0 to destination, ok you use CLRD, me ClearData somebody else ClearD You still have to look what to guy do in his call. I don't alway clear a0 long size, sometime I will use address registr for and only clear the 8 fisrt bit.... Macro is confusing! Secondly macro EAT your memory if used for subprogram and will only save you a couple of cycle! it's not a bsr and rts that will take over the 68000:-) For string I used library... Why have 1000 copy of the same rouitne in 10 diferent program run at the same time! But people should add macro 'has' opcode like that, it would be a mess! I already find the 68000 pretty full of opcodes, I would use macro maybe for library call, loading the base address and make the call, but a6 is not a temporary register.So in a look that will call for example 1000 time the GFX library I wont have to load the base address.But I will only save 20,000 cycle here:-) (5000 bus read cycle). If you use macro, make a library out of it and document it.not thing like moveq->clr but routines, you told you where using macro instead of subroutine... I telling you have to guess what a macro do, and to be sure you have to look at it. I saw some early macro pasted on the amiga section (maybe not here) mostly string handling macro.Those macro should be used has subroutines. like: Right: CallRight a0 rts But I have to agree that if you want to use macro has 'opcode' is the perfect solution! I use include instead of macro to include subroutines. Anyway it's a style, but I anderstand a sources without macro faster. Reply(s) #11807 #11836 Msg: #11807 Sec: 6 - the Amiga chulkboard 27-May-89 07:44 PM Subj: #11803 - ?! (R) From: Chris Green To: Stephan (X) Another thing is that if you use a memory move macro for every memory move you do, your code will probably run slower...If moving medium sized or large blocks, it is better to have a subroutine which aligns the addresses, moves long words, and moves multiple longwords per iteration to save loop overhead... that routine is too big to put inline. Reply(s) #11809 Msg: #11809 Sec: 6 - the Amiga chulkboard 27-May-89 09:18 PM Subj: #11807 - ?! From: Stephan To: Chris Green Yes, or why not using the blitter for multy mdedium-large block copy... Anyway that limit you to the first 512k:-( I don't think any developer will use it for 1 meg machine since the new chip set is not spread enought! But I still use the blitter for inside window smooth scrolling, And I'm sure my routine is more eficient than ScrollVport. Well I copy alot small bock of mem, like for a requester qetting the file name...I put my 68010 in loop mode puting #-1 in d0 and loop until move.b (a0)+,(a1)+ copy the null byte and terminate the loop (dbeq). I don't move mutch data around exepted chip data with the blitter and small data in loop mode, both are VERY efecient way to get the job done. So in you routine you check bit 0 and if so you copy the first byte sub 1 to the count, than lsr it by 2 (div by 4) now you CAN't get a odd number twice:-) But you check bit 1 clearit, save it and long copy, if bit 1 was set do a word copy... that's it I guess take care of the case count of 3... Should around 10-15 instruction. And you can get the long copy in loop mode for the 68010! Not a bad idea I will try that:-) 680x0 assembly is THE BEST! I try alot and these the first I felt good with, Well I dont have data from left to right:-) By the way, someone is coming with a 3D library, most of the routine used on the IRIS workstation. Msg: #11836 Sec: 6 - the Amiga chulkboard 28-May-89 07:55 PM Subj: #11803 - ?! (R) From: Kevin Smathers To: Stephan (X) Umm.... a very badly defined macro would force you to reload (eg.) A6 every time you use it, but a well written one would not. Typically for macros, if a parameter is left out then the macro assumes that the register which would require it has already been loaded. For instance GFXCALL LVO_whocareswhat, GFXBASE would load GFXBASE into A6 before calling LVO_whocareswhat(A6), while GFXCALL LVO_whocareswhat would assume that A6 has already been loaded. So you see using macros doesn't have to be a disadvantage. As for string compares, the actual subroutine to count the string length, or to compare two strings is less than ten instructions long. BSR is great if the relative offset is within 64k, otherwise it is SLOW. In line code can speed up tight loops by double that required for subroutine calls. Anything this small *should* be duplicated thousands of times if neccessary. We aren't working with Z80's here. There is at least 400k available for applications, we don't have to scrimp on every byte of code. I find just the opposite with respect to the opcode set of the 68000. There are far too few opcodes. That is a fact which is both good and bad. Since there are very few opcodes it is easy to create macros because none of the opcodes are taken. On the other hand I can't read MOVE D0,(-A7) because it should be (which is much more intuitive) PUSH D0 [,A7] in macros the optional parameters are a useful tool. If not specified just make them the default, otherwise use the item specified. Instead of specialized opcodes, Motorola decided to use a menagerie of addressing modes. I like opcodes more than addressing modes. That was the problem with the Z80 instruction set. Everything that the beast could do was in a LD instruction. -kls Reply(s) #11839 #11848 sg: #11848 Sec: 6 - the Amiga chulkboard 28-May-89 11:00 PM Subj: #11836 - ?! (R) From: Stephan To: Kevin Smathers (X) Here again! can't you write jsr _xxx(a6) intead of CLVOCALL or somethinf the like!?! And I don't alway use a6 for dos dos, for speed I use a5 in tight loop where I need 2 diferent call to librarys! you can't read d0,-(a7)? hey assembly lenguage isn't C the good thing about it is you don't have to pass 2 year learn off the functions, restriction, format etc... etc... I'm sory but move d0,-(a7) I find that better than push, because in push you need the notion of stack pointer and knowing also that it decrement the destination before ->>>MOVING<<<<--- the data!!!! My stringlenght routine is 4 instruction and 10 byte loop, with 1 instruction in the loop itself.And it work with string of 4 gigabyte long:-) I still don't see the point of macro, it's a extra work that you don't have to do, and if you alway want to use them it's a limit. I 68000 don't need stuff like PUSH COPY, they are already there with equivalent names.What you are trying to do is 'customizing' it for 'yourself'. I don't use small subrouitne in short loop, but I use them in the program itself.Because you source will be cleaner and if you call the function only 10 time in a large program, I prefere to have a source 100 lines smaller and deal with a couple of extra cycles. But I don't say you shouldn't use macro, just macro are not my style. Reply(s) #11896 Msg: #11896 Sec: 6 - the Amiga chulkboard 29-May-89 09:02 PM Subj: #11848 - ?! From: Kevin Smathers To: Stephan (X) Hell, a hundred lines is about 500 bytes which is less than the length of this message. Everyone has their own way of doing things I suppose. Ever since I got a good macro compiler I've reserved subroutines for things that really need them. (Ie: over 10 instructions in length.) Lots of addressing modes confuse me. It is easy to forget whether a particular mode is indexed relative, or absolute, or some other weird mixture. I'm never sure how the assembler is going to resole relative references. Are they *specified* as relative offsets, or do you just use a label and the program will automatically create a relative offset. Macros are (for me) a lot easier to remember. I will say though that given current decompilers, writing lots of direct code helps you figure them out a lot faster. I was staring at some code I'd run through ReSource the other day. I sure wish it would decompile to standard macros. :) -kls Msg: #11806 Sec: 6 - the Amiga chulkboard 27-May-89 07:41 PM Subj: #11784 - ?! (R) From: Chris Green To: Kevin Smathers (X) Oh, OK. I generally don't use macros for things like that as they can cause a lazy programmer (like me) to generate extra code. Often, there are special circumstances which can be taken advantage of when doing things like moving memory. For instance, one of the addresses, or the count (or one of the addresses-2, or the count +1) is already available.. also, macros which modify registers without you explicitly telling it to can make code either hard to read or buggy. Basically I use macros when: a) they only ass4emble to one instruction, like PUSHM and POPM (which assemble to MOVE.L regs,-(a7) or b) in special cases in one place in the code ... like a character plotter needs a sequence of 3 or 4 instructions repeated 8 times. Better to use the assembler REPEAT pseudo-op if the code is the same all 8 times, though. or c) for generating structured data. That's on the 68000 and 8086...on the 6502 I go crazy without a whole bunch of macros. Reply(s) #11837 Msg: #11837 Sec: 6 - the Amiga chulkboard 28-May-89 08:11 PM Subj: #11806 - ?! From: Kevin Smathers To: Chris Green In general I make D0, D1, A0, A1 all scratch. I can do anything I want to with them at any time, even in the middle of a macro. (Subroutines do the same.) When I write the macro I document the inputs and outputs including side effects so that I can use them if they are handy. If I'm lazy I just avoid using those registers. All macros should be defined so that they don't require parameters which are already defined. MEMNCPY, or LDIR (whichever you prefer) should look like. LDIR [[source] [,[dest] [,[count] ]]] Source and dest can either be address registers or memory labels. If labels the macro should generate: LEA source,A0 LEA dest,A1 Otherwise the registers specified should be substituted for A0 and A1 throughout the macro. Count if specified as a label should be loaded into D0, and if given as a register should be substituted for D0 through out the subroutine. Side effects would be: Source <- Source + Count A0 <- Source (if label) Dest <- Dest + Count A1 <- Dest (if label) Count <- 0 D0 <- Count (if value) MAcros such as these are easily defined. It doesn't take very much work to avoid generating extra code because of the macro. What does take time is looking up the side effects when you aren't sure what they are. If you meticulously avoid using the scratch registers you won't have to worry about side effects, but you may be losing some useable information. Macros that need more than the scratch registers either PUSH and POP, or become subroutines (which in turn push and pop.) -kls ---- [EOF] ----