/* copdis - standalone copper list disassembler * * by Karl Lehenbauer, April 1989 * * This code is released to the public domain for any legal use. * * This is free software. No warranties are expressed or implied. * * * There should be a text file, copdis.doc, that describes the function * of the program in greater detail. If you don't have it, you've been * ripped off! * * A quick summary: to disassemble a copper list, call copdis and pass it * the address of the start of the copper list. Note that this is not * the address of the cprlst or CopList data structure, but the actual * address of the first copper instruction. * * Some examples: * * GfxBase's copinit list, this may not be right * copdis(GfxBase->copinit); * * Top Viewport's display instructions for the "long frame" * copdis(GfxBase->ActiView->ViewPort->DspIns->CopLStart); * * Top Viewport's display instructions for the "short frame" * copdis(GfxBase->ActiView->ViewPort->DspIns->CopSStart); * * Currently active LOF copper list * copdis(GfxBase->ActiView->LOFCprList->start); * * Currently active SHF copper list: * copdis(GfxBase->ActiView->SHFCprList->start); * */ #include #include struct copregstruct { char *regname; char *longname; short regid; short flags; }; struct copinstruction { short ir1; short ir2; }; #define COLOR 1 static struct copregstruct copregisters[] = { {"bltddat","blitter destination early read (dummy address)",0,0}, {"dmaconr","DMA control (and blitter status) read",0x2,0}, {"vposr","read vert most signif. bit (and frame flop)",0x4,0}, {"vhposr","read vert and horiz. position of beam",0x6,0}, {"dskdatr","disk data early read (dummy address)",0x8,0}, {"joy0dat","joystick-mouse 0 data (vert,horiz)",0xa,0}, {"joy1dat","joystick-mouse 1 data (vert,horiz)",0xc,0}, {"clxdat","collision data (read and clear)",0xe,0}, {"adkconr","audio, disk control register read",0x10,0}, {"pot0dat","pot counter pair 0 data (vert,horiz)",0x12,0}, {"pot1dat","pot counter pair 1 data (vert,horiz)",0x14,0}, {"potgor","pot port data read",0x16,0}, {"serdatr","serial port data and status read",0x18,0}, {"dskbytr","disk data byte and status read",0x1a,0}, {"intenar","interrupt enable bits read",0x1c,0}, {"intreqr","interrupt request bits read",0x1e,0}, {"dskpth","disk pointer (high 3 bits)",0x20,0}, {"dskptl","disk pointer (low 15 bits)",0x22,0}, {"dsklen","disk length",0x24,0}, {"dskdat","disk DMA data write",0x26,0}, {"refptr","refresh pointer",0x28,0}, {"vposw","write vert most signif. bit (and frame flop)",0x2a,0}, {"vhposw","write vert and horiz position of beam",0x2c,0}, {"copcon","copper control register (CDANG)",0x2e,0}, {"serdat","serial port data and stop bits write",0x30,0}, {"serper","serial port period and control",0x32,0}, {"potgo","pot port data write and start",0x34,0}, {"joytest","write all four joystick-mouse counters",0x36,0}, {"strequ","strobe for horiz sync with vertical blank and EQU",0x38,0}, {"strvbl","strobe for horiz sync with vertical blank",0x3a,0}, {"strhor","strobe for horizontal sync",0x3c,0}, {"strlong","strobe for identification of long horiz. line",0x3e,0}, {"bltcon0","blitter control register 0",0x40,0}, {"bltcon1","blitter control register 1",0x42,0}, {"bltafwm","blitter first word mask for source A",0x44,0}, {"bltalwm","blitter last word mask for source A",0x46,0}, {"bltcpth","blitter pointer to source C (high 3 bits)",0x48,0}, {"bltcptl","blitter pointer to source C (low 15 bits)",0x4a,0}, {"bltbpth","blitter pointer to source B (high 3 bits)",0x4c,0}, {"bltbptl","blitter pointer to source B (low 15 bits)",0x4e,0}, {"bltapth","blitter pointer to source A (high 3 bits)",0x50,0}, {"bltaptl","blitter pointer to source A (low 15 bits)",0x52,0}, {"bltdpth","blitter pointer to source D (high 3 bits)",0x54,0}, {"bltdptl","blitter pointer to source D (low 15 bits)",0x56,0}, {"bltsize","blitter start and size (window width, height)",0x58,0}, {"bltcmod","blitter modulo for source C",0x60,0}, {"bltbmod","blitter modulo for source B",0x62,0}, {"bltamod","blitter modulo for source A",0x64,0}, {"bltdmod","blitter modulo for source D",0x66,0}, {"bltcdat","blitter source C data",0x70,0}, {"bltbdat","blitter source B data",0x72,0}, {"bltadat","blitter source A data",0x74,0}, {"dsksync","disk sync pattern for disk read",0x7e,0}, {"cop1lch","copper first location (high 3 bits)",0x80,0}, {"cop1lcl","copper first location (low 15 bits)",0x82,0}, {"cop2lch","copper second location (high 3 bits)",0x84,0}, {"cop2lcl","copper second location (low 15 bits)",0x86,0}, {"copjmp1","restart copper at first location",0x88,0}, {"copjmp2","restart copper at second location",0x8a,0}, {"copins","copper instruction fetch identify",0x8c,0}, {"diwstrt","display window start (upper left vert-horiz position)",0x8e,0}, {"diwstop","display window stop (lower right vert-horiz position)",0x90,0}, {"ddfstrt","display bit plane data fetch start (horiz. position)",0x92,0}, {"ddfstop","display bit plane data fetch stop (horiz. position)",0x94,0}, {"dmacon","DMA control write (clear or set)",0x96,0}, {"clxcon","collision control",0x98,0}, {"intena","interrupt enable bits",0x9a,0}, {"intreq","interrupt request bits",0x9c,0}, {"adkcon","audio, disk, UART control",0x9e,0}, {"aud0lch","audio channel 0 location (high 3 bits)",0xa0,0}, {"aud0lcl","audio channel 0 location (low 15 bits)",0xa2,0}, {"aud0len","audio channel 0 length",0xa4,0}, {"aud0per","audio channel 0 period",0xa6,0}, {"aud0vol","audio channel 0 volume",0xa8,0}, {"aud0dat","audio channel 0 data",0xaa,0}, {"aud1lch","audio channel 1 location (high 3 bits)",0xb0,0}, {"aud1lcl","audio channel 1 location (low 15 bits)",0xb2,0}, {"aud1len","audio channel 1 length",0xb4,0}, {"aud1per","audio channel 1 period",0xb6,0}, {"aud1vol","audio channel 1 volume",0xb8,0}, {"aud1dat","audio channel 1 data",0xba,0}, {"aud2lch","audio channel 2 location (high 3 bits)",0xc0,0}, {"aud2lcl","audio channel 2 location (low 15 bits)",0xc2,0}, {"aud2len","audio channel 2 length",0xc4,0}, {"aud2per","audio channel 2 period",0xc6,0}, {"aud2vol","audio channel 2 volume",0xc8,0}, {"aud2dat","audio channel 2 data",0xca,0}, {"aud3lch","audio channel 3 location (high 3 bits)",0xd0,0}, {"aud3lcl","audio channel 3 location (low 15 bits)",0xd2,0}, {"aud3len","audio channel 3 length",0xd4,0}, {"aud3per","audio channel 3 period",0xd6,0}, {"aud3vol","audio channel 3 volume",0xd8,0}, {"aud3dat","audio channel 3 data",0xda,0}, {"bpl1pth","blitter plane 1 pointer (high 3 bits)",0xe0,0}, {"bpl1ptl","blitter plane 1 pointer (low 15 bits)",0xe2,0}, {"bpl2pth","blitter plane 2 pointer (high 3 bits)",0xe4,0}, {"bpl2ptl","blitter plane 2 pointer (low 15 bits)",0xe6,0}, {"bpl3pth","blitter plane 3 pointer (high 3 bits)",0xe8,0}, {"bpl3ptl","blitter plane 3 pointer (low 15 bits)",0xea,0}, {"bpl4pth","blitter plane 4 pointer (high 3 bits)",0xec,0}, {"bpl4ptl","blitter plane 4 pointer (low 15 bits)",0xee,0}, {"bpl5pth","blitter plane 5 pointer (high 3 bits)",0xf0,0}, {"bpl5ptl","blitter plane 5 pointer (low 15 bits)",0xf2,0}, {"bpl6pth","blitter plane 6 pointer (high 3 bits)",0xf4,0}, {"bpl6ptl","blitter plane 6 pointer (low 15 bits)",0xf6,0}, {"bplcon0","bit plane control bits",0x100,0}, {"bplcon1","bit plane scroll values for PF1 & PF2",0x102,0}, {"bplcon2","bit plane priority control",0x104,0}, {"bpl1mod","bit plane modulo for odd planes",0x108,0}, {"bpl2mod","bit plane modulo for even planes",0x10a,0}, {"bpl1dat","bit plane 1 data (parallel-to-serial convert)",0x110,0}, {"bpl2dat","bit plane 2 data (parallel-to-serial convert)",0x112,0}, {"bpl3dat","bit plane 3 data (parallel-to-serial convert)",0x114,0}, {"bpl4dat","bit plane 4 data (parallel-to-serial convert)",0x116,0}, {"bpl5dat","bit plane 5 data (parallel-to-serial convert)",0x118,0}, {"bpl6dat","bit plane 6 data (parallel-to-serial convert)",0x11a,0}, {"spr0pth","sprite 0 pointer (high 3 bits)",0x120,0}, {"spr0ptl","sprite 0 pointer (low 15 bits)",0x122,0}, {"spr1pth","sprite 1 pointer (high 3 bits)",0x124,0}, {"spr1ptl","sprite 1 pointer (low 15 bits)",0x126,0}, {"spr2pth","sprite 2 pointer (high 3 bits)",0x128,0}, {"spr2ptl","sprite 2 pointer (low 15 bits)",0x12a,0}, {"spr3pth","sprite 3 pointer (high 3 bits)",0x12c,0}, {"spr3ptl","sprite 3 pointer (low 15 bits)",0x12e,0}, {"spr4pth","sprite 4 pointer (high 3 bits)",0x130,0}, {"spr4ptl","sprite 4 pointer (low 15 bits)",0x132,0}, {"spr5pth","sprite 5 pointer (high 3 bits)",0x134,0}, {"spr5ptl","sprite 5 pointer (low 15 bits)",0x136,0}, {"spr6pth","sprite 6 pointer (high 3 bits)",0x138,0}, {"spr6ptl","sprite 6 pointer (low 15 bits)",0x13a,0}, {"spr7pth","sprite 7 pointer (high 3 bits)",0x13c,0}, {"spr7ptl","sprite 7 pointer (low 15 bits)",0x13e,0}, {"spr0pos","sprite 0 vert-horiz start position",0x140,0}, {"spr0ctl","sprite 0 vert stop position and control data",0x142,0}, {"spr0data","sprite 0 image data register A",0x144,0}, {"spr0datb","sprite 0 image data register B",0x146,0}, {"spr1pos","sprite 1 vert-horiz start position",0x148,0}, {"spr1ctl","sprite 1 vert stop position and control data",0x14a,0}, {"spr1data","sprite 1 image data register A",0x14c,0}, {"spr1datb","sprite 1 image data register B",0x14e,0}, {"spr2pos","sprite 2 vert-horiz start position",0x150,0}, {"spr2ctl","sprite 2 vert stop position and control data",0x152,0}, {"spr2data","sprite 2 image data register A",0x154,0}, {"spr2datb","sprite 2 image data register B",0x156,0}, {"spr3pos","sprite 3 vert-horiz start position",0x158,0}, {"spr3ctl","sprite 3 vert stop position and control data",0x15a,0}, {"spr3data","sprite 3 image data register A",0x15c,0}, {"spr3datb","sprite 3 image data register B",0x15e,0}, {"spr4pos","sprite 4 vert-horiz start position",0x160,0}, {"spr4ctl","sprite 4 vert stop position and control data",0x162,0}, {"spr4data","sprite 4 image data register A",0x164,0}, {"spr4datb","sprite 4 image data register B",0x166,0}, {"spr5pos","sprite 5 vert-horiz start position",0x168,0}, {"spr5ctl","sprite 5 vert stop position and control data",0x16a,0}, {"spr5data","sprite 5 image data register A",0x16c,0}, {"spr5datb","sprite 5 image data register B",0x16e,0}, {"spr6pos","sprite 6 vert-horiz start position",0x170,0}, {"spr6ctl","sprite 6 vert stop position and control data",0x172,0}, {"spr6data","sprite 6 image data register A",0x174,0}, {"spr6datb","sprite 6 image data register B",0x176,0}, {"spr7pos","sprite 7 vert-horiz start position",0x178,0}, {"spr7ctl","sprite 7 vert stop position and control data",0x17a,0}, {"spr7data","sprite 7 image data register A",0x17c,0}, {"spr7datb","sprite 7 image data register B",0x17e,0}, {"color0","",0x180,COLOR}, {"color1","",0x182,COLOR}, {"color2","",0x184,COLOR}, {"color3","",0x186,COLOR}, {"color4","",0x188,COLOR}, {"color5","",0x18a,COLOR}, {"color6","",0x18c,COLOR}, {"color7","",0x18e,COLOR}, {"color8","",0x190,COLOR}, {"color9","",0x192,COLOR}, {"color10","",0x194,COLOR}, {"color11","",0x196,COLOR}, {"color12","",0x198,COLOR}, {"color13","",0x19a,COLOR}, {"color14","",0x19c,COLOR}, {"color15","",0x19e,COLOR}, {"color16","",0x1a0,COLOR}, {"color17","",0x1a2,COLOR}, {"color18","",0x1a4,COLOR}, {"color19","",0x1a6,COLOR}, {"color20","",0x1a8,COLOR}, {"color21","",0x1aa,COLOR}, {"color22","",0x1ac,COLOR}, {"color23","",0x1ae,COLOR}, {"color24","",0x1b0,COLOR}, {"color25","",0x1b2,COLOR}, {"color26","",0x1b4,COLOR}, {"color27","",0x1b6,COLOR}, {"color28","",0x1b8,COLOR}, {"color29","",0x1ba,COLOR}, {"color30","",0x1bc,COLOR}, {"color31","",0x1be,COLOR}, {"","",-1,0} }; struct copregstruct *find_copper_register_info(reg) int reg; { struct copregstruct *regp; for (regp = &copregisters[0]; regp->regid != -1; regp++) { if (regp->regid == reg) return(regp); } return(0); } disassemble_copper_instruction(ip) struct copinstruction *ip; { short vp, hp, ve, he, bfd; int registerid; struct copregstruct *regp; char *regtext, *longtext; /* printf("instruction %x, %x\n",ip->ir1,ip->ir2); */ /* true if it's a branch or skip instruction */ if (ip->ir1 & 1) { /* branch or skip instruction */ /* calculate vertical and horizontal position */ vp = (ip->ir1 >> 8) & 0xff; hp = (ip->ir1 >> 1) & 0x7f; /* calculate vertical and horizontal position compare bits * and blitter-finished-disable bit */ ve = (ip->ir2 >> 8) & 0x7f; he = (ip->ir2 >> 1) & 0x7f; bfd = (ip->ir2 & 0x8000); /* print the instruction type, check bit 0 of second word */ if (ip->ir2 & 1) { /* it's a skip */ printf("\tskip"); } else { /* it's a wait */ printf("\twait"); } /* reverse sense of blitter finish wait disable to show blitter * finish wait -- that way we occasionally say "blitter" instead * of almost always saying "no blitter" */ if (!bfd) printf("\tbf,"); else printf("\t"); /* print vertical and horizontal position */ printf("vpos=%d,hpos=%d",vp,hp); printf("instruction %x, %x\n",ip->ir1,ip->ir2); /* if enable masks are not basically "all", print them */ if ((ve != 0x7f) || (he != 0x7f)) { printf(",vcomp=%d,hcomp=%d\n",ve,he); } } else { /* it's a move instruction */ /* calculate register ID and look it up */ registerid = ip->ir1 & 0x1ff; regp = find_copper_register_info(registerid); /* if we found the register in our table, print the text * else whine about something we don't understand */ if (regp) { regtext = regp->regname; longtext = regp->longname; } else { regtext = "UNKNOWN_OPCODE"; longtext = ""; } printf("\tmove\t%x,%s",ip->ir2,regtext); if (*longtext != '\0') printf("\t;%s",longtext); } printf("\n"); } /* have a go at disassembling a copper list */ copdis(coplist) struct copinstruction *coplist; { /* check and refuse null list pointers */ if (coplist == (struct copinstruction *)NULL) { fprintf(stderr,"copdis: copper list pointer is null\n"); return; } /* while we don't have an instruction of 0xffff 0xfffe, which is * a de facto END PROGRAM instruction, print instructions. * * Use of do-while is in order that the END instruction is also * disassembled. * * This should really have a sanity check (like no more than a few * hundred instructions, and/or a length -- heck, it's in the cprlst * and CopList structures anyway), but it doesn't, or at least not * yet */ do { disassemble_copper_instruction(coplist++); } while ((coplist->ir1 != 0xffff) && (coplist->ir2 != 0xfffe)); /* and disassemble the WAIT 255 instruction */ disassemble_copper_instruction(coplist); }