tschak909 Posted September 23, 2023 Author Share Posted September 23, 2023 I've done the first pass of disassembly doing annotation of code blocks, labels, and cross references, using the OS7 absolute listings, and other sources as cross reference. I have created a folder called sre/ in the GitHub repo: https://github.com/tschak909/os7lib/tree/main/sre It currently contains both an ASCII text output of the disassembly, along with a Ghidra ZIP file containing the entire project context. This can be imported with Ghidra: https://ghidra-sre.org/ Here is an example screenshot from function graph viewer on PUT_OBJ, you can see roughly a third of it, and it's a huge function, but it's now much easier to see the flow and relationships between each part of it. -Thom Quote Link to comment Share on other sites More sharing options...
tschak909 Posted September 23, 2023 Author Share Posted September 23, 2023 (edited) Currently looking through and annotating graphic objects. Here is a complex object structure representing two objects, with three frames. (edit: This is the compound for Donkey kong SMO for body, and sprite for face) -Thom Edited September 23, 2023 by tschak909 Quote Link to comment Share on other sites More sharing options...
Captain Cozmos Posted September 23, 2023 Share Posted September 23, 2023 (edited) UNK_B47C: DB 0F0H DB 1FH DB 18H DW DONKEY_KONG_PAT DW DONKEY_K_CENTER DW DONKEY_K_LEFT DW DONKEY_K_RIGHT DONKEY_K_CENTER: DB 006,004 DB 1FH, 20H, 21H, 22H, 23H, 1FH DB 24H, 25H, 26H, 27H, 28H, 29H DB 1FH, 2AH, 2BH, 2CH, 2DH, 1FH DB 2EH, 2FH, 30H, 31H, 32H, 33H DONKEY_K_LEFT: DB 006,004 DB 34H, 35H, 36H, 37H, 1FH, 1FH DB 38H, 39H, 3AH, 3BH, 1FH, 1FH DB 3CH, 3DH, 3EH, 3FH, 40H, 1FH DB 41H, 42H, 43H, 44H, 45H, 1FH DONKEY_K_RIGHT: DB 006,004 DB 7BH, 7BH, 93H, 92H, 91H, 90H DB 7BH, 7BH, 97H, 96H, 95H, 94H DB 7BH, 9CH, 9BH, 9AH, 99H, 98H DB 7BH,0A1H,0A0H, 9FH, 9EH, 9DH DW UNK_B4DB DW $7190 DB 0FFH DB 0BFH UNK_B4DB: DB 0F0H DB 5EH DB 8 DW FIRE_BARREL_PAT DW FIRE_BARREL DW FIRE_BARREL This is somewhere around where your working After I clean up a few things I will post my disassembly and then you can finish the pattern definitions from your research and merge the two works. I think somewhere along the line you can get a whole picture. I am finding both in Smurf and DK that there are parts that are important to the program but have no links to them outside of some Stack Pointer exchange. Another disturbing issue are the Pascal entry points in Smurf which seems to have been taken out of DK 24k when they created DK 16k. There are a couple of issues there and if I can resolve the missing data I can then remove all the PASCAL crap and have a cleaner Smurf. And everyone wants a cleaner Smurf just ask my wife. Edited September 23, 2023 by Captain Cozmos Quote Link to comment Share on other sites More sharing options...
tschak909 Posted September 23, 2023 Author Share Posted September 23, 2023 Spending today filling in object data from Donkey Kong (16K): Let's take a good look at Donkey Kong, which is, a complex object. Complex objects are made up of one or more SEMI-MOBILE or SPRITE objects (MOBILE objects can't be a part of complex objects, I can understand why COLECO did NOT want to open that Pandora's box of edge cases!). The composite object The face 16x16 sprite object: And Donkey Kong's body, which lives on the background layer: As you can see, This complex object comprises two child objects: COMPLEX_OBJECT_DONKEY_KONG XREF[1]: FUN_ram_8b1a:8c39(*) ram:b43d 45 b4 dw B445h COMPLEX OBJECT ram:b445 Graphics ram:b43f cd 71 dw 71CDh ram:71cd Status object ram:b441 64 b4 dw B464h ram:b464 1st Component ram:b443 76 b4 dw B476h ram:b476 2nd Component From the ColecoVision Programmer's Guide Rev 5 (this is all in Appendix B): The graphics object, and the two component child objects have addresses in ROM, while the status area (which governs the state of the object as a whole) is in RAM. There are two child objects, so the graphics object looks like this: DONKEY_KONG_GRAPHICS ram:b445 24 db 24h Complex Obj with 2 components ram:b446 52 b4 addr DONKEY_KONG_GRAPHICS_FRAME0 Now a list of pointers to each f with frame #s and pixel offsets ram:b448 58 b4 addr DONKEY_KONG_GRAPHICS_OFFSET0 ... ram:b44a 54 b4 addr DONKEY_KONG_GRAPHICS_FRAME1 ... ram:b44c 5c b4 addr DONKEY_KONG_GRAPHICS_OFFSET1 ... ram:b44e 56 b4 addr DONKEY_KONG_GRAPHICS_FRAME2 ... ram:b450 60 b4 addr DONKEY_JONG_GRAPHICS_OFFSET2 ...end of list The whole structure is explained here: Since we have two objects we're describing here, the MSN of OBJ_TYPE is 2, while the LSN is 4 (for complex object) This is followed by a list of pointers to FRAME and OFFSET tables. FRAME_X is simple, and simply a list of frame numbers for the child object, to use for the frame object of the parent. This is literally so that you can re-use frame objects for multiple frames, and potentially cut down on used ROM space. But in this case, there are separate frame objects for each individual child part. DONKEY_KONG_GRAPHICS_FRAME0 XREF[1]: ram:b446(*) ram:b452 00 db 0h component 0 uses frame 0 ram:b453 00 db 0h component 1 uses frame 0 DONKEY_KONG_GRAPHICS_FRAME1 XREF[1]: ram:b44a(*) ram:b454 01 db 1h component 0 uses frame 1 ram:b455 01 db 1h component 1 uses frame 1 DONKEY_KONG_GRAPHICS_FRAME2 XREF[1]: ram:b44e(*) ram:b456 02 db 2h component 0 uses frame 2 ram:b457 02 db 2h component 1 uses frame 2 OFFSET_X is is similar, just a linear list of X and Y offsets for each frame of the parent object, the X and Y positions are relative to the X and Y position of the parent. DONKEY_KONG_GRAPHICS_OFFSET0 XREF[1]: ram:b448(*) ram:b458 10 db 10h X offset frame 0 component 0 ram:b459 00 db 0h Y offset frame 0 component 0 ram:b45a 00 db 0h X offset frame 0 component 1 ram:b45b 00 db 0h Y offset frame 0 component 1 DONKEY_KONG_GRAPHICS_OFFSET1 XREF[1]: ram:b44c(*) ram:b45c 00 db 0h X offset frame 1 component 0 ram:b45d 00 db 0h Y offset frame 1 component 0 ram:b45e 00 db 0h X offset frame 1 component 1 ram:b45f 00 db 0h Y offset frame 1 component 1 DONKEY_JONG_GRAPHICS_OFFSET2 XREF[1]: ram:b450(*) ram:b460 20 db 20h X offset frame 2 component 0 ram:b461 00 db 0h Y offset frame 2 component 0 ram:b462 00 db 0h X offset frame 2 component 1 ram:b463 00 db 0h Y offset frame 2 component 1 Since the X and Y position of the face needs to change, depending on which frame is being displayed, component 0 has different offsets. Once the composite object and its frames and offsets have been defined, we need the object definition for each of the children: First, the head sprite, which needs to be a sprite,because it needs to be accurately positioned along single pixel boundaries: DONKEY_KONG_HEAD_SPRITE_OBJECT ram:b464 69 b4 addr DONKEY_KONG_HEAD_SPRITE_GRAPHICS ram:b469 GRAPHICS ram:b466 d4 71 char * DONKEY_KONG_HEAD_SPRITE_STATUS ram:71d4 STATUS ram:b468 0c db Ch START AT SPRITE INDEX 0x0C Sprite objects are defined as: Of note here is the SPRITE_INDEX, which specifies the sprite slot (0-31) to use for this particular sprite, in this case, it's 0x0C, or sprite #12, and sure enough, if we look at the sprite dump in the VDP, we see in the 13th slot: Which brings us to the GRAPHICS object: and in context: DONKEY_KONG_HEAD_SPRITE_GRAPHICS XREF[1]: ram:b464(*) ram:b469 03 db OBJ_TYPE_SPRITE ram:b46a b4 db B4h Donkey Kong's Face starts at spr ram:b46b b3 a6 addr DONKEY_KONG_HEAD_GENERATORS pointer to generator bitmaps ram:b46d 14 db DONKEY_KONG_HEAD_NUMGEN 20 ($14) generators used ram:b46e 70 b4 addr DONKEY_KONG_FRAME_TABLE pointer to frame table Note the B4h, which corresponds exactly to the corresponding tile in the SPRITE GENERATOR table. ACTIVATE will use this as the destination for where to start copying generator data from the generators field immediately below it, along with NUMGEN which specifies how many of said generators need to be copied. Since we are dealing with 16x16 sprites here, we need to copy a multiple of four generators for each and every frame of the sprite. Finally, we have a pointer to the frame table for each possible sprite state: and in context: DONKEY_KONG_FRAME_TABLE XREF[1]: ram:b46e(*) ram:b470 0f db WHITE_ON_TRANSPARENT ram:b471 00 db 0h $B4 straight ahead ram:b472 0f db WHITE_ON_TRANSPARENT ram:b473 04 db 4h $B8 facing left ram:b474 0f db WHITE_ON_TRANSPARENT ram:b475 08 db 8h $BC Facing right As we saw in the images above, Donkey Kong's face foreground is white, and it stays that way for all three frames. The background color is transparent, thus the byte 0FH. and if we look at the address for the generaators (A6B3, if you look at the listing bytes, or by double clicking DONKEY_KONG_HEAD_GENERATORS in Ghidra), we see: and if we look in this area with a binary pixel viewer, we see: Each bit of sprite information is stored sequentially, in the order the VDP needs it. This brings us to the SEMI-MOBILE object needed for the body. Since the body doesn't move that much, and it's very large, it's implemented as a semi-mobile object, which is basically a collection of background tiles, that get loaded into the PATTERN NAME TABLE via the ACTIVATE call. Because no image processing is done on these tiles when they are put onto the background, they must be positioned along tile (8 pixel) boundaries, which is fine here. The definition of the SMO object is as thus: And in context: DONKEY_KONG_BODY_SMO ram:b476 7c b4 addr DONKEY_KONG_BODY_GRAPHICS Donkey Kong Body Graphics ram:b478 b4 71 addr DONKEY_KONG_BODY_STATUS Donkey Kong Body Status ram:b47a ff bf addr NOT_USED Old Screen Data not used; disable. We see pointers to the GRAPHICS and STATUS objects, just like we did with the sprite object. But since the semi-mobile objects operate on the background, there is an additional field called OLD_SCREEN, which functions as a backing store, temporarily saving tiles that get overwritten by the object, and restoring them when the object moves or the frame changes. You can even choose to put this either in VRAM (faster) or in RAM, which is very clever IMHO. First, the SMO graphics object: And in Context: DONKEY_KONG_BODY_GRAPHICS XREF[1]: ram:b476(*) ram:b47c f0 db F0h OBJ TYPE 0 (SMO) appearing in al ram:b47d 1f db 1Fh FIRST GEN USED IS $1F ram:b47e 18 ?? 18h Kong body needs 24 ($18) gens in ram:b47f cb a8 addr DONKEY_JONG_BODY_GENERATORS Ptr to Kong Body Generators ram:b481 87 b4 addr DONKEY_KONG_BODY_FRAME0 Ptr to Donkey Kong Body Frame 0 ram:b483 a1 b4 addr DONKEY_KONG_BODY_FRAME1 Ptr to Donkey Kong Body Frame 1 ram:b485 bb b4 addr DONKEY_KONG_BODY_FRAME2 Ptr to Donkey Kong Body Frame 2 The object type, is F0, and if you read the note about the MSN for OBJ_TYPE above, you'll see that for mode 2 graphics, the upper three bits explicitly control which of the three M2 PATTERN GENERATORS to copy the tiles into, if you know that you're only going to be using the graphic on the upper third of the screen, you can set bit 7. They set all three of these bits here, so if we look at the PATTERN GENERATOR TABLES we see Donkey Kong's body copied, three times. Bit 4 is also set, which specifies that only one color generator per tile will be used, this puts the same foreground/background for each individual tile specified. 0x1F specifies the first generator that is used by this SEMI MOBILE OBJECT, the generators are copied from the DONKEY_KONG_BODY_GENERATORS in the cartridge rom to this position in the PATTERN GENERATORS table. NUMGEN specifies the number of 8x8 generator tiles to copy, in this case 24. This is followed by a pointer to the area in the cartridge ROM (or system RAM) that will hold the PATTERN GENERATORS to copy over. They are arranged sequentially, and up to the NUMGEN specified. And immediately after there are pointers to the individual FRAME objects, one for each frame needed. The FRAME objects are specified as: And in context: DONKEY_KONG_BODY_FRAME0 XREF[1]: ram:b481(*) ram:b487 06 db 6h Donkey Kong Body X extent for Fr ram:b488 04 db 4h Donkey Kong Body Y extent for Fr ram:b489 1f db 1Fh Generator for X 0 Y 0 ram:b48a 20 db 20h Generator for X 1 Y 0 ram:b48b 21 db 21h Generator for X 2 Y 0 ram:b48c 22 db 22h Generator for X 3 Y 0 ram:b48d 23 db 23h Generator for X 4 Y 0 ram:b48e 1f db 1Fh Generator for X 5 Y 0 ram:b48f 24 db 24h Generator for X 0 Y 1 ram:b490 25 db 25h Generator for X 1 Y 1 ram:b491 26 db 26h Generator for X 2 Y 1 ram:b492 27 db 27h Generator for X 3 Y 1 ram:b493 28 db 28h Generator for X 4 Y 1 ram:b494 29 db 29h Generator for X 5 Y 1 ram:b495 1f db 1Fh Generator for X 0 Y 2 ram:b496 2a db 2Ah Generator for X 1 Y 2 ram:b497 2b db 2Bh Generator for X 2 Y 2 ram:b498 2c db 2Ch Generator for X 3 Y 2 ram:b499 2d db 2Dh Generator for X 4 Y 2 ram:b49a 1f db 1Fh Generator for X 5 Y 2 ram:b49b 2e db 2Eh Generator for X 0 Y 3 ram:b49c 2f db 2Fh Generator for X 1 Y 3 ram:b49d 30 db 30h Generator for X 2 Y 3 ram:b49e 31 db 31h Generator for X 3 Y 3 ram:b49f 32 db 32h Generator for X 4 Y 3 ram:b4a0 33 db 33h Generator for X 5 Y 3 DONKEY_KONG_BODY_FRAME1 XREF[1]: ram:b483(*) ram:b4a1 06 db 6h Donkey Kong Body X Extent for Fr ram:b4a2 04 db 4h Donkey Kong Body Y Extent for Fr ram:b4a3 34 db 34h Generator for X 0 Y 0 ram:b4a4 35 db 35h Generator for X 1 Y 0 ram:b4a5 36 db 36h Generator for X 2 Y 0 ram:b4a6 37 db 37h Generator for X 3 Y 0 ram:b4a7 1f db 1Fh Generator for X 4 Y 0 ram:b4a8 1f db 1Fh Generator for X 5 Y 0 ram:b4a9 38 db 38h Generator for X 0 Y 1 ram:b4aa 39 db 39h Generator for X 1 Y 1 ram:b4ab 3a db 3Ah Generator for X 2 Y 1 ram:b4ac 3b db 3Bh Generator for X 3 Y 1 ram:b4ad 1f db 1Fh Generator for X 4 Y 1 ram:b4ae 1f db 1Fh Generator for X 5 Y 1 ram:b4af 3c db 3Ch Generator for X 0 Y 2 ram:b4b0 3d db 3Dh Generator for X 1 Y 2 ram:b4b1 3e db 3Eh Generator for X 2 Y 2 ram:b4b2 3f db 3Fh Generator for X 3 Y 2 ram:b4b3 40 db 40h Generator for X 4 Y 2 ram:b4b4 1f db 1Fh Generator for X 5 Y 2 ram:b4b5 41 db 41h Generator for X 0 Y 3 ram:b4b6 42 db 42h Generator for X 1 Y 3 ram:b4b7 43 db 43h Generator for X 2 Y 3 ram:b4b8 44 db 44h Generator for X 3 Y 3 ram:b4b9 45 db 45h Generator for X 4 Y 3 ram:b4ba 1f db 1Fh Generator for X 5 Y 3 DONKEY_KONG_BODY_FRAME2 XREF[1]: ram:b485(*) ram:b4bb 06 db 6h Donkey Kong Body X Extent for fr ram:b4bc 04 db 4h Donkey Kong Body Y Extent for fr ram:b4bd 7b db 7Bh Generator for X 0 Y 0 ram:b4be 7b db 7Bh Generator for X 1 Y 0 ram:b4bf 93 db 93h Generator for X 2 Y 0 ram:b4c0 92 db 92h Generator for X 3 Y 0 ram:b4c1 91 db 91h Generator for X 4 Y 0 ram:b4c2 90 db 90h Generator for X 5 Y 0 ram:b4c3 7b db 7Bh Generator for X 0 Y 1 ram:b4c4 7b db 7Bh Generator for X 1 Y 1 ram:b4c5 97 db 97h Generator for X 2 Y 1 ram:b4c6 96 db 96h Generator for X 3 Y 1 ram:b4c7 95 db 95h Generator for X 4 Y 1 ram:b4c8 94 db 94h Generator for X 5 Y 1 ram:b4c9 7b db 7Bh Generator for X 0 Y 2 ram:b4ca 9c db 9Ch Generator for X 1 Y 2 ram:b4cb 9b db 9Bh Generator for X 2 Y 2 ram:b4cc 9a db 9Ah Generator for X 3 Y 2 ram:b4cd 99 db 99h Generator for X 4 Y 2 ram:b4ce 98 db 98h Generator for X 5 Y 2 ram:b4cf 7b db 7Bh Generator for X 0 Y 3 ram:b4d0 a1 db A1h Generator for X 1 Y 3 ram:b4d1 a0 db A0h Generator for X 2 Y 3 ram:b4d2 9f db 9Fh Generator for X 3 Y 3 ram:b4d3 9e db 9Eh Generator for X 4 Y 3 ram:b4d4 9d db 9Dh Generator for X 5 Y 3 Each frame contains the X and Y extents for each frame, that is, the width and the height of the object for that frame, and this is followed by the names of each tile starting with 0,0 and ending with X_EXTENT and Y_EXTENT, going in row-order. If we look at the tiles, we see the left most pixels for DK's head I will finish, with one last note. I didn't go over the STATUS object, because while they are slightly different for each object, they contain the same basic information that the programmer can manipulate to change the position of an object, its frame, etc. Modifying the status object, and calling PUT_OBJ again, will cause the object to change appropriately. Whew, that was a lot, but I wanted to get this out there. More to come. -Thom 1 Quote Link to comment Share on other sites More sharing options...
Captain Cozmos Posted September 24, 2023 Share Posted September 24, 2023 If you had to put it in a particular format, this is the way I do it. DB 6, 4 corresponds to the actual frame 6 patterns across by 4 rows down This represents the entire body KONG_CENTER_FRAME_A: DB 6H,4H DB 1FH, 20H, 21H, 22H, 23H, 1FH DB 24H, 25H, 26H, 27H, 28H, 29H DB 1FH, 2AH, 2BH, 2CH, 2DH, 1FH DB 2EH, 2FH, 30H, 31H, 32H, 33H KONG_LEFT_FRAME_B: DB 6H,4H DB 34H, 35H, 36H, 37H, 1FH, 1FH DB 38H, 39H, 3AH, 3BH, 1FH, 1FH DB 3CH, 3DH, 3EH, 3FH, 40H, 1FH DB 41H, 42H, 43H, 44H, 45H, 1FH KONG_RIGHT_FRAME_C: DB 6H,4H DB 7BH, 7BH, 93H, 92H, 91H, 90H DB 7BH, 7BH, 97H, 96H, 95H, 94H DB 7BH, 9CH, 9BH, 9AH, 99H, 98H DB 7BH,0A1H,0A0H, 9FH, 9EH, 9DH Quote Link to comment Share on other sites More sharing options...
tschak909 Posted September 24, 2023 Author Share Posted September 24, 2023 (edited) 9 minutes ago, Captain Cozmos said: If you had to put it in a particular format, this is the way I do it. DB 6, 4 corresponds to the actual frame 6 patterns across by 4 rows down This represents the entire body KONG_CENTER_FRAME_A: DB 6H,4H DB 1FH, 20H, 21H, 22H, 23H, 1FH DB 24H, 25H, 26H, 27H, 28H, 29H DB 1FH, 2AH, 2BH, 2CH, 2DH, 1FH DB 2EH, 2FH, 30H, 31H, 32H, 33H KONG_LEFT_FRAME_B: DB 6H,4H DB 34H, 35H, 36H, 37H, 1FH, 1FH DB 38H, 39H, 3AH, 3BH, 1FH, 1FH DB 3CH, 3DH, 3EH, 3FH, 40H, 1FH DB 41H, 42H, 43H, 44H, 45H, 1FH KONG_RIGHT_FRAME_C: DB 6H,4H DB 7BH, 7BH, 93H, 92H, 91H, 90H DB 7BH, 7BH, 97H, 96H, 95H, 94H DB 7BH, 9CH, 9BH, 9AH, 99H, 98H DB 7BH,0A1H,0A0H, 9FH, 9EH, 9DH I don't agree. The way I have presented it above, is more understandable in context. ... hmm.. maybe, but.. i'm thinking... I wanted to deliberately point out in comments how each name is explicitly laid out. -Thom Edited September 24, 2023 by tschak909 Quote Link to comment Share on other sites More sharing options...
Captain Cozmos Posted September 24, 2023 Share Posted September 24, 2023 (edited) I look at it as the first constant 6 as 6 across so when it prints to vram into the name table as in 1,2,3,4,5,6 then for each of the second constant it would add 32 to get to the next row. 1,2,3,4,5,6 + 32 (1) 1,2,3,4,5,6 + 32 (2) 1,2,3,4,5,6 + 32 (3) 1,2,3,4,5,6 + 32 (4) In reality the math would look like OFFSET 23 (place in name table) + 1,2,3,4,5,6 + 32 ect.... 23 being a number I picked randomly it could be anything from 0 to 766 Being in Mode two, it would be 0-255 each third of the screen and the patterns/colors have to also be in the third being printed. Each pattern has to have all 8 lines each of it's on color. In mode I it is 0-766 and one set of patterns but each 8 patterns can have only one color to save VRAM for the design of the VDP I'm just ranting at this point. Edited September 24, 2023 by Captain Cozmos Quote Link to comment Share on other sites More sharing options...
tschak909 Posted September 24, 2023 Author Share Posted September 24, 2023 Just now, Captain Cozmos said: I look at it as the first constant 6 as 6 across so when it prints to vram into the name table as in 1,2,3,4,5,6 then for each of the second constant it would add 32 to get to the next row. 1,2,3,4,5,6 + 32 (1) 1,2,3,4,5,6 + 32 (2) 1,2,3,4,5,6 + 32 (3) 1,2,3,4,5,6 + 32 (4) In reality the math would look like OFFSET 23 (place in name table) + 1,2,3,4,5,6 + 32 ect.... 23 being a number I picked randomly it could be anything from 0 to 766 But being in Mode two, it would be 0-255 each third of the screen and the patterns/colors have to also be in the third being printed. Each pattern has to have all 8 lines each of it's on color. In mode I it is 0-766 and one set of patterns but each 8 patterns can have only one color to save VRAM for the design of the VDP I'm just ranting at this point. I know those moments. -Thom Quote Link to comment Share on other sites More sharing options...
Captain Cozmos Posted September 24, 2023 Share Posted September 24, 2023 (edited) An interesting note: This is what the Smurf Character is made up of SMURF_OBJECT: DW byte_A091 DW $7298 DW SMURF_TABLE_A DW SMURF_TABLE_B DW SMURF_TABLE_C DW SMURF_TABLE_D DB 44h Meaning this is a Complex Object made up of 4 animations hence the 44H High 4 (frames) and Low 4 (complex) The only thing making this a complex is that it is an animated sprite with no patterns attached. So one would assume that all animated sprites would fall under the complex designation. BTW, sent you a PM. Edited September 24, 2023 by Captain Cozmos Quote Link to comment Share on other sites More sharing options...
tschak909 Posted September 24, 2023 Author Share Posted September 24, 2023 I have added examples to OS7LIB for the four table-level transforms: * ROTATE_90 * REFLECT_VERTICAL * REFLECT_HORIZONTAL * ENLARGE (for each tile, make two of double size) They are in the examples folder: https://github.com/tschak909/os7lib/tree/main/examples Note: These are relatively self explanatory, with one note, VERTICAL and HORIZONTAL refer to the AXIS by which the rotation takes place, so they may behave opposite of what you might think. The interesting thing is that since these functions wrap GET and PUT_VRAM, they are table-aware, you can rotate, reflect, and enlarge the sprite and background pattern generators and name tables alike. With that said, it is your responsibility to order things so that they do come out right, especially in FRAME objects. I did the ENLARGE example to show how to use it with semi mobile objects, and the interleaving of tiles that you have to do, to re-order things so they appear correctly. You can see the order of tiles in the EnlargedFrame object in https://github.com/tschak909/os7lib/blob/main/examples/enlarge/src/enlarge.c#L163 It's important to note, that ALL of these calls are not only table-aware, they are mode-aware, especially in relation to generator placement, and preserving and transposing color table information. The amount of care taken here to do this is truly astounding. Furthermore, you can also see, precisely why ACTIVATE has a boolean option that determines whether generators are copied from ROM into the VDP RAM. It's not needed for the enlarged object, because the ENLARGE call does all the heavy lifting there, generating new tiles, we just need to fill in the objects with the appropriate generator numbers so that PUT_OBJ can display them (and ACTIVATE also does much needed initialization of the OLD SCREEN and STATUS objects) https://github.com/tschak909/os7lib/blob/main/examples/enlarge/src/enlarge.c#L259 In each of these cases, the WORK BUFFER specified at the top of the cartridge ROM is used to perform the transforms, before they are transferred to VRAM. e.g. for the rotate and reflect transforms, 8 bytes of the work buffer are used, while enlarge uses a minimum of 16 bytes, or more depending on the number of generators to transfer. Continuing onward. -Thom Quote Link to comment Share on other sites More sharing options...
tschak909 Posted September 26, 2023 Author Share Posted September 26, 2023 (edited) Am currently working through displaying Donkey Kong as a complex object, code here: https://github.com/tschak909/os7lib/tree/main/examples/complex_object But thus far, am running into interesting issues I Can get the face sprite to display, the body? not so much. Anyone have any potential insight here? It does seem that they did some very unusual tricks with the color table on the SMO, as there is seperate code to transfer color data, and the second frame of Donkey Kong's body is actually made of reflected sprites, thanks to REFLECT_VERTICAL. ************************************************************** * FUNCTION * ************************************************************** undefined FUN_ram_84a3() undefined A:1 <RETURN> FUN_ram_84a3 XREF[1]: ram:8069(c) ram:84a3 01 82 01 LD BC,0x182 ram:84a6 cd d9 1f CALL WRITE_REGISTER void WRITE_REGISTER(uchar regist ram:84a9 3e 03 LD A,PATTERN_GENERATOR_TABLE ram:84ab 21 d3 a7 LD HL,0xa7d3 ram:84ae cd 0f 99 CALL put_vram_256_starting_at undefined put_vram_256_starting_ ram:84b1 3e 04 LD A,PATTERN_COLOR_TABLE ram:84b3 21 ab ab LD HL,0xabab ram:84b6 cd 0f 99 CALL put_vram_256_starting_at undefined put_vram_256_starting_ ram:84b9 3e 01 LD A,SPRITE_GENERATOR_TABLE ram:84bb 21 13 a1 LD HL,0xa113 ram:84be 11 00 01 LD DE,0x100 ram:84c1 cd 1e 99 CALL COPY_GENERATORS_TO_VDP undefined COPY_GENERATORS_TO_VDP() ram:84c4 cd 99 84 CALL CLEAR_NAME_TABLE undefined CLEAR_NAME_TABLE() ram:84c7 3e 03 LD A,0x3 ram:84c9 11 1f 00 LD DE,0x1f ram:84cc 01 27 00 LD BC,0x27 ram:84cf 21 7b 00 LD HL,0x7b ram:84d2 cd 6a 1f CALL REFLECT_VERTICAL Reflect 39 Donkey kong body tiles from 0x1f, and place starting in ram:84d5 c3 35 97 JP TURN_ON_DISPLAY_WITH_SIZE1_SPRITES undefined TURN_ON_DISPLAY_WITH_S -- Flow Override: CALL_RETURN (CALL_TERMINATOR) Anyone have any potential insight on this? Has anyone been through this before? -Thom Edited September 26, 2023 by tschak909 Quote Link to comment Share on other sites More sharing options...
Kiwi Posted September 26, 2023 Share Posted September 26, 2023 1 hour ago, tschak909 said: But thus far, am running into interesting issues I Can get the face sprite to display, the body? not so much. When loading mass amount of graphics or generating graphics with vertical reflect, makes sure that the nmi(interrupt) is off. Seems like the color tables and tiles aren't loading completely. Quote Link to comment Share on other sites More sharing options...
tschak909 Posted September 26, 2023 Author Share Posted September 26, 2023 Ah yes. That is probably it! Thank you! -Thom Quote Link to comment Share on other sites More sharing options...
Kiwi Posted September 26, 2023 Share Posted September 26, 2023 11 minutes ago, tschak909 said: Ah yes. That is probably it! Thank you! -Thom No problem. nmi vram corruption is one of the pitfall when programming for the Colecovision. You can do small vram write(approxiately 200-300 bytes, depending on what function you're doing) when it is enabled, you have to do the task before the screen finished status flag goes up. Quote Link to comment Share on other sites More sharing options...
tschak909 Posted September 26, 2023 Author Share Posted September 26, 2023 (edited) 12 minutes ago, Kiwi said: No problem. nmi vram corruption is one of the pitfall when programming for the Colecovision. You can do small vram write(approxiately 200-300 bytes, depending on what function you're doing) when it is enabled, you have to do the task before the screen finished status flag goes up. This is one of the reasons there is a WRITER function, which literally handles deferred writes during the NMI. I'm trying to create examples to show how all of this is used. From section 4 -Thom Edited September 26, 2023 by tschak909 1 Quote Link to comment Share on other sites More sharing options...
Captain Cozmos Posted September 26, 2023 Share Posted September 26, 2023 (edited) I can not say for definite what the issue is. However, I have noticed that if you do not initiate everything through the appropriate commands, patterns do not work. Sprites are a different entity. The PutOBJ command and the like do not function. A ways back I tried to use examples in Tony Cruise's book and they would not work unless I called MODE1 or some deal like that first. A lot of things he forgets to mention or just did not occur. Most of the time VRAM is divided up as Patterns start at $0000, Color at $2000, Name table at $1800, Sprites at $3000 and Sprite attributes at $1B00 While that is the case, a game such as Smurf Rescue uses a much larger pattern setup and starts at $2000 while Color starts at $0000 I suspect because you are using the entire playfield as a blank screen and a different set of patterns for each of the 1/3rd screen. While the latter is standard mode 2 where each of the 3rd area's are replicated. Sprite addresses can change but I have yet to find a game that has. They always use $3000 and $1B00 and will work on any screen other than text mode. So, bringing that long story short, setting up manually may just have your patterns going to the wrong address because those commands are dependent on the previous tables being set up correctly. I have disassembled a few of these games that will setup all the tables using MODE1 then change aspects of VRAM with Write Register after. Edited September 26, 2023 by Captain Cozmos Quote Link to comment Share on other sites More sharing options...
tschak909 Posted September 26, 2023 Author Share Posted September 26, 2023 2 hours ago, Captain Cozmos said: I can not say for definite what the issue is. However, I have noticed that if you do not initiate everything through the appropriate commands, patterns do not work. Sprites are a different entity. The PutOBJ command and the like do not function. A ways back I tried to use examples in Tony Cruise's book and they would not work unless I called MODE1 or some deal like that first. A lot of things he forgets to mention or just did not occur. Most of the time VRAM is divided up as Patterns start at $0000, Color at $2000, Name table at $1800, Sprites at $3000 and Sprite attributes at $1B00 While that is the case, a game such as Smurf Rescue uses a much larger pattern setup and starts at $2000 while Color starts at $0000 I suspect because you are using the entire playfield as a blank screen and a different set of patterns for each of the 1/3rd screen. While the latter is standard mode 2 where each of the 3rd area's are replicated. Sprite addresses can change but I have yet to find a game that has. They always use $3000 and $1B00 and will work on any screen other than text mode. So, bringing that long story short, setting up manually may just have your patterns going to the wrong address because those commands are dependent on the previous tables being set up correctly. I have disassembled a few of these games that will setup all the tables using MODE1 then change aspects of VRAM with Write Register after. I do exactly the same pattern: in: https://github.com/tschak909/os7lib/blob/main/examples/complex_object/src/complex_object.c#L56 mode2_with_size1_sprites(false); // Set up, but keep screen BLANK Which does this: https://github.com/tschak909/os7lib/blob/main/examples/complex_object/src/complex_object.c#L35 void mode2_with_size1_sprites(bool bOnOff) { mode_1(); write_register(0x00,2); // SET M2 write_register(0x01,bOnOff ? 0xE2 : 0xC2); // BLANK(bOnOff), 16K, INTERRUPTS } -Thom Quote Link to comment Share on other sites More sharing options...
Captain Cozmos Posted September 26, 2023 Share Posted September 26, 2023 (edited) This is how I set up mode 2 If I use it this way I can follow directly from the TI TMS9928 manual by changing the bits per example in the book. GRAPHICS_MODE: DI LD C, CTRL_PORT LD B, 10H LD HL, MODE_REGISTERS OTIR MODE_REGISTERS: DB %00000010, 128+0 ; MODE REGISTER #0 ; bit 6 controls which mode, bit 7 is for external video DB %11000010, 128+1 ; MODE REGISTER #1 ; bit 6 is for 8x8 or 16x16 sprites, bit 7 is enlarge sprites DB %00000110, 128+2 ; NAME TABLE DB %11111111, 128+3 ; COLOR TABLE DB %00000011, 128+4 ; PATTERN TABLE DB %00110110, 128+5 ; SPRITES ATTRIBUTES DB %00000111, 128+6 ; SPRITES PATTERNS DB %00000000, 128+7 ; BACKGROUND COLOR MODE 1 would be the same except for DB %00000000, 128+0 ; MODE REGISTER #0 To ENLARGE sprites you change bit 7 of register 1 DB %11000011, 128+1 ; MODE REGISTER #1 I can't work with all that C gibberish. Edited September 26, 2023 by Captain Cozmos Quote Link to comment Share on other sites More sharing options...
tschak909 Posted September 26, 2023 Author Share Posted September 26, 2023 2 minutes ago, Captain Cozmos said: This is how I set up mode 2 If I use it this way I can follow directly from the TI TMS9928 manual by changing the bits per example in the book. GRAPHICS_MODE: DI LD C, CTRL_PORT LD B, 10H LD HL, MODE_REGISTERS OTIR MODE_REGISTERS: DB %00000010, 128+0 ; MODE REGISTER #0 ; bit 6 controls which mode, bit 7 is for external video DB %11000010, 128+1 ; MODE REGISTER #1 ; bit 6 is for 8x8 or 16x16 sprites, bit 7 is enlarge sprites DB %00000110, 128+2 ; NAME TABLE DB %11111111, 128+3 ; COLOR TABLE DB %00000011, 128+4 ; PATTERN TABLE DB %00110110, 128+5 ; SPRITES ATTRIBUTES DB %00000111, 128+6 ; SPRITES PATTERNS DB %00000000, 128+7 ; BACKGROUND COLOR MODE 1 would be the same except for DB %00000000, 128+0 ; MODE REGISTER #0 To ENLARGE sprites you change bit 7 of register 1 DB %11000011, 128+1 ; MODE REGISTER #1 I can't work with all that C gibberish. you mean to tell me you literally can't read: write_register(0x01,0xC2) ? .... ... ok. -Thom Quote Link to comment Share on other sites More sharing options...
Captain Cozmos Posted September 26, 2023 Share Posted September 26, 2023 1 minute ago, tschak909 said: you mean to tell me you literally can't read: write_register(0x01,0xC2) ? .... ... ok. -Thom That's long hand. I am a simple, yet humble man. In reality, when I am working on a game and go to bed I am thinking in assembly language to the point I have to get back up and write it down. I took C, Pascal and Cobol when I first went to college then ADA, Lisp and Forth shortly after. I'm happy with Z80, 6801 and 68000 assembly. But yes, I can follow your work. I just don't want to deviate from what I am proficient at in my latter days of existence. Quote Link to comment Share on other sites More sharing options...
tschak909 Posted September 26, 2023 Author Share Posted September 26, 2023 27 minutes ago, Captain Cozmos said: That's long hand. I am a simple, yet humble man. In reality, when I am working on a game and go to bed I am thinking in assembly language to the point I have to get back up and write it down. I took C, Pascal and Cobol when I first went to college then ADA, Lisp and Forth shortly after. I'm happy with Z80, 6801 and 68000 assembly. But yes, I can follow your work. I just don't want to deviate from what I am proficient at in my latter days of existence. fair enough. -Thom Quote Link to comment Share on other sites More sharing options...
tschak909 Posted September 26, 2023 Author Share Posted September 26, 2023 Still working through getting the semi-mobile objects displayed correctly. Scratching my head, because: * The graphic generators are being copied correctly to 0x1f - 0x45 * The color generators are being copied to the same place in the color table (starting at 0x20F8) and I've verified the tiles are indeed 0x1f to 0x45 that make up donkey kong, and on the name table but the color values are being pulled from 0x2000 (color for generator 0x00), what the hell?! Rom is attached As is video showing condition 2023-09-26 13-40-12.mp4 -Thom complex_object.rom Quote Link to comment Share on other sites More sharing options...
Captain Cozmos Posted September 26, 2023 Share Posted September 26, 2023 (edited) This is the VRAM init for the 16k DK version SETUP_VRAM: CALL SUB_9A5E LD A, 0D0H LD B, 48H ; 'H' LD HL, (OFF_8004) CALL SUB_97FA LD A, 0 LD DE, 0 LD IY, 12H CALL PUT_VRAM LD A, 10H CALL INIT_SPR_NM_TBL CALL RESET_SCORES LD BC, 2 CALL WRITE_REGISTER LD BC, 700H CALL WRITE_REGISTER LD A, 0 LD HL, 1C00H CALL INIT_TABLE LD A, 1 LD HL, 3800H CALL INIT_TABLE LD A, 2 LD HL, 1800H CALL INIT_TABLE LD A, 3 LD HL, 2000H CALL INIT_TABLE LD A, 4 LD HL, 0 CALL INIT_TABLE JP DISABLE_NMI ; END OF FUNCTION SETUP_VRAM Edited September 26, 2023 by Captain Cozmos Quote Link to comment Share on other sites More sharing options...
tschak909 Posted September 26, 2023 Author Share Posted September 26, 2023 16k. Quote Link to comment Share on other sites More sharing options...
Captain Cozmos Posted September 26, 2023 Share Posted September 26, 2023 1 minute ago, tschak909 said: 16k. check my edit Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.