Jump to content
IGNORED

Help understanding LMS instructions in display lists


Recommended Posts

Hi,

 

I've been playing with custom display lists (using Atari Basic) and am having trouble understanding LMS instructions. I know that they work as three bytes; an opcode followed by two operands (low byte, high byte). I've been reading De Re Atari and looking at various other sources, but I can't seem to understand exactly how to address them properly to get the display data I want. I also understand that there's some sort of counter that can't cross a (1K?) boundary.

 

So if someone could give me a good explanation of how they work and how to use them that would be greatly appreciated.

  • Like 1
Link to comment
Share on other sites

I am pretty sure if you post what you have done or explained what you are trying to do that someone would help you towards success.

True, but all I was looking for was just a good general explanation.

 

But here's some code in Basic that I've been playing with (referencing the books De Re Atari and Atari Graphics & Arcade Game Design):

 

10 DLIST=1536

20 FOR I=0 TO 41

30 READ A:POKE DLIST+I,A:NEXT I

40 POKE 560,0:POKE 561,6

50 FOR I=0 TO 235

60 FOR J=1 TO 12

70 POKE DLIST+(3*J)+1,I

80 NEXT J

90 NEXT I

100 GOTO 50

110 DATA 112,112,112,71,0,0,71,0,1,71,0,2,71,0,3,71,0,4,71,0,5,71,0,6

120 DATA 71,0,7,71,0,8,71,0,9,71,0,10,71,0,11,65,0,6

 

The program scrolls 12 horizontal 256 byte lines in a rightward motion, each independently displaying a page in the Atari's memory. I understand that the program starts by loading the custom display list into page 6 of the Atari, and then increments the LMS instructions until the end of the allocated memory is reached, where it then restarts. As can be seen, there's an independent LMS instruction for each line, with all of the first operands being 0, and the second operands being the address of the page. The operands are what I need help understanding. As an example: for line #6, it has the LMS instruction "71,0,6". I know that it's addressed to page 6 which is 1536 in decimal. Using 256 byte pages make this display list simple, but I'm having trouble trying to address the operands correctly for any other memory locations besides those pages because I don't quite understand fully how they work (or the calculations used). I hope that makes sense.

 

(I know Basic isn't the ideal language, but I use it to learn and later convert the programs to C using the CC65 cross compiler)

Link to comment
Share on other sites

The instruction 71,0,6 means LMS ANTIC mode 7 (71 is $47 - $40 is LMS instruction the 7 is in what mode it will be displayed - it's graphics mode 2 in basic I think) from address $600 (low byte first - 0, high byte next - 6). The display list simply shows individual lines at addresses $0, $100, $200 .... $a00, $b00.

Link to comment
Share on other sites

Not being able to cross a 1K boundary refers to the display list itself. If you're just doing custom DLists that are only a few bytes longer than standard then you shouldn't have that danger. If you were doing some really big DList like 230 hires bitmap lines where every one was an LMS then you'd have real danger of crossing a 1K boundary.

 

In cases where you know it'll be a large display list the easiest thing to do is just start it on a 1K boundary in the first place.

Link to comment
Share on other sites

And the boundry is 4k for display data itself (that's why GR.8 display lists will have an LMS in the middle). The loops are simply instructing the dlist to begin display data at different points of the pages. Each line's data showing from $xx00 on the first pass, $xx01 on the second, etc. In effect, a coarse horizontal scroll. In this example, each display line needs an LMS so that screen data does not bleed from one line to another.

Edited by Nukey Shay
Link to comment
Share on other sites

Thank you all! And the boundaries now make total sense to me.

 

When it comes to the LMS addresses, I guess what confuses me is that fact that you're representing HEX numbers with whole numbers. I have some new code here that displays one Basic mode 0 line in page 6. For experimentation purposes, I added "Hello!" after the display list in memory (as can be seen when running the program) and I'm trying to address LMS to start at that "Hello" instead of the display list itself:

 

10 DLIST=1536

20 FOR I=0 TO 255:C=DLIST:POKE C+I,0:NEXT I // Clear all of page 6 just in case

30 FOR I=0 TO 15

40 READ A:POKE DLIST+I,A:NEXT I

50 POKE 560,0:POKE 561,6

60 DATA 112,112,112,66,0,6,65,0,6,0,40,37,44,44,47,1

 

So as can been seen, "66,0,6" is the LMS instruction, and "40,37,44,44,47,1" is the added "Hello!". Obviously the LMS is addressed to the beginning of page 6 at location 1536 like before. To start at the "Hello!", I believe I need to start at location 1546. So that would be $60a in HEX. How do I add such an address using whole numbers? (Sorry if the answer is so obvious)

Edited by programmer6502
Link to comment
Share on other sites

Okay, I just figured it out.

 

I played with the program in post #3 again and printed out the values being generated from the code on line #70. I found that when it modifies the LMS operands, it increments the low byte to scroll and leaves the high byte alone with the page number. That makes so much more sense! Now I know what I'm doing! ;)

 

Thank you all once again

 

Edit: Using that knowledge I can solve my problem trying to get the LMS instruction to start at "Hello!" in my previous post by changing the LMS instruction from "66,0,6" to "66,10,6". So it seems that it uses page numbers no matter what, you just move within them.

Edited by programmer6502
Link to comment
Share on other sites

That is how all memory addressing works...low byte (LSB) first, high byte (MSB) second. These 2 bytes, when used together to form an address, are referred to as a word...and should be written the opposite way on paper or in an assembly (MSB followed by LSB). BTW what you are calling "whole numbers" should be referred to decimal to be clear in your descriptions. Hexadecimal numbers should be preceded by the $ symbol, and binary numbers should be preceded by the % symbol. Unfortunately, Atari Basic has no provision to use $hex or %bin numbers directly...so these must be converted into the decimal equivalent when used in DATA lines, etc.

Link to comment
Share on other sites

BTW the program you wrote in post #7 is incorrect...you are confusing a display list with screen data. A display list instructs ANTIC which graphic modes to use & where screen data exists, screen data is the actual characters or bitmap patterns to be displayed.

Link to comment
Share on other sites

That is how all memory addressing works...low byte (LSB) first, high byte (MSB) second. These 2 bytes, when used together to form an address, are referred to as a word...and should be written the opposite way on paper or in an assembly (MSB followed by LSB). BTW what you are calling "whole numbers" should be referred to decimal to be clear in your descriptions. Hexadecimal numbers should be preceded by the $ symbol, and binary numbers should be preceded by the % symbol. Unfortunately, Atari Basic has no provision to use $hex or %bin numbers directly...so these must be converted into the decimal equivalent when used in DATA lines, etc.

Thank you, that makes sense. I was initially thinking decimal but confused the heck out of myself like I like to do. "Words" are new to me so that was a really good lesson using low and high bytes. I should have my username changed to avoid false perceptions that I'm an advanced programmer. ;)

Link to comment
Share on other sites

BTW the program you wrote in post #7 is incorrect...you are confusing a display list with screen data. A display list instructs ANTIC which graphic modes to use & where screen data exists, screen data is the actual characters or bitmap patterns to be displayed.

 

Right, I just meant that I put the screen data "Hello!" after the display list in memory (in the same page). It's spaced a byte or so above the end of the display list program. I apologize, I find that describing programming topics in writing correctly can be a little complicated! :)

Edited by programmer6502
Link to comment
Share on other sites

That's why you wouldn't normally use the screen scroll example program's addresses for your own program. ANTIC expects that the values follow it's own guidelines. Here's a quick rundown...

Values evenly divisible by 16 instruct ANTIC to send a set number of blank scanlines. Commonly used at the start of the display list so that the upper portion of the screen avoids the top of a television display:

0  =  1 blank scanline
16 = 2 blank scanlines
32 = 3 blank scanlines
48 = 4 blank scanlines
64 = 5 blank scanlines
80 = 6 blank scanlines
96 = 7 blank scanlines
112 = 8 blank scanlines

ie Those 3 112's at the start are sending a total of 24 blank scanlines at the top of the display.

 

The very next byte should be which ANTIC mode you want to use...with 64 added to it so ANTIC knows where screen memory begins.

Character modes:
2 = 1 color 40 char. 8 scanlines (GR.0)
3 = 1 color 40 char. 10 scanlines
4 = 5 color 40 char. 8 scanlines
5 = 5 color 40 char. 16 scanlines
6 = 4 color 20 char. 8 scanlines (GR.1)
7 = 4 color 20 char. 16 scanlines (GR.2)
Bitmap modes:
8 = 4 color 40 pixel 8 scanlines (GR.3)
9 = 2 color 80 pixel 4 scanlines (GR.4)
10 = 4 color 80 pixel 4 scanlines (GR.5)
11 = 2 color 160 pixel 2 scanlines (GR.6)
12 = 2 color 160 pixel 1 scanline
13 = 4 color 160 pixel 2 scanlines (GR.7)
14 = 4 color 160 pixel 1 scanline
15 = 1 color 320 pixel 1 scanline (GR.

The 4th byte in the example program is 71...that's 7+64, or GR.2 + the LMS code to set the display address. The 5th and 6th bytes are the LSB and MSB of this address. After LMS has been defined, ANTIC will pull screen data for the following graphic mode(s) sequentially from the last address that had been specified. This is where care must be taken that your screen data does not attempt to cross a 4k boundry. If it is about to...set LMS on the following line to reset the screen address on or beyond the upcoming 4k boundry.

 

Also note that unlike Basic's predefined graphic modes, you can use a display list to mix 'n match graphic modes however you choose. In addition to making use of ANTIC modes that are not predefined by Basic. ANTIC will continue to spool screen data from the last LMS address you specified...or you can reset LMS on any lines you choose.

 

 

0 was already mentioned as the code to use to output 1 blank scanline...but notice that the value 1 was not used in the table above. That is because the value of 1 is used by ANTIC to perform a jump (over a 1k boundry within the display list...or when the LMS code 64 is added, to signal the end of the display list and start VBLANK. So the display list finishes with code 65 followed by the address to jump to for the display list itself.

 

Also notice that all of the values shown above are less than 128. This is because when 128 is added to the values above, it's a signal to ANTIC to trigger a display list interrupt.

 

An interrupt means exactly what it sounds like. When triggered (with interrupts enabled), ANTIC stops everything and executes a short machine language subroutine of your design. There is not much time available when you interrupt ANTIC...just the short period of time when a scanline has finished being sent and the television's electron gun is going back to draw the next line's data (18 cycles total for the subroutine code & return).

Edited by Nukey Shay
  • Like 1
Link to comment
Share on other sites

Some WTF in that article.

 

"Not Turing complete" - who cares? It's a coprocessor in just about the loosest usage of the term, and it's job is fetching data for graphical display, not performing computations.

 

Wiki articles are supposed to give functional overviews, not be a complete reference. OK, on the flipside some Atari related articles are downright annorexic but this one is an epic.

 

And yeah, agreed. Bad move just plagurising Avery's work without a word of credit.

Edited by Rybags
Link to comment
Share on other sites

Yeah that's not cool at all. I noticed that in the book "Atari Graphics & Arcade Game Design" that some of the articles copy De Re Atari almost word for word, or pretty close anyway! But maybe permission was received, I don't have a clue.

 

Well this is what's happening for me if anyone was curious. Been attempting some hard core programming all week and am currently working to bring the years of studying (that's been on and off) into one program in the hopes to eventually go on to make something worth while. Jack-o'-lantern shootout??? No idea. ;)

 

atari_programming_zpsqophxsol.png

 

That might explain some my questionable reasoning in this tread, it's hard not to loose your mind trying to keep everything in check! It's fun though, programming Atari's in the 21st century! :)

 

(Please don't question the code, it's all for experiment so it's dirty :thumbsup:)

  • Like 1
Link to comment
Share on other sites

If you are programming in Basic, you should look into ways you can improve execution time. Like using string variables for display and P/M graphics (to take advantage of Basic's relatively faster string manipulation) and USR routines to replace common multiple-case operations such as controller readings, or other bottlenecks. Also, keep in mind that the lower 3/8th stretch of memory in P/M data can be repurposed for whatever you want - handy if you are using redefined characters but don't need a full set.

  • Like 1
Link to comment
Share on other sites

If you are programming in Basic, you should look into ways you can improve execution time. Like using string variables for display and P/M graphics (to take advantage of Basic's relatively faster string manipulation) and USR routines to replace common multiple-case operations such as controller readings, or other bottlenecks. Also, keep in mind that the lower 3/8th stretch of memory in P/M data can be repurposed for whatever you want - handy if you are using redefined characters but don't need a full set.

Those are some good pointers that I'll try to keep in mind, thanks! I used to program primarily in Basic, but I updated to the CC65 C cross compiler last year and love it. Not only is it a night and day difference in speed, it's so much easier to manage your code. Lot's of flexibility too, there's many ways to accomplish the same task. I think it's a great option if you don't feel up to assembly but want to program somewhat professionally.

 

I do however find Basic to be very handy even when programming with CC65 when I need to quickly test code segments or check memory calculations. Not to mention that when I need to reference code in books, it's usually in Basic then I covert it over to C. So sometimes I'll quickly type in and run the program in Basic first to get a nice overview of it's behavior.

Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...