Jump to content
IGNORED

Session 8: Our First Kernel


Recommended Posts

I think all those WSYNC's look ugly so I thought I'd share this with the class

 

[snip/snip]

 

Z26 must default to PAL because it's not using the whole screen :ponder:

I changed 192 to 242 and it works fine :) but does the vertical blank and overscan need to be adjusted?

 

 

I welcome questions - after all, this is supposed to be an interactive tutorial/forum.

 

I tried to make the code sample as UNDERSTANDABLE as possible. It is certainly not the most efficient code - for it uses too many bytes of ROM to achieve its effect. But we're learning, and what's important right now is understanding how things work.

 

It's as good a time as any to explain a little bit about the assembler - DASM. As you have probably gathered by now, we make our changes to the source code - which is meant to be a human-readable form of the program. We feed that source code to the assembler - and provided the assembler doesn't find any errors in the format of the code, it will convert the human-readable format into a binary format which is directly runnable on the '2600 (burn it to an EPROM, plug the EPROM into a cartridge, and plug the cartridge into a '2600) or on an emulator (just load the binary into the emulator).

 

Consider the following snippet of code...

 


       sta	WSYNC

       sta	WSYNC

       sta	WSYNC

 

That's 3 scanlines of 6502-halting. DASM has a nice feature where it can output a listing file which shows both our original source code, but also the binary numbers it replaces that code with. We'll have a close look at this feature later (and how to 'drive' DASM) - but those wishing to look through the DASM documentation should look for the "-l" switch.

 

When the above code fragment (from our original kernel) is assembled, the listing file contains the following...

 


    25  f008         85 02        sta	WSYNC

    26  f00a         85 02        sta	WSYNC

    27  f00c         85 02        sta	WSYNC

 

 

The leftmost number is the line-number in our original source. The next 4-digit hexadecimal number is the address in ROM of the code. Don't worry too much about that now - but do notice that each line of code is taking 2 bytes of ROM. That is, the first line starts at F008 and the next line starts at F00A (2 bytes different). That's because the "sta WSYNC" assembles to two bytes - $85 and $02. In fact, there's a 1:1 correspondence here between the mnemonic ("abbreviation") of our instruction - the human readable form - and the binary - the machine-readable form. The "sta" instruction (which stands for store-accumulator) has an opcode of $85. Whenever the 6502 fetches an instruction from ROM, and that instruction opcode is $85, it will execute the "store accumulator" instruction.

 

The above code fragment, then, shows three consecutive "$85 $02" pairs, corresponding exactly to our three consecutive "sta WSYNC" pairs. Can you guess the actual address of the TIA WSYNC register? If you need a clue, load up the "vcs.h" file and see what you can find in there. It should be clear to you that the assembler has simply replaced the WSYNC with an actual numerical value. To be exact, after assembling the file, it has decided that the correct value for WSYNC is 2 - and replaced all occurences of WSYNC with the number 2 in the binary image.

 

OK, so that was pretty straightforward - now let's do what HappyDood did, and insert that "REPEAT" thingy...

 


    REPEAT 3

         sta WSYNC

    REPEND

 

This does do exactly the same thing, as he has surmised - but not, I suspect, quite in the way that he thinks. Let's have a look at the listing file for this one...

 


    31  f008           REPEAT	3

    32  f008         85 02        sta	WSYNC

    31  f008           REPEND

    32  f00a         85 02        sta	WSYNC

    31  f00a           REPEND

    32  f00c         85 02        sta	WSYNC

    33  f00e           REPEND

 

If you look carefully, you can see in the source code at right, we still have exactly 3 lines of code - the "sta WSYNC" code - and in the middle, we still have 3 pairs of "$85 $02" bytes in our binary. All that has changed, really, is that our source code was smaller and easier to write (especially if we're considering dozens of lines of "sta WSYNC"s.

 

DASM is a pretty good assembler - and it is loaded with features which make writing code easier. Happy has used one of these features to simplify the writing of the code. That feature is the "repeat" construct. Wrap any code with "REPEAT n" (where n is a number > 0), and "REPEND" and the assembler will automatically duplicate the surrounded code in the binary n times.

 

Note, we're not saving ROM, we're just having an easier time writing the code in the first place.

 

So this highlights, I hope, that it is possible to include things in your source code which are directions to the assembler - basically a guide to the assembler about how to interpret the code. REPEAT is one of those. There are several others, and we will no doubt learn about these in future sessions.

 

I won't introduce too much more 6502 at this stage - but what HappyDood was striving to do was simplify the code. The repeat structure was a way to do that visually, but it does not reduce ROM usage. One way (of several) to do that is to incorporate the "sta WSYNC" into a loop, which iterates 37 times. Here's a teaser...

 


              ; 37 scanlines of vertical blank...



               ldx #0

VerticalBlank   sta WSYNC

               inx

               cpx #37

               bne VerticalBlank

 

 

Remember, the 6502 has three "registers" named "X", "Y", and "A". In the code above, we initialise one register to the value 0 through "ldx #0", then we do the halt "sta WSYNC" which will halt the 6502 until the TIA finishes the current scanline. Then we increment the x-register "inx" by one, then we compare the x-register with 37 "cpx #37". This is in essence asking "have we done this 37 times yet". The final line "bne VerticalBlank" transfers control of the program back to the line "VerticalBlank" if the comparison returned (in effect) "no".

 

The actual listing file for that code contains the following...

 


    41  f012         a2 00        ldx	#0

    42  f014         85 02    VerticalBlank sta	WSYNC

    43  f016         e8        inx

    44  f017         e0 25        cpx	#37

    45  f019         d0 f9        bne	VerticalBlank

 

If we count the number of bytes in the binary output we can see that this code takes just 9 bytes of ROM. If we had 37 "sta WSYNC" instructions, at two bytes each, that's 74 bytes of ROM. Using the REPEAT structure, as noted, will still take 74 bytes of ROM. So looping is a much more efficient way to do this sort of thing. There are even MORE efficient ways, but let's not get ahead of ourselves.

 

We are a bit ahead of ourselves here, so don't panic. Just remember, though, that DASM is a tool designed to aid us humans. It is full of things which make the code more readable (less "ugly") but taking lines of code out does not necessarily mean our code is more efficient - or uses less ROM :)

 

Does anyone familiar with the sessions know if the above info is covered in one of the sessions or does it need to be added?

Edited by Random Terrain
Link to comment
Share on other sites

  • 9 months later...

Hey everyone. Firstly let me say I am absolutely loving the guide. It's one of the few I can actually understand. So far everything was going great until I tried to compile this source code - the process went smoothly but the program itself runs with artifacts so to speak. I'm not sure if dasm/z26 was updated or if I'm screwing up somehow, but copying that source and compiling it with dasm atarit.asm -f3 -oatarit.bin (new and old) gives me this:

 

23kau08.png

 

The end result spits out a thick green bar at the top, followed by a thin green bar at the bottom. For whatever reason, not even the example Andrew compiled himself seems to run properly in StellaX - no idea why but here's what I get:

 

1zgt3pz.png

 

 

Edit- This is what it says with -v5:

 

START OF PASS: 1
----------------------------------------------------------------------
SEGMENT NAME				 INIT PC  INIT RPC FINAL PC FINAL RPC
						 f000						    f000
RIOT					 [u] 0280						    0280
TIA_REGISTERS_READ	   [u] 0000						    0000
TIA_REGISTERS_WRITE	  [u] 0000						    0000
INITIAL CODE SEGMENT		 0000 ????					   0000 ????
----------------------------------------------------------------------
3 references to unknown symbols.
0 events requiring another assembler pass.
--- Symbol List (sorted by symbol)
0.FREE_BYTES			 0000
AUDC0				    0015
AUDC1				    0016
AUDF0				    0017
AUDF1				    0018
AUDV0				    0019
AUDV1				    001a
COLUBK				   0009			  (R )
COLUP0				   0006
COLUP1				   0007
COLUPF				   0008
CTRLPF				   000a
CXBLPF				   0006
CXCLR				    002c
CXM0FB				   0004
CXM0P				    0000
CXM1FB				   0005
CXM1P				    0001
CXP0FB				   0002
CXP1FB				   0003
CXPPMM				   0007
ENABL				    001f
ENAM0				    001d
ENAM1				    001e
GRP0					 001b
GRP1					 001c
HMBL					 0024
HMCLR				    002b
HMM0					 0022
HMM1					 0023
HMOVE				    002a
HMP0					 0020
HMP1					 0021
INPT0				    0008
INPT1				    0009
INPT2				    000a
INPT3				    000b
INPT4				    000c
INPT5				    000d
INTIM				    0284
NUSIZ0				   0004
NUSIZ1				   0005
PF0					  000d
PF1					  000e
PF2					  000f
REFP0				    000b
REFP1				    000c
RESBL				    0014
Reset				    f000			  (R )
RESM0				    0012
RESM1				    0013
RESMP0				   0028
RESMP1				   0029
RESP0				    0010
RESP1				    0011
RSYNC				    0003
StartOfFrame			 f000			  (R )
SWACNT				   0281
SWBCNT				   0283
SWCHA				    0280
SWCHB				    0282
T1024T				   0297
TIA_BASE_ADDRESS		 0000			  (R )
TIA_BASE_READ_ADDRESS    0000			  (R )
TIA_BASE_WRITE_ADDRESS   0000			  (R )
TIM1T				    0294
TIM64T				   0296
TIM8T				    0295
TIMINT				   0285
VBLANK				   0001			  (R )
VDELBL				   0027
VDELP0				   0025
VDELP1				   0026
VERSION_MACRO		    006a
VERSION_VCS			  0069
VSYNC				    0000			  (R )
WSYNC				    0002			  (R )
--- End of Symbol List.

Edited by TerryMasters
Link to comment
Share on other sites

  • 4 years later...

Greetings,

 

I am new to the Atari 2600 and Assembly. I have been following this awesome tutorial but I came across an issue from using this tutorial's code and I am not sure how to fix it.

 

I get this:

 

START OF PASS: 1
Warning: Unable to open 'vcs.h'
Warning: Unable to open 'macro.h'

----------------------------------------------------------------------
SEGMENT NAME INIT PC INIT RPC FINAL PC FINAL RPC
f000 f000

INITIAL CODE SEGMENT 0000 ???? 0000 ????

----------------------------------------------------------------------
458 references to unknown symbols.
458 events requiring another assembler pass.
- Expression in mnemonic not resolved.

--- Unresolved Symbol List
COLUBK 0000 ???? (R )
VBLANK 0000 ???? (R )
VSYNC 0000 ???? (R )
WSYNC 0000 ???? (R )
--- 4 Unresolved Symbols


START OF PASS: 2
Warning: Unable to open 'vcs.h'
Warning: Unable to open 'macro.h'

----------------------------------------------------------------------
SEGMENT NAME INIT PC INIT RPC FINAL PC FINAL RPC
f000 f000

INITIAL CODE SEGMENT 0000 ???? 0000 ????

----------------------------------------------------------------------
458 references to unknown symbols.
458 events requiring another assembler pass.
- Expression in mnemonic not resolved.

--- Unresolved Symbol List
COLUBK 0000 ???? (R )
VBLANK 0000 ???? (R )
VSYNC 0000 ???? (R )
WSYNC 0000 ???? (R )
--- 4 Unresolved Symbols

--- Unresolved Symbol List
COLUBK 0000 ???? (R )
VBLANK 0000 ???? (R )
VSYNC 0000 ???? (R )
WSYNC 0000 ???? (R )
--- 4 Unresolved Symbols



Fatal assembly error: Source is not resolvable.

 

 

Can anyone point me in the right direction?

Edited by PiXL
Link to comment
Share on other sites

START OF PASS: 2

Warning: Unable to open 'vcs.h'

Warning: Unable to open 'macro.h'

 

Can anyone point me in the right direction?

 

These two files (vcs.h and macro.h) are distributed with DASM, and contain code and equates that are needed to get your program working.

Simply put, the assembler can't "see" those files when it's looking for them. Copy them from the DASM directory to the same directory as your source file and this should fix it.

If you don't have them, they should be easy enough to find - try the sourceforge DASM repository, for example.

Essentially it's a path problem - can't find the files as they're not on the search path, or they don't exist. Fix that!

Link to comment
Share on other sites

 

These two files (vcs.h and macro.h) are distributed with DASM, and contain code and equates that are needed to get your program working.

Simply put, the assembler can't "see" those files when it's looking for them. Copy them from the DASM directory to the same directory as your source file and this should fix it.

If you don't have them, they should be easy enough to find - try the sourceforge DASM repository, for example.

Essentially it's a path problem - can't find the files as they're not on the search path, or they don't exist. Fix that!

 

Ah! So that's what it meant! Silly me! Indeed the files seem to be missing.

I'll keep you updated

 

EDIT: I forgot to specify that the DASM I downloaded came from https://sourceforge.net/projects/dasm-dillon/It only came with dasm.Darwin.x86, dasm.exe and dasm.Linux.x86. I can't seem to find the dasm repository on SourceForge

Edited by PiXL
Link to comment
Share on other sites

 

Ah! So that's what it meant! Silly me! Indeed the files seem to be missing.

I'll keep you updated

 

EDIT: I forgot to specify that the DASM I downloaded came from https://sourceforge.net/projects/dasm-dillon/It only came with dasm.Darwin.x86, dasm.exe and dasm.Linux.x86. I can't seem to find the dasm repository on SourceForge

 

You can find those header files in the source. On that page click on files then drill down to the latest source. After unarchiving the source you'll find them in directory machines/atari2600.

Link to comment
Share on other sites

  • 3 years later...
20 minutes ago, KrazyKattapilla said:

Hi,

 

Does the "END" on the last line of the kernel have a special purpose?

 

I seem to be able to compile and run things successfully without it so I'm guessing it's more of an aide-memoir.


Simon

 

Funny, I never even noticed it. My current game has it there. It appears to be superfluous.

 

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