How to write demos that work (Version 4.3) - 3/1/93 =================================================== (or How to bash the metal and get away with it) (or the Amiga Demo Coders Reference Manual) by Comrade J, Share and Enjoy (retired) Thanks to everyone on the internet for sending their suggestions, bug reports and comments to me on this article. I'll try and keep this up to date and posted here frequently. Coming soon, source code for a small intro using all these techniques that you can use as the base for whatever you want to do.... Now, is anyone out there going to write a good Amiga 1200 demo, or am I going to have to do it? -------------------------------------------------------------------- Most demos I've seen use similar startup code to that I was using back in 1988. Hey guys, wake up! The Amiga has changed quite a bit since then. So. Here are some tips on what to do and what not to do: 1. RTFM. ======== Read the F**king manuals. All of them. Borrow them off friends or from your local public library if you have to. Read the "General Amiga Development Guidelines" in the dark grey (2.04) Hardware Reference Manual and follow them TO THE LETTER. If it says "Leave this bit cleared" then don't set it! Don't use self-modifying code. A common bit of code I see is: ... in the setup code move.l $6c.w,old ... at the end of the interrupt movem.l (sp)+,a0-a6/d0-d7 dc.w $4ef9 ; jmp instruction old dc.l 0 ; self modifying!!!! DONT DO THIS! This is much better (although it still hits $6c which is not a good thing - It's much better to use AddIntServer() to call your interrupts, ... in the setup code move.l VBRBase(a0) move.l $6c(a0),old ; see under VBR below.... ... at the end of the interrupt movem.l (sp)+,a0-a6/d0-d7 move.l old,-(sp) ; push old address to stack rts ... in your data section old dc.l 0 68020 and above processors with cache enabled often barf at the first piece of code (the cache still contains the JMP 0 instruction which isn't then altered), but the second piece works fine on the '040. 2. Proper Copper startup. ========================= (Please look at the startup example code at the end of this file). IF you are going to use the copper then this is how you should set it up. The current workbench view and copper address are stored, the system frozen, and then the copper enabled. On exit the workbench view is restored. This guarantees(*) your demo will run on an AGA (Amiga 1200) machine, even if set into some weird screenmode before running your code. Otherwise under AGA, the hardware registers can be in some strange states before your code runs, beware! The LoadView(NULL) forces the display to a standard, empty position, flushing the crap out of the hardware registers: Note. There is a bug in the V39 OS on Amiga 1200/4000 and the sprite resolution is *not* reset, you will have to do this manually if you use sprites... Two WaitTOF() calls are needed after the LoadView to wait for both the long and short frame copperlists of interlaced displays to finish. See the bottom of this file for a full, tested, example startup.asm code, that you can freely use for your own productions. It has been suggested to me that instead of using the GfxBase gb_ActiView I should instead use the Intuition ib_ViewLord view. This will work just as well, but there has been debate as to whether in the future with retargetable graphics (RTG) this will work in the same way. As the GfxBase is at a lower level than Intuition, I prefer to access it this way (but thank's for the suggestion Boerge anyway!). Using gb_ActiView code should run from non-Workbench environments (for example, being called from within Amos) too... CJ 1, Chris Green (CBM USA) 0 :-) * - Nothing is ever guaranteed where Commodore are involved. They may move the hardware registers into chipram next week :-) 3. Your code won't run from an icon. ==================================== You stick an icon for your new demo (not everyone uses the CLI!) and it either crashes or doesn't give back all the RAM it uses. Why? Icon startup needs specific code to reply to the workbench message. With the excellent Hisoft Devpac assember, all you need to do is add the line include "misc/easystart.i" and it magically works! For those without Devpac, here is the relevent code: --------------------------------------------------------- * some startup code to make a Workbench execute look like the CLI * based loosely on RKM Vol 1 page 4-36 * Include this at the front of your program * after any other includes * note that this needs exec/exec_lib.i IFND EXEC_EXEC_I include "exec/exec.i" ENDC IFND LIBRARIES_DOSEXTENS_I include "libraries/dosextens.i ENDC movem.l d0/a0,-(sp) save initial values clr.l returnMsg sub.l a1,a1 move.l 4.w,a6 jsr _LVOFindTask(a6) find us move.l d0,a4 tst.l pr_CLI(a4) beq.s fromWorkbench * we were called from the CLI movem.l (sp)+,d0/a0 restore regs bra end_startup and run the user prog * we were called from the Workbench fromWorkbench lea pr_MsgPort(a4),a0 move.l 4.w,a6 jsr _LVOWaitPort(A6) wait for a message lea pr_MsgPort(a4),a0 jsr _LVOGetMsg(A6) then get it move.l d0,returnMsg save it for later reply * do some other stuff here RSN like the command line etc nop movem.l (sp)+,d0/a0 restore end_startup bsr.s _main call our program * returns to here with exit code in d0 move.l d0,-(sp) save it tst.l returnMsg beq.s exitToDOS if I was a CLI move.l 4.w,a6 jsr _LVOForbid(a6) move.l returnMsg(pc),a1 jsr _LVOReplyMsg(a6) ; ***** This line was missing from ; previous articles!!!! ********** jsr _LVOPermit(a6) exitToDOS move.l (sp)+,d0 exit code rts * startup code variable returnMsg dc.l 0 * the program starts here even _main --------------------------------------------------------- 4. How do I tell if I'm running on an Amiga 1200/4000? ====================================================== Do *NOT* check library revision numbers, V39 OS can and does run on standard & ECS chipset machines (This Amiga 3000 is currently running V39). This code will check for AGA move.w $dff07c,d0 cmp.b #$f8,d0 bne.s .notaga ; Do your funky AGA Stuff in here! .notaga 5. Use Relocatable Code ======================= If you write demos that run from a fixed address you should be shot. NEVER EVER DO THIS. It's stupid and completely unnecessary. If you require bitplanes to be on a 64Kb boundary then try the following (in pseudo-code because I'm too lazy to write it in asm for you): for c=0 to (top of chip ram) step 65536 if AllocAbs(c,NUMBER_OF_BYTES_YOU_WANT) == TRUE then goto ok: next c: print "sorry. No free ram. Close down something and retry demo!" stop ok: Run_Outrageous_demo with mem at c Keep your code in multiple sections. Several small sections are better than one large section, they will more easilly fit in and run on a system with fragmented memory. 6. Don't Crunch demos! ====================== Don't ever use Tetrapack or Bytekiller based packers. They are crap. Many more demos fall over due to being packed with crap packers than anything else. If you are spreading your demo by electronic means (which most people do now, the days of the SAE Demodisks are long gone!) then assemble your code, and use LHARC to archive it, you will get better compression with LHARC than with most runtime packers. If you *have* to pack your demos, then use Powerpacker 4+, Turbo Imploder or Titanics Cruncher, which I've had no problems with myself. 7. Don't use the K-Seka assembler! ================================== It's dead and buried. Get a life, get a real assembler. Hisoft Devpac is probably the best all-round assembler, although I use ArgAsm which is astonishingly fast. The same goes for hacked versions of Seka. 8. Don't use the hardware unless you have to! ============================================= This one is aimed particularly at utility authors. I've seen some *awfully* written utilities, for example (although I don't want to single them out as there are plenty of others) the Kefrens IFF converter. There is NO REASON why this has to have it's own copperlist. A standard OS-friendly version opening it's own screen works perfectly (I still use the original SCA IFF-Converter), and multitasks properly. If you want to write good utilities, learn C. 9. Beware bogus input falling through to Workbench ================================================== If you keep multitasking enabled and run your own copperlist remember that any input (mouse clicks, key presses, etc) fall through to the workbench. The correct way to get around this is to add an input server to the IDCMP food chain (see - you *do* have to read the other manuals!) at a high priority to grab all input events before workbench/cli can get to them. Look at the sourcecode for Protracker for an excellent example of how to do the job properly. Well done Lars! 10. Have fun! ============= Too many people out there (particularly the American OS-Lamic Fundamentalists) try to tell us that you should never program at a hardware level. If you're programming for fun, ignore them! But try and put a little thought into how your code will work on other machines, nothing annoys people more than downloading 400Kb of demo and then finding it blows up on their machines. I'm not naming any names, but there are quite a few groups who I have no intention of downloading their demos again because I know it's a waste of download. With the launch of the Amiga 1200 you cannot just write for 1.3 Amiga 500's any more. Let's go out there and write some shit hot demos! 11. Don't Publish Code you haven't checked! =========================================== Thanks to Timo Rossi for spotting the stupid bug in my copper setup routine (using LOFList instead of copinit). Funnily enough my own setup routine uses the correct copinit code: Please ignore the original file (howtocode.txt) and use this instead. 12. Copper End ============== I've remembered where this double copper end comes from: The ArgAsm assembler has copper macros (CMOVE, CWAIT and CEND) built in, and the CEND macro deliberately leaves two copper END instructions, the manual states this is important for compatibility reasons.. When I get back to the office on Monday I'll look this up... 13. Vector Base Register (68010 and up) ======================================= The 68010 and above processors have a Vector Base Register (VBR) that allows the exception vector table to be placed anywhere in RAM, including fast ram. This gives some speed benefits to systems with this running, but at a cost. Anything that accesses the interrupt locations directly, for example: move.l $6c.w,old move.l MyWickedInterruptCode,$6c.w won't work... Unfortunately this includes 99.9% of demos. Boerg Noest (borgen@stud.cs.uit.no) writes.... > Next your text should mention VBR. It's easy - like this: > move.l 4.w a6 > moveq #0,d0 > btst.b #AFB_68010,AttnFlags+1(a6) > beq .done > movec vbr,d0 >.done > move.l d0,VBRBase > rts > then you just > move.l VBRBase,a0 move.l $6c(a0),oldinterrupt > move.l #myinterrupt,$6c(a0) > Ok. I don't know how many people use the VBR to offset their interrupts, I certainly don't as it breaks too much software on my 3000, and it only gives a minimal speed increase. The main benefit of the 68010 over the 68000 is the loop cache mode. Common 3 word loops like: moveq #50,d0 .lp move.b (a0)+,(a1)+ ; one word dbra d0,.lp ; two words are recognised as loops and speed up dramatically on 68010. 14 Using the blitter. ===================== If you are using the blitter in your code and you are leaving the system intact (as you should) always use the graphics.library functions OwnBlitter() and DisownBlitter() to take control of the blitter. Remember to free it for system use, many system functions (including floppy disk data decoding) use the blitter. Another big mistake I've seen is with blitter/processor timing. Assuming that a particular routine will be slow enough that a blitter wait is not needed is silly. Always check for blitter finished, and wait if you need to. Don't assume the blitter will always run at the same speed too. Think about how your code would run if the processor or blitter were running at 100 times the current speed. As long as you keep this in mind, you'll be in a better frame of mind for writing compatible code. Another big source of blitter problems is using the blitter in interrupts. Most demos do all processing in the interrupt, with only a .wt btst #6,$bfe001 ; is left mouse button clicked? bne.s .wt loop outside of the interrupt. However, some demos do stuff outside the interrupt too. Warning. If you use blitter in both your interrupt and your main code, (or for that matter if you use the blitter via the copper and also in your main code), you may have big problems.... Take this for example: lea $dff000,a5 bsr WaitBlitterFinish ; check bits for blitter ready move.l #-1,BLTAFWM(a5) ; set FWM and LWM in one go move.l #source,BLTAPT(a5) move.l #dest,BLTDPT(a5) move.w #100111110000,BLTCON0(a5) move.w #0,BLTCON1(a5) move.w #64*height+width/2,BLTSIZE(a5) ; trigger blitter There is *nothing* stopping an interrupt, or copper, triggering a blitter operation between the WaitBlitterFinish call and your final BLTSIZE blitter trigger. This can lead to total system blowup. Code that may, by luck, work on standard speed machines may die horribly on faster processors due to timing differences causing this type of problem to occurr. The safest way to avoid this is to keep all your blitter calls together, use the copper exclusively, or write a blitter-interrupt routine to do your blits for you. Always remember to do two blitter-wait-checks... eg: btst.b #DMAB_BLTDONE-8,DMACONR(a1) btst.b #DMAB_BLTDONE-8,DMACONR(a1) The first may not give the correct result on machines with early (non Fat) Agnus chips (eg Amiga 1000, German A2000). The Hardware Reference manual explains why, if you're interested. 15 NTSC ======= As an European myself, I'm naturally biased agains the inferior video system, but even though the US & Canada have a relatively minor Amiga community compared with Europe (Sorry, it's true :-) we should still help them out, even though they've never done a PAL Video Toaster for us (sob!). You have two options. Firstly, you could write your code only to use the first 200 display lines, and leave a black border at the bottom. This annoys PAL owners, who rightly expect things to have a full display. It took long enough for European games writers to work out that PAL displays were better. You could write code that automatically checked which system it is running on and ran the correct code accordingly: (How to check: Note, this is probably not the officialy supported method, but so many weird things happen with new monitors on AGA machines that I prefer this method, it's simpler, and works under any Kickstart) move.l 4.w,a6 ; execbase cmp.b #50,PowerSupplyFrequency(a6) ; 531(a6) beq.s .pal jmp I'm NTSC (or more accurately, I'm running from 60Hz power) .pal jmp I'm PAL (or I'm running from 50hz power). If people have already switched modes to PAL, or if they are running some weird software like the ICD Flicker Free Video Prefs thingy, then this completely ignores them, but that serves them right for trying to be clever :-) Probably better would be to check VBlankFrequency(a6) [530(a6)] as well, if both are 60Hz then it's definately a NTSC machine. If one or more are 50Hz, then it's probably a better idea to run in PAL. Under Kickstart 2.04 or greater, the Display Database can be accessed. Any program can enquire of the database what type of displays are available, so for example "I want a 50hz 15Khz PAL screen. Can I display it on this Amiga?" (Unfortunately it doesn't take an ASCII string like that, but it's not much more dificult). Of course many users will have the default monitor installed (PAL or NTSC) and not realise that they can have extra modes by dragging the monitor icon into their Monitors drawer, and of course this doesn't work on Kickstart 1.3 machines. Now, if you want to force a machine into the other display system you need some magic pokes: Here you go (beware other bits in $dff1dc can do nasty things. One bit can reverese the polarity on the video sync, not to healthy for some monitors I've heard...) To turn a NTSC system into PAL (50Hz) move.w #32,$dff1dc ; Magically PAL To turn a PAL system into NTSC (60Hz) move.w #0,$dff1dc ; Magically NTSC Remember: Not all displays can handle both display systems! Commdore 1084/1084S, Philips 8833/8852 and multisync monitors will, and very few US TV's will handle PAL signals (especially if being used with a NTSC Amiga modulator). I gather that most NTSC machines are Amiga 2000's, so perhaps this isn't a problem. So come on you NTSC users, tell us how you would prefer the demos written! 16 Programming AGA hardware =========================== I've just got this interesting text file which I thought should be included with this document. I've now translated it into better English :-) "The following information was gathered by Junkie/PMC Fr and Yragael. Junkie bought a 1200 and started to dissassemble the workbench copperlist. Thanks to this important work and his impressive speed (which lead me to dissassemble the copperlist too, I (Yragel) bring you the following information: More will follow (unless we get the official AGA hardware reference manual) [You'll be lucky :-) CJ] We now wait to see your productions on the 1200, and with your cooperation we can trip into the hardware of the A1200. [? Are these guys French or what? :-)] (next issue: Sprite corrections, HAM8+, other graphic modes, 3 words copperlists ...) *************************************************************************** USING THE SUPERHIRES MODE To use the SuperHires mode (1280 pixels wide), just use the bit 6 of register $0100 bit 6 | Mode SuperHires ----------------------- 0 | Normal ----------------------- 1 | SuperHires ----------------------- *************************************************************************** USING 8 BITPLANES The number of bitplanes available used to be no more than 7 and was coded using the bits 14 to 12 of register $0100. To use 8 bitplanes, just use bit 4 of register $0100. The value of bits 14 to 12 will then not be considered anymore (CJ - It's probably better to set this to %111 for future compatibility) bit 4 | 8 bitplanes mode ------------------------ 0 | 0 to 7 bitplanes (from bits 12 - 14) ------------------------ 1 | 8 bitplanes ------------------------ *************************************************************************** ACCESSING 24 BITS COLOURS The 24 bit colour values are coded using 2 words: - the first receives the 4 high bits of each R, G and B componants - the second receives the 4 low bits of each R, G and B componants To modify a color using 24 bits coding, you must use 2 coppers-moves on the same color register. The first move must always be the move of the word of the 3*4 high bits, the second move is the move of the word of the 3*4 low bits. You set whether to write the high or the low bits by setting or clearing bit 9 of register $0106 bit 9 | Components access ----------------------------------------------------------------- 0 | Access to the 4 high bits of components R, G and B ----------------------------------------------------------------- 1 | Access to the 4 low bits of components R, G and B ----------------------------------------------------------------- ** Editorial note: Looks like he got a little confused about ** high and low bits here: ** ** Take $f1f200 (a bright yellow), the high-bits word is $ff0 ** (look familiar?), and the low-bits word is $120. - CJ ex: change $0180 to $00123456 in the copperlist $01060000 $01800135 $01060200 $01800246 When you want to work using the 12 bits color coding mode, the 3*4 bits value you move to the color register is considered by the copper as the 3*4 high bits. You don't have to care about $0106. It seems bit 9 of register $0106 is initialized to 0 at each copjmp. (Editorial note: The following code *will* work: $1060000 ; set high bits $1800123 ; high bits register 0 $1820123 ; high bits register 1 ... etc $1060200 ; set low bits $1800456 ; low bits register 0 $1820567 ; low bits register 1 ... etc ie, you don't have to do the high bits and low bits of each colour immediately after each other. This saves lots of needless $106 commands!) *************************************************************************** ACCESSING THE 256 COLOURS PALETTE The amiga doesn't work with 256 separate color registers. The same colour register is used several times to code several colors. The amiga just works with 8 differents palettes of 32 colors each, using color registers from $0180 to $01BE. You can choose the palette you want to access via the bits 11 to 14 of register $0106 bit 14 | bit 13 | bit 12 | Selected palette -------------------------------------------------------- 0 | 0 | 0 | Palette 0 (color 0 to 31) -------------------------------------------------------- 0 | 0 | 1 | Palette 1 (color 32 to 63) -------------------------------------------------------- 0 | 1 | 0 | Palette 2 (color 64 to 95) -------------------------------------------------------- 0 | 1 | 1 | Palette 3 (color 96 to 125) -------------------------------------------------------- 1 | 0 | 0 | Palette 4 (color 128 to 159) -------------------------------------------------------- 1 | 0 | 1 | Palette 5 (color 160 to 191) -------------------------------------------------------- 1 | 1 | 0 | Palette 6 (color 192 to 223) -------------------------------------------------------- 1 | 1 | 1 | Palette 7 (color 224 to 255) -------------------------------------------------------- ex: You want to change color 177 to $00123456 Color 177 is color $01A2 of palette 5 $01065000 $01a20135 $01065200 $01a20245 * (Editorial note: This was wrong and has been fixed!!! - CJ) *************************************************************************** SWITCHING THE PALETTE You can switch colors. The definition of switching color A and color B is: - Color registers of colors A and B are NOT modified by the switching - Color A is displayed using the content of register of color B and vice-versa The switching of palette can't be used on just n colors of the palette. Once you choose a switching value, ALL the palette's colors will be switched. The switching value is the value separing the colors to be switched and is coded with bits 15 to 8 of register $010C. ex: You want all the colors separated by one color in the colorlist to be switched $0180 <-- $0182 <--|-- $0184 <-- | $0186 <----- $0188 <-------- . | . . Value 2 will be stocked in bits 15 to 8. The switching works with the palette as if it was a circular palette. I mean if if the copper consider color 255 and must switch by 1 the colors, color $0180 will be assiocated to color 255. (??? - CJ) (Editorial note: A bit confusing here. the high byte of the $dff10c register (BPLCON4) seems to be an XOR value: So, if you set the value to $FF, all colour registers are negated, eg Colour 255 = colour 0, colour 1 = 254, etc... - CJ) *************************************************************************** USING SPRITES IN LOWRES, HIRES AND SUPERHIRES To change the reolution of the sprite, just use bit 7 and 6 of register $0106 bit 7 | bit 6 | Resolution -------------------------- 0 | 0 | Lowres (140ns) -------------------------- 1 | 0 | Hires (70ns) -------------------------- 0 | 1 | Lowres (140ns) -------------------------- 1 | 1 | SuperHires (35ns) -------------------------- (Now.. 70ns sprites may not be available unless the Interlace bit in BPLCON0 is set. Don't ask me why.... CJ) *************************************************************************** USING 16, 32 AND 64 PIXELS WIDE SPRITES Well, I still have bug there with sprites in 32 or 64 pixels. Sorry but the followings informations may have to be corrected. Use bit 3 and 2 of register $01FC bit 3 | bit 2 | Wide ------------------------- 0 | 0 | 16 pixels ------------------------- 1 | 0 | 32 pixels ------------------------- 0 | 1 | 32 pixels ------------------------- 1 | 1 | 64 pixels ------------------------- The copper doesn't read the spritelist in the same way regarding the wide you choose for your sprite 16 pixels wide reading: word C1, word C2 word A1, word B1 . . . word An, word Bn $0000 0000 C1=first control word C2=second control word Ai and Bi are combined via OR to form the sprite 32 pixels wide reading: long C1, long C2 long A1, long B1 . . . long An, long Bn $0000 0000 0000 00000 C1=first control long the first control word is the high word of C1. The low word of C1 must contain the second control word. C2=second control long the second control word is the high word of C2. Low word of C2 is $0000 Ai and Bi are combined via OR to form the sprite 64 pixels wide reading: double C1, double C2 double A1, double B1 . . . double An, double Bn $0000 0000 0000 00000 0000 0000 0000 00000 C1=first control double C1=W3:W2:W1:W0 (Wi=words) W3 is first control word W2 and W1 are second control word C2=second control double C2=W3:W2:W1:W0 (Wi=words) W3 is second control word Ai and Bi are combined via OR to form the sprite *************************************************************************** CHANGING THE SPRITE PALETTE It is possible to choose the color palette of the sprite. This is done by the bits 7 and 4 of register $010C. bit 7 | bit 6 | bit 5 | bit 4 | Starting color of the sprite's palette ------------------------------------------------------------------------- 0 | 0 | 0 | 0 | $0180/palette 0 (coulor 0) ------------------------------------------------------------------------- 0 | 0 | 0 | 1 | $01A0/palette 0 (color 15) ------------------------------------------------------------------------- 0 | 0 | 1 | 0 | $0180/palette 1 (color 31) ------------------------------------------------------------------------- 0 | 0 | 1 | 1 | $01A0/palette 1 (color 47) ------------------------------------------------------------------------- 0 | 1 | 0 | 0 | $0180/palette 2 (color 63) ------------------------------------------------------------------------- 0 | 1 | 0 | 1 | $01A0/palette 2 (color 79) ------------------------------------------------------------------------- 0 | 1 | 1 | 0 | $0180/palette 3 (color 95) ------------------------------------------------------------------------- 0 | 1 | 1 | 1 | $01A0/palette 3 (color 111) ------------------------------------------------------------------------- 1 | 0 | 0 | 0 | $0180/palette 4 (color 127) ------------------------------------------------------------------------- 1 | 0 | 0 | 1 | $01A0/palette 4 (color 143) ------------------------------------------------------------------------- 1 | 0 | 1 | 0 | $0180/palette 5 (color 159) ------------------------------------------------------------------------- 1 | 0 | 1 | 1 | $01A0/palette 5 (color 175) ------------------------------------------------------------------------- 1 | 1 | 0 | 0 | $0180/palette 6 (color 191) ------------------------------------------------------------------------- 1 | 1 | 0 | 1 | $01A0/palette 6 (color 207) ------------------------------------------------------------------------- 1 | 1 | 1 | 0 | $0180/palette 7 (color 223) ------------------------------------------------------------------------- 1 | 1 | 1 | 1 | $01A0/palette 7 (color 239) ------------------------------------------------------------------------- *************************************************************************** That's all. Thanx you VERY MUCH to Junkie/PMC Fr for his work. Written by Yragael. Translated & Bugfixed by Comrade J Chaos. Live it. Learn it. Be it. _\!/_ The Illuminated Ones _\!/_ /!\ ««««««««««»»»»»»»»»» /!\ Interesting, eh? 17. Keyboard Timings ==================== If you have to read the keyboard by hardware, be very careful with your timings. Not only do different processor speeds affect the keyboard timings (for example, in the game F-15 II Strike Eagle on an Amiga 3000 the key repeat delay is ridiculously slow, you ttyyppee lliikkee tthhiiss aallll tthhee ttiimmee. You use up an awful lot of Sidewinders very quickly!), but there are differences between different makes of keyboard (for example, some Amiga 2000's come with Cherry keyboards, these have small function keys (same size as normal alphanumeric keys - these keyboards have different timings to the normal Mitsumi keyboards. Again, here's something from Boerge: >Third, you should warn about f**king up the keyboard read timing. My keyboard >absolutely does not work with just reading the $bfxxxx turning it to output, >and writing the reply, and turning it to input again. I do not have any code >that is especially good, but for now I use this: > move.b $bfec01,d0 ;get keycode > not.b d0 > lsr.b #1,d0 ;test up/down flag > bcs.s .NoStore ;if up, ignore > > move.b d0,Key >.NoStore > >;handshake > bset #6,$bfee01 ;output > clr.b $bfec01 > moveq #4-1,d0 >.L1 move.b VHPOSR,d1 >.L2 cmp.b VHPOSR,d1 > beq.b .L2 > dbra d0,.L1 > > bclr #6,$bfee01 ;input again Remember though, if you have system interrupts and workbench enabled, keys can fall-through to workbench. For example, press Amiga-Q in your demo and you may find Workbench closed on return! 18. How to break out of never-ending loops ========================================== Another great tip for Boerge here: >This is a simple tip I have. I needed to be able to break out of my >code if I had neverending loops. I also needed to call my exit code when I did >this. Therefore I could not just exit from the keyboard interrupt which I have >taken over(along with the rest of the machine). My solution wa to enter >supervisor mode before I start my program, and if I set the stack back then >I can do an RTE in the interrupt and just return from the Supervisor() call. >This is snap'ed from my code: > > lea .SupervisorCode,a5 > move.l sp,a4 ; > move.l (sp),a3 ; > EXEC Supervisor > bra ReturnWithOS > >.SupervisorCode > move.l sp,crashstack ; remember SSP > move.l USP,a7 ; swap USP and SSP > move.l a3,-(sp) ; push return address on stack > >that last was needed because it was a subroutine that RTSes (boy did I have >porblems working out my crashes before I fixed that) >Then I have my exit code: > >ReturnWithOS > tst.l crashstack > beq .nocrash > move.l crashstack,sp > clr.l crashstack > RTE ; return from supervisor mode >.nocrash > >my exit code goes on after this. > >This made it possible to escape from an interrupt without having to care >for what the exception frames look like. 19. Version numbers! ==================== Put version numbers in your code. This allows the CLI version command to determine easily the version of both your source and executable files. Some directory utilities allow version number checking too (so you can't accidentally copy a newer version of your source over an older one, for example). Of course, if you pack your files the version numbers get hidden. Leaving version numbers unpacked was going to be added to PowerPacker, but I don't know if this is done yet. A version number string is in the format $VER: howtocode4.txt 4.2 02/01/92. ^ ^ ^Version number (date is optional) | | | | File Name | | Identifier The Version command searches for $VER and prints the string it finds following it. For example, adding the line to the begining of your source file ; $VER: MyFunDemo.s 4.0 01/01/93 and somewhere in your code dc.b "$VER: MyFunDemo 4.0 01/01/93",0 means if you do VERSION MyFunDemo.s you will get: MyFunDemo.s 4.0 01/01/93 and if you assemble and do Version MyFunDemo, you'll get MyFunDemo 4.0 01/01/93 Try doing version howtocode4.txt and see what you get :-) This can be very useful for those stupid demo compilations where everything gets renamed to 1, 2, 3, etc... Just do version 1 to get the full filename (and real date) Does this work on Kickstart 1.3? I can't remember, I ditched my 1.3 Kickstart 2 years ago :-) 20. CDTV ======== I've been asked if there is any special advice on how to program demos to work on CDTV, and if hardware access to the CDTV (for playing CD Audio, etc) is possible. The CDTV is essentially a 1Mb chip ram Amiga with a CD-ROM drive. The major difference (apart from lack of fast ram or $c00000 ram) is that the CDTV roms can take up anything from 100-200Kb of ram. Many demos fail on CDTV through lack of memory. You can hack your CDTV to switch on/off these roms (put a switch on JP15), when switched off the CDTV has a full 1Mb of memory and more software works, but you can still play audio CD's in the CD drive.. I have no information on how to program the CDTV at the hardware level. Currently the only supported way to access the CDTV special functions is by the CDTV.DEVICE, a standard ROM device that can be OpenDevice()d and sent IORequests. I don't think I'm allowed to give out the documentation for this, sorry :-( 21. Copper Wait Commands ======================== The Hardware Reference manual states a copper wait for the start of line xx is done with: $xx01,$fffe However (as many of you have found out), this actually triggers just before the end of the previous line (around 4 or 5 low-res pixels in from the maximum overscan border). For most operations this is not a problem (and indeed gives a little extra time to initialise stuff for the next line), but if you are changing the background colour ($dff180), then there is a noticalbe 'step' at the end of the scanline. The correct way to do a copper wait to avoid this problem is $xx07,$fffe. This just misses the previous scanline, so the background colour is changed exactly at the start of the scanline, not before. 22. Screen Modulos (thanks Magnus for this one...) ================================================== Don't assume bitplane modulos (BPL0MOD and BPL1MOD) will be set to zero. If you require zero modulos set them, at the start of your copperlist is as good a place as any. Under V39 OS the workbench is interleaved by default, so the modulo can be huge... 23. Open Graphics Library! (again, thanks Magnus) ================================================= I've never seen this in use before, but Magnus spotted it. It's got to be one of the worst pieces of code I've ever seen! Don't ever do this! move.l 4.w,a0 ; get execbase move.l (a0),a0 ; wandering down the library list... move.l (a0),a0 ; right. I think this is graphics.library ; now goes ahead and uses a0 as gfxbase... Oh yes, graphics.library is always going to be second down the chain from Execbase? LISTEN and LISTEN good. If you want to access gfxbase (or any other library base) OPEN the library. Do not wander down the library chain, either by guesswork or by manually checking for "graphics.library" in the library base name. OpenLibrary() will do this for you. 24. Protracker Replay code bug ============================== I've just got the Protracker 2.3 update, and the replay code (both the VBlank and CIA code) still has the same bug from 1.0! At the front of the file is an equate >DMAWait = 300 ; Set this as low as possible without losing low notes. And then it goes on to use 300 as a hard coded value, never refering to DMAWait! Now, until I can get some free time to write a reliable scanline-wait routine to replace their DBRA loops (does anyone want to write a better Protracker player? Free fame & publicity :-), I suggest you change the references to 300 in the code (except in the data tables!) to DMAWait, and you make the DMAWait value *MUCH* higher. I use 1024 on this Amiga 3000 without any apparent problem, but perhaps it's safer to use a value around 2000. Has anyone tried Protracker on a 68040 machine, if so, what DMAWait value in Prefs is needed to make all modules sound ok? 25. Optimise mode on produces crap code? ======================================== If you're using Devpac and have found that the OPT o+ flag produces crap code, then you need to add the option o3-. I can't remember what this option does, my Devpac 3 manual is at the office. 26. Argasm produces crap code, whatever happens =============================================== First, Argasm (unlike Devpac) from the Command Line or if called from Arexx using Cygnus Ed (my prefered system) defaults to writing linkable code, so you need to add opt l- (disable linkable code) If you find that your Argasm executables fail then check you haven't got any BSR's across sections! Argasm seems to allow this, but of course the code doesn't work. Jez San from Argonaut software who publish ArgAsm says it's not a bug, but a feature of the linker... Yeah right Jez... But Argasm is *fast*, and it produces the *fastest* non-working code of any assembler :-) I still use it though, but Devpac comes in handy for checking code every now and then. Argonaut have abandoned ArgAsm so the last version (1.09d) is the last. There will be no more... 27. Help! I'm starting to code in assembler. Where do I begin? ============================================================== If you are just starting to learn programming, and you want a good place to begin learning assembler, buy Amos!. It's very easy to write assembler code, load it into amos and test it. For example, take this routine: ;simplemaths.s add.l d0,d1 ; add contents of d0 to d1 rts Assemble this with Devpac and what do you get? Not a lot. Now, load AMOS and type this: Pload "ram:simplemaths",1 ' load executable file into bank 1 Input "Enter a number ";n1 Input "Enter another number ";n2 dreg(0) = n1 ' Store n1 in 68000 register d0 dreg(1) = n2 ' Store n2 in 68000 register d1 call(1) ' Run your machinecode routine Print n1;" plus ";n2;" equals ";dreg(1) ' returns result in d1 You can start playing with 68000 instructions this way, seeing how they work, without having to 'jump in the deep end' writing routines to set up displays, copperlists, windows or writing to the console. Once you have got the hang of 68000, you can drop Amos. 28 How can I tell what processor I am running on? ================================================= Look inside your case. Find the large rectangular (or Square) chip, read the label :-) Or... move.l 4.w,a6 move.w AttnFlags,d0 ; get processor flags d0.w is then a bit array which contains the following bits Bit Meaning if set 0 68010 processor fitted 1 68020 processor fitted 2 68030 processor fitted 3 68040 processor fitted 4 68881 MMU fitted 5 68882 MMU fitted There may well be other flags set now, I only have old documentation at home.. DO NOT assume that the system has a >68000 if the word is non-zero! 68881 chips are available on add-on boards without any faster processor. And don't assume that a 68000 processor means a 7Mhz 68000. It may well be a 14Mhz processor. So, you can use this to determine whether specific processor functions are available (more on 68020 commands in a later issue), but *NOT* to determine values for timing loops. Who knows, Motorola may release a 100Mhz 68020 next year :-) 29 All addresses are 32 bit =========================== "Oh look" says clever programmer. "If I access $dcdff180 I can access the colour0 hardware register, but it confuses people hacking my code!". Oh no you can't. On a machine with a 32-bit address bus (any accelerated Amiga) this doesn't work. And all us hackers know this trick now anyway :-) Always pad out 24-bit addresses (eg $123456) with ZEROs in the high byte ($00123456). Do not use the upper byte for data, for storing your IQ, for scrolly messages or for anything else. Similarly, on non ECS machines the bottom 512k of memory was paged four times on the address bus, eg: move.l #$12345678,$0 move.l $80000,d0 ; d0 = $12345678 move.l $100000,d1 ; d1 = $12345678 move.l $180000,d2 ; d2 = $12345678 This does not work on ECS and upwards!!!! You will get meaningless results if you try this, so PLEASE do not do it! 30. New Chipsets? ================= TO : ALL CODERS IN THE AMIGA DEMO-/GAMESCENE !!! New Low- Highend Chipset ------------------------ Got this message from a BBS... >As we heard from serious Commodore developers, there >will be a new Low-end and a High-end chipset. This is no secret. This was announced by Lew Egelbrecht (sp?) head of Commodore Engineering a couple of months back >The High-end chipset will feature totally new customchips. >They will bring 16 Bit Sound and some other new features. >There will be no DSP (Digital Signal Processor) like >the MOTOROLA 68851 in this AMIGA. Instead of it, there >will take a new Commodore own Signal Processor part in this >wonderful machine. This is not what I heard. I head the AT&T DSP would probably be used (a true floating point DSP, unlike the integer one found in the Atari Falcon). The 68851 is a Memory Management Unit for the 68020, not a DSP. >The new chips are not fully compatible to AA Chips. Most of >the new AA Registers like $dff106 and $dff10c will be changed. >That's the reason, why Commodore didn't released a new >A1200 and A4000 Hardware Reference Manual. This is exactly what I have heard from *very* reliable sources. It may be that AGA chips are a temporary solution inbetween ECS and the new (AAA?) Superchips... I wonder if the low-end AAA chipset will be any more AGA compatible than the high-end? >The old Registers won't be changed. >Consequence: If Coders use the old (Normal & ECS) registers, >that are documented from Commodore, there are no probs with >the High-end chips. But if they use AA Registers, the new >AMIGA will propably CRASH. You have been warned! But what are the chances we get AAA hardware information. :-( >Probably publishing date of this AMIGA: Summer '93 (August). More likely early 1994. CBM won't release any new machines while AGA machines are still selling well.... > >Other facts:- The consumer price of the A4000 will turn under > $1200 in 1993! Not for the 68040 version. The A4000/030 (Amiga 4000 with 25Mhz 680EC30 chip) may reach $1500 or less. > - Kickstart 4.0 is finished! Yeah right :-) >The truth of this facts is nearly 100 %. Hmmmmm.... >Text from SMC of ABYSS >{written on 30.12.92} Commented by CJ on 2nd Jan 1993 31. Action Replay Cartridges ============================ These things are great fun, even more so if you get into the 'sysop mode' (Allows disassembly of ram areas not previously allowed by Action Replay, including non-autoconfig ram and the cartridge rom!) To get into sysop mode on Action Replay 1 type: LORD OLAF To get into sysop mode on Action Replay 2 type: MAY THE FORCE BE WITH YOU To get into sysop mode on Action Replay 3 type the same as Action Replay 2. After this you get a message "Try a new one". Then type in NEW and sysop powers are granted! Startup Code ============ I've seperated this out now, cut out this file and keep it safe (you may need a grown up to help you with this :-) 8<-------8<-------8<-------8<-------8<-------8<-------8<-------8<------- * * Startup.asm - A working tested version of startup from Howtocode3.txt * * CJ - 31/12/92 (Happy new year) [comradej@althera.demon.co.uk] * * This code sets up one of two copperlists (one for PAL and one for NTSC) * machines. It shows something to celebrate 3(?) years since the Berlin * wall came down :-) Press left mouse button to return to normality. * Tested on Amiga 3000 (ECS/V39 Kickstart) and Amiga 1200 (AGA/V39) * Read Howtocode3.txt for information on this source! * * $VER: startup.asm V2.0 With added fibre and no artificial preservatives * * opt l-,o+ ; auto link, optimise on ; opt o3- ; add this for Devpac Assembler section mycode,code ; need not be in chipram incdir "include:" include "exec/types.i" include "exec/funcdef.i" ; keep code simple and include "exec/exec_lib.i" ; easy to read - use include "graphics/gfxbase.i" ; the includes! include "graphics/graphics_lib.i" include "misc/easystart.i" ; Allows startup from ; icon StartCopper: move.l 4.w,a6 ; get ExecBase lea gfxname,a1 ; graphics name moveq #0,d0 ; any version jsr _LVOOpenLibrary(a6) tst.l d0 beq End ; failed to open? Then quit move.l d0,gfxbase move.l d0,a6 move.l gb_ActiView(a6),wbview ; store current view address ; gb_ActiView = 32 move.w #0,a1 ; clears full long-word jsr _LVOLoadView(a6) ; Flush View to nothing jsr _LVOWaitTOF(a6) ; Wait once jsr _LVOWaitTOF(a6) ; Wait again. move.w $dff07c,d0 cmp.b #$f8,d0 bne.s .notaga move.w #0,$dff1fc ; reset sprites (fix V39 bug) .notaga ; Now you can hit the copper! move.l 4.w,a6 jsr _LVOForbid(a6) ; Suspend multitasking! cmp.b #50,VBlankFrequency(a6) ; Am I *running* PAL? bne.s .ntsc move.l #mycopper,$dff080 ; bang it straight in. bra.s .lp .ntsc move.l #mycopperntsc,$dff080 .lp btst #6,$bfe001 bne.s .lp CloseDown: move.l 4.w,a6 jsr _LVOPermit(a6) ; Enable multitasking move.l wbview,a1 move.l gfxbase,a6 jsr _LVOLoadView(a6) ; Fix view move.l gb_copinit(a6),$dff080 ; Kick it into life ; copinit = 36 move.l a6,a1 move.l 4.w,a6 jsr _LVOCloseLibrary(a6) ; EVERYONE FORGETS THIS!!!! End: rts ; back to workbench/clc section mydata,data_c ; keep data & code seperate! mycopper dc.w $100,$0200 ; otherwise no display! dc.w $180,$00 dc.w $8107,$fffe ; wait for $8107,$fffe dc.w $180,$f00 ; background red dc.w $d607,$fffe ; wait for $d607,$fffe dc.w $180,$ff0 ; background yellow dc.w $ffff,$fffe dc.w $ffff,$fffe mycopperntsc dc.w $100,$0200 ; otherwise no display! dc.w $180,$00 dc.w $6e07,$fffe ; wait for $6e07,$fffe dc.w $180,$f00 ; background red dc.w $b007,$fffe ; wait for $b007,$fffe dc.w $180,$ff0 ; background yellow dc.w $ffff,$fffe dc.w $ffff,$fffe wbview dc.l 0 gfxbase dc.l 0 gfxname dc.b "graphics.library",0 Thanks to everyone who has replied. Any more questions, queries, or "CJ, you got it wrong again!" type mail to the email address below.... Thanks to: Vic Ricker, Grue, Timo Rossi, Jesse Michael, John Derek Muir, Boerge Noest, Christopher Klaus, Doz/Shining, Andrew Patterson, Walter Dao and Magnus Timmerby. Wanted! If you can write sections on the following, I'd be very greatful. Some of these I may do myself eventually.. Good optimisations (eg lea 16(a0),a1 instead of move.l a0,a1 add.l #16,a1) Simple 68881/882 programming introduction Bootblocks Any other short programming tips & tricks -------------------------------------------------------------------- This text is Copyright (C) 1993 Share and Enjoy, but may be freely distributed in any electronic form. The copyright of contributions quoted from other authors remains with the original author. If you would like to contribute to this file, email me at the address below... The startup code in this article is freeware and may be used by anyone for any purpose. All opinions expressed in this article are my own, and in no way reflect those of Share and Enjoy or any BBS this file may be found on. I didn't write this for fun, I wrote it for you to use! Hopefully this will grow into a big file that demo coders can use. If you strongly disagree with anything I write, or you want to send me some source or demos to test on Amiga 1200/4000 etc, or you have questions about Amiga programming, or suggestions for future articles, or just want to chat about the best way to optimise automatic copperlist generation code, then contact me via email at: comradej@althera.demon.co.uk, or in alt.sys.amiga.demos I'm having a few problems with sending email at the moment, so please be patient if you haven't received a reply. I will try to reply to every message within a day or two..