Jump to content

Photo

CC65 - easy and fast way to define a display list


9 replies to this topic

#1 Yaron Nir OFFLINE  

Yaron Nir

    Chopper Commander

  • 125 posts

Posted Sat Mar 23, 2019 5:28 AM

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 by Yaron Nir, Sat Mar 23, 2019 6:21 AM.


#2 Wrathchild OFFLINE  

Wrathchild

    River Patroller

  • 2,189 posts
  • Location:Reading, UK.

Posted Sat Mar 23, 2019 5:51 AM

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


#3 Yaron Nir OFFLINE  

Yaron Nir

    Chopper Commander

  • Topic Starter
  • 125 posts

Posted Sat Mar 23, 2019 6:26 AM

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. 



#4 Yaron Nir OFFLINE  

Yaron Nir

    Chopper Commander

  • Topic Starter
  • 125 posts

Posted Sat Mar 23, 2019 6:42 AM

actually, come to think of it, in this support,  i am not sure display list address is needed after the JVB,



#5 Wrathchild OFFLINE  

Wrathchild

    River Patroller

  • 2,189 posts
  • Location:Reading, UK.

Posted Sat Mar 23, 2019 7:01 AM

Do you understand what the difference between DL_JVB & DL_JMP is?

 

Take a look at the basic dlist:

 

basic_dlist.png


Edited by Wrathchild, Sat Mar 23, 2019 7:06 AM.


#6 Yaron Nir OFFLINE  

Yaron Nir

    Chopper Commander

  • Topic Starter
  • 125 posts

Posted Sat Mar 23, 2019 8:00 AM

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....



#7 Wrathchild OFFLINE  

Wrathchild

    River Patroller

  • 2,189 posts
  • Location:Reading, UK.

Posted Sat Mar 23, 2019 8:16 AM

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.



#8 Wrathchild OFFLINE  

Wrathchild

    River Patroller

  • 2,189 posts
  • Location:Reading, UK.

Posted Sat Mar 23, 2019 8:35 AM

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:

 

dlist_reset.png

 

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.



#9 dmsc OFFLINE  

dmsc

    Dragonstomper

  • 509 posts
  • Location:Viņa del Mar, Chile

Posted Sat Mar 23, 2019 8:52 AM

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.

#10 Wrathchild OFFLINE  

Wrathchild

    River Patroller

  • 2,189 posts
  • Location:Reading, UK.

Posted Sat Mar 23, 2019 9:14 AM

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 by Wrathchild, Sat Mar 23, 2019 9:14 AM.





0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users