Yaron Nir Posted March 23, 2019 Share Posted March 23, 2019 (edited) the assumption is you already know what a display list is and how it is created and maintained in A8. Just wanted to share, Here is a code sample on how to use CC65 and its strong A8 capabilities to define a display list in just few simple steps: Step 1: define the screen memory and display list fixed addresses #define ScreenMemory 0x3000 #define DisplayListMemory 0x5000 in this example, the screen memory address is fixed and set to 0x3000 In this example, the display list memory address is fixed and set to 0x5000 Step 2: define the display list void DisplayList = { DL_BLK8, DL_BLK8, DL_BLK4, DL_LMS(DL_CHR40x8x4), ScreenMemory, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_CHR40x8x4, DL_JVB, DisplayListMemory, DL_JMP }; The display list above is pretty basic, it is Antic mode 4 (characters mode). in line 5 it refers the screen memory address which we have defined in step 1 Step 3: copy the display list into the fixed memory address memcpy((void*) DisplayListMemory,&DisplayList,sizeof(DisplayList)); Step 4: tell ANTIC what memory address holds the display list and we're done OS.sdlst = (void*)DisplayListMemory; the sdlst points to the known memory location 560 and 561 (0x230, 0x231). Hope this was helpful to anyone. cheers, Yaron Edited March 23, 2019 by Yaron Nir Quote Link to comment Share on other sites More sharing options...
Wrathchild Posted March 23, 2019 Share Posted March 23, 2019 Possibly a few issues with this? The 'void' declaration should probably be 'unsigned char' / 'uint8_t' void DisplayList = When 'ScreenMemory' is used this should be broken into low and high bytes. <ScreenMemory, >ScreenMemory, The ending of the instruction list doesn't make sense DL_JVB, DL_JMP a JVB would be followed by the start address of a Dlist so should this have been DL_JVB, <DisplayListMemory, >DisplayListMemory Quote Link to comment Share on other sites More sharing options...
Yaron Nir Posted March 23, 2019 Author Share Posted March 23, 2019 Wrathchild, i've edited the post as i noticed it was missing at the end the display list memory address to jump to. as for your comments: The 'void' declaration should probably be 'unsigned char' / 'uint8_t' well, could be, but i can void also can be used. The ending of the instruction list doesn't make sense DL_JVB, DL_JMP yes, fixed. Quote Link to comment Share on other sites More sharing options...
Yaron Nir Posted March 23, 2019 Author Share Posted March 23, 2019 actually, come to think of it, in this support, i am not sure display list address is needed after the JVB, Quote Link to comment Share on other sites More sharing options...
Wrathchild Posted March 23, 2019 Share Posted March 23, 2019 (edited) Do you understand what the difference between DL_JVB & DL_JMP is? Take a look at the basic dlist: Edited March 23, 2019 by Wrathchild Quote Link to comment Share on other sites More sharing options...
Yaron Nir Posted March 23, 2019 Author Share Posted March 23, 2019 of course, one is wait on VBLANK and one is jumping back to DL mem address to loop over again. listen,all i am saying that in the CC65 of this currect display list implementation it is done for you behind the scenes that you don't have to specify it explicirly in the code. i've seen many examples that the addresses were left out.... Quote Link to comment Share on other sites More sharing options...
Wrathchild Posted March 23, 2019 Share Posted March 23, 2019 DL_JVB isn't solely to wait for a vblank, it also sets the internal dlist pointer to the operand (next two bytes). Similarly, DL_JMP is a direct instruction to reload the internal pointer with a new address. Hence the DL_JMP left in at the end of your display list is redundant as it would never be reached as the JVB effectively restarts the dlist. DL_JMPs are rarely used, e.g. a dlist shouldn't span a 1K page boundary and so a jump can be used to handle this, but it can be, say, in the case of a display list that has a fixed header area and the lower content can be redirected based on the game state. Quote Link to comment Share on other sites More sharing options...
Wrathchild Posted March 23, 2019 Share Posted March 23, 2019 i've seen many examples that the addresses were left out.... Granted, a JVB on its own can work, however this is a side-effect of having the operating system reload the address from its shadow during the VBI handling: This can be seen in Altirra if you load basic, enable the debugger and type "e 9c3e 00 00". So when you write code that, for example, switches out the O/S and provides its own VBI routines, then this would make you responsible for including the same resetting of the h/w values from a shadow. So overall in trying to save 2 bytes out of a dlist the code now needs 10 or 12 bytes of code and a few instruction cycles that h/w is already giving you for free. Therefore I would consider it better practice to include the operands. 1 Quote Link to comment Share on other sites More sharing options...
dmsc Posted March 23, 2019 Share Posted March 23, 2019 Hi! Possibly a few issues with this? The 'void' declaration should probably be 'unsigned char' / 'uint8_t' void DisplayList = This is "special" cc65 syntax: it allows you to define data with different types, allowing mixing bytes and words in the same block. When 'ScreenMemory' is used this should be broken into low and high bytes. <ScreenMemory, >ScreenMemory, This is not needed thanks to the "void" type above, the compiler will do the correct thing.... but, there are other problems with the code: The ending of the instruction list doesn't make sense DL_JVB, DL_JMP a JVB would be followed by the start address of a Dlist so should this have been DL_JVB, <DisplayListMemory, >DisplayListMemory Yes, the correct code should be: #include <atari.h> #define ScreenMemory ((unsigned char *)0x3000) void DisplayList = { DL_BLK8, DL_BLK8, DL_BLK8, DL_LMS(DL_CHR20x8x2), ScreenMemory, DL_CHR20x8x2, DL_CHR20x8x2, DL_CHR20x8x2, DL_BLK4, DL_CHR20x8x2, DL_JVB, &DisplayList }; Note two things: - The ScreenMemory define properly sets the type. Without this, the DL won't work with addresses bellow 0x100, as a byte would be inserted instead of a word. - The JVB jumps to the start of the DL again. This code assumes that the display list will be used as is in memory, not copied to another location. You should assure that the data does not cross a 1k boundary. 2 Quote Link to comment Share on other sites More sharing options...
Wrathchild Posted March 23, 2019 Share Posted March 23, 2019 (edited) Thanks dmsc, With a custom cfg file, using the 'atari' executable FILE format, could you demonstrate how to use a dedicated MEMORY/SEGMENT to place a display list inside such that the code would load directly where it was needed rather than having to relocate it? In the old CC65 world I would define something like this in the cfg file: MEMORY { ... HEADER2: start = $000C, size = $6, file = %O; RAM2: start = $0D00, size = $0100, file = %O; ... } SEGMENTS { ... H_PAGE_D: load = HEADER2, type = ro; PAGE_D: load = RAM2, type = rw, define = yes; ... } and then in assembler code: .segment "H_PAGE_D" ; .word $FFFF .word __PAGE_D_LOAD__ .word __PAGE_D_LOAD__ + __PAGE_D_SIZE__ - 1 presumably the LOAD/RUN/SIZE defines would be accessible in 'C' via an 'extern'? Edited March 23, 2019 by Wrathchild 1 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.