Jump to content
LX.NET

Atari Lynx programming tutorial

Recommended Posts

Hello Everyone,

I took the liberty of opening a new topic on the tutorial series. The main reason (besides my big ego) is that the notifications on new parts and potential discussion is now scattered throughout the Atari Lynx and Programming forum and multiple topics. Also, it gives a single, easy to find location for the source code that goes with the tutorials.

So, for your convenience, here is the list of tutorial parts:

Let me know if you find things unclear, wrong, have suggestions for topics, see room for improvement or anything else.
I hope you will find it useful and take up the programming challenge. You can take my word for it, or that of Karri, ninjabba, Matashen, sage, GadgetUK, vince, obschan, TailChao, Sebastian, Wookie, Shawn Jefferson, toyamigo, or any of the other developers: it is a lot of fun.

 

I've added the sources, tools and documentation for the CC65 2.13.9 SVN 5944 which is a known stable build. Remove the .txt extension for the sources archive.

cc65-snapshot-win32-2.13.9.20121203-1.zip

cc65-snapshot-doc-2.13.9.20121203-1.zip

cc65-snapshot-lynx-2.13.9.20121203-1.zip

cc65-snapshot-sources-2.13.9.20121203.tar.bz2.txt

Tutorials26082016.zip

Edited by LX.NET
  • Like 7

Share this post


Link to post
Share on other sites

At a cursory glance this looks like a wonderful bunch of tutorials covering C, cc65 and Lynx development all in one. I can't see any reason anyone wouldn't want to start here for console development!

 

I especially appreciate having a section devoted to setting up your development environment. For those used to higher level languages with integrated IDEs this seems to be a big hurdle for beginners.

  • Like 1

Share this post


Link to post
Share on other sites

Do you plan to explain how to develop (espacially configuring makefiles) without Visual Studio ?

  • Like 1

Share this post


Link to post
Share on other sites

Do you plan to explain how to develop (espacially configuring makefiles) without Visual Studio ?

It's not what I do regularly, but I could do a part on it if I get some input/feedback from those who do.
  • Like 1

Share this post


Link to post
Share on other sites

Makefiles can also be used like scripts. Remember to use tab, not spaces.

 

all:
    $(MAKE) sprites
    $(MAKE) sounds
    $(MAKE) game

sprites:
    sprpck ...

sounds:
    whatever ....

game:
    cl65 -t lynx -o game.lnx ....

 

To build just the sprites type "make sprites"

To build it all type "make"

  • Like 1

Share this post


Link to post
Share on other sites

Some examples which I use:

(as always: You aren't permitted to upload this kind of file)

 

#
# makefile to create a complete Atari Lynx cart using the
# the BLL kit
#
# for savety
SHELL = /bin/sh
ifndef PROJECT_NAME
    $(error PROJECT_NAME not set!)
endif
ifndef LYNX_BASEDIR
    $(error LYNX_BASEDIR not set!)
endif
ifndef LYNX_BIN
    $(error LYNX_BIN not set!)
endif
NEWCC65:=$(LYNX_BASEDIR)/newcc65
BLL_ROOT:=$(LYNX_BASEDIR)/lyxass
export BLL_ROOT
#
# misc binaries
#
RM=rm -f
CP=cp
#
# lynx binaries
# (lyxass, lynxer, ...)
LYXASS=$(LYNX_BIN)/lyxass
LYNXER=$(LYNX_BIN)/lynxer
LYNXDIR=$(LYNX_BIN)/lynxdir																																				   
SPRPCK=$(LYNX_BIN)/sprpck																																					 
MAKE_LNX=$(LYNX_BIN)/make_lnx																																				 
																																										  
#																																											 
# lynx binaries																																							   
# (newcc, ...)																																								
																																										  
NEWCC=$(NEWCC65)/bin/cc65																																					 
XOPT=$(NEWCC65)/bin/xopt																																					  
RASM=$(NEWCC65)/bin/ra65																																					  
LIBR65=$(NEWCC65)/bin/libr65																																				  
LINK65=$(NEWCC65)/bin/link65																																				  
																																										  
BIN2OBJ=$(LYNX_BIN)/bin2obj																																				   
BIN2INCLUDE=$(LYNX_BIN)/bin2include																																		   
BIN2INC=$(LYNX_BIN)/bin2inc																																				   
PUCRUNCH=$(LYNX_BIN)/pucrunch
#
# Libraries and programm parameters
#
CC65INCLUDE=$(NEWCC65)/include/
NEWCC_INC=$(NEWCC65)/include/
export CC65INCLUDE
CC65LIB=$(NEWCC65)/lib/
NEWCC_LIB=$(NEWCC65)/lib/
export CC65LIB
RUNTIME=-r runtime.run
LYNXLIB=lynx.olb
LYNXCLIB=c.olb
LINKOPT= -s2000 $(RUNTIME) $(LYNXCLIB) $(LYNXLIB)
## CFLAGS= -v -I$(NEWCC_INC)
CFLAGS= -I$(NEWCC_INC)
BMPFLAGS= -p1 -t6
.SUFFIXES:
.SUFFIXES: .o .c .cc .obj .m56 .asm .lyx .lnx
.SECONDARY:
.SECONDARY: .o .lyx .obj
.INTERMEDIATE:
.INTERMEDIATE: .m56
.PHONY: all install clean echo
.DEFAULT: all
##########################################
#		  And now the rules...		  #
##########################################
#
# start pic insert.o needs special treatment
#
#insert.o : insert.asm
#	   $(LYXASS) -v -d -o insert.o $<
#
#  Normal assembler file
#
%.o : %.asm
    echo "BLL_ROOT $(BLL_ROOT)"
    $(LYXASS) -v $<
# quiet useless
%.spr : %.bmp
    $(SPRPCK) $(BMPFLAGS) $<
%.m65 : %.c
    $(NEWCC) $(CFLAGS) $<
%.m65 : %.cc
    $(NEWCC) $(CFLAGS) $<
%.obj : %.m65
    $(XOPT) -v $<
    $(RASM) -v $<
%.puc : %.o
    $(PUCRUNCH) -c0 $< [email protected]
%.puc : %.bin
    $(PUCRUNCH) -d -c0 $< [email protected]
#
# simple lynx game, single file unpacked, lynxer-ng is used
#
#%.lnx : %.o
#	   $(LYNXER) -v -l $<
%.lnx : %.o
    $(LYNXDIR) $<
#
# convert lyx to lnx, simple 256*1024b
#
#%.lnx : %.lyx
#	   $(MAKE_LNX) $< -b0 256K
# well here the mak file content must go
#%.lnx : %.mak %.o
#	   $(MAKE_LNX) -l $<
#
#%.lyx : %.mak %.o
#	   $(MAKE_LNX) $<
#
# simple lynx game, single file unpacked, lynxer/-ng is used
# if lyx is really needed
#
#%.lyx : %.o
#	   $(LYNXER) -v $<
%.lyx : %.o
    $(LYNXDIR) $<
#
# now this depends on what your want as result(s).
#
#$(PROJECT_NAME): $(PROJECT_NAME).lnx;
#$(PROJECT_NAME): $(PROJECT_NAME).lyx $(PROJECT_NAME).lnx;
ifeq ((suffix $(PROJECT_NAME)),)
$(PROJECT_NAME): $(PROJECT_NAME).o  $(PROJECT_NAME).lyx $(PROJECT_NAME).lnx;
endif
all:    $(PROJECT_NAME) ;
clean:
    -$(RM) *.o
    -$(RM) *.m65
    -$(RM) *.obj
    -$(RM) *.lyx
    -$(RM) *.lnx
echo:
    @echo "Listing envs:"
    @echo "BLL_ROOT=$(BLL_ROOT)"
    @echo "LYXASS=$(LYXASS)"
    @echo "LYNXER=$(LYNXER)"
    @echo "LYNXDIR=$(LYNXDIR)"
    @echo "SPRPCK=$(SPRPCK)"
    @echo "MAKE_LNX=$(MAKE_LNX)"
    @echo "NEWCC=$(NEWCC)"
    @echo "XOPT=$(XOPT)"
    @echo "RASM=$(RASM)"
    @echo "LIBR65=$(LIBR65)"
    @echo "LINK65=$(LINK65)"
    @echo "BIN2OBJ=$(BIN2OBJ)"
    @echo "BIN2INC=$(BIN2INC)"
    @echo "BIN2INCLUDE=$(BIN2INCLUDE)"
    @echo "... thats all!"

 

and

PROJECT_NAME=pusharoundtheworld
# SOURCE_NAME:=
include $(LYNX_BASEDIR)/Makefile.base
include convspr1.make
include convspr2.make
include convspr3.make
CFLAGS= -I./ -I$(NEWCC_INC)/
LINKOPT= -r ./runtime.run
%.obj : %.m65
    $(XOPT) $<
    $(RASM) $<
soundbs.obj : soundbs.c macros.h
#clean:
#	   $(RM) kisteexp.lyx
#	   $(RM) kisteexp.lnx
STUFF=file_bs3.obj lynx_puc.obj soundbs.obj
optspr.olb: option_ok.bmp
    $(SPRPCK) -i160102 -S006006 -t6 -p0 option_ok.bmp ok.obj
    $(SPRPCK) -i160102 -S006006 -o006000 -t6 -p0  option_ok.bmp no.obj
    $(SPRPCK) -i160102 -S008008 -o012000 -t6 -p0 option_ok.bmp sel.obj
    $(LIBR65) a optspr.olb ok.obj no.obj sel.obj
stuff.olb: $(STUFF)
    $(LIBR65) a stuff.olb $(STUFF)
### explode1.obj
#kiste.c: kiste53.c filenr.h
#	   $(CP) -v $< [email protected]
scanib.c: scanib03.c filenr.h
    $(CP) -v $< [email protected]
kmenu.c: kmenu04.c filenr.h
    $(CP) -v $< [email protected]
kgame.c: kgame05.c filenr.h
    $(CP) -v $< [email protected]
#kiste.obj: kiste.c
#	   $(RM) kiste.m65
#	   $(NEWCC65) kiste.c
#	   $(XOPT) kiste.m65
#	   $(RM) kiste.obj
#	   $(RA65) kiste.m65
kgame.o: stuff.olb kgame.obj  loclib/lynx.olb  loclib/c.olb loclib/runtime.run
    $(LINK65) -v -s1300 -r loclib/runtime.run -o kgame.o stuff.olb kgame.obj loclib/lynx.olb
kmenu.o: stuff.olb kmenu.obj  loclib/lynx.olb  loclib/c.olb optspr.olb loclib/runtime.run
    $(LINK65) -v -s1300 -r loclib/runtime.run -o kmenu.o stuff.olb kmenu.obj loclib/lynx.olb
scanib.o: stuff.olb scanib.obj  loclib/lynx.olb  loclib/c.olb loclib/runtime.run
    $(LINK65) -v -s1300 -r loclib/runtime.run -o scanib.o stuff.olb scanib.obj loclib/lynx.olb
## loclib/c.olb
#### war 1300
#
# BLL serial loader screen
#
bllload.o : bllload.asm
    $(LYXASS) -v $<
#
#  Intro
#
kontis.bin: kon_eu.spr kon_as.spr kon_na.spr kon_af.spr kon_au.spr kon_sa.spr kon_ar.spr kon_an.spr 
    cat $^ >> [email protected]
menu.bin: mw.p16 mhbl.pal mw.spr
    cat $^ >> [email protected]
score.bin: flash/score18.p16 flash/score18.spr
    cat $^ >> [email protected]
option.bin: flash/option.p16 flash/option.spr flash/opt_con.spr flash/opt_res.spr flash/opt_men.spr
    cat $^ >> [email protected]
optionneu1.spr:
    sprpck -t2 -i160102 optneu.sps optionneu1.spr
optionneu2.spr:
    sprpck -u -t2 -i160102 optneu.sps optionneu2.spr
optionneu1.dtt: optionneu1.p16 optionneu1.spr
    cat $^ >> [email protected]
optionneu2.dtt: optionneu1.p16 optionneu2.spr
    cat $^ >> [email protected]
intro.o : intro.asm
    $(LYXASS) -v $<
intro.asm : intro13.asm
    $(CP) -v $< [email protected]
#
#  Boot Logo
#
logo3.spr: logo3.bmp
    $(SPRPCK) -v -s4 -t6 logo3.bmp
insert.o: insert.asm logo3.spr
#
# Now the ROM image
#
%.puc : %.dtt
    $(PUCRUNCH) -d -c0 $< [email protected]
#%.spp : %.spr
#	   $(PUCRUNCH) -d -c0 $< [email protected]
#
#ANIMS = ani_p/scani_01.spp ani_p/scani_02.spp ani_p/scani_03.spp ani_p/scani_04.spp ani_p/scani_05.spp ani_p/scani_06.spp ani_p/scani_07.spp \
#   ani_p/scani_08.spp  ani_p/scani_09.spp ani_p/scani_10.spp ani_p/scani_11.spp ani_p/scani_12.spp ani_p/scani_13.spp ani_p/scani_14.spp \
#   ani_p/scani_15.spp ani_p/scani_16.spp ani_p/scani_17.spp ani_p/scani_18.spp ani_p/scani_19.spp scani.dat
#
#scani.puc: $(ANIMS)
#	   cat $(ANIMS) > scani.puc
SETS = setp/set_0.puc setp/set_0s.puc setp/set_0m.puc setp/set_31.puc setp/set_31s.puc setp/set_31m.puc setp/set_32.puc setp/set_32s.puc setp/set_32m.puc \
 setp/set_33.puc setp/set_33s.puc setp/set_33m.puc setp/set_34.puc setp/set_34s.puc setp/set_34m.puc setp/set_12.puc setp/set_12s.puc setp/set_12m.puc \
 setp/set_13.puc setp/set_13s.puc setp/set_13m.puc setp/set_14.puc setp/set_14s.puc setp/set_14m.puc setp/set_15.puc setp/set_15s.puc setp/set_15m.puc \
 setp/set_16.puc setp/set_16s.puc setp/set_16m.puc setp/set_17.puc setp/set_17s.puc setp/set_17m.puc setp/set_18.puc setp/set_18s.puc setp/set_18m.puc \
 setp/set_19.puc setp/set_19s.puc setp/set_19m.puc setp/set_20.puc setp/set_20s.puc setp/set_20m.puc

LEVELS = level_p/00_null.puc level_p/05_five.puc level_p/16_sixteen.puc level_p/notused.puc \
 level_p/01_one.puc level_p/06_six.puc level_p/20_twenty.puc level_p/sym2_1.puc \
 level_p/02_two.puc level_p/07_seven.puc level_p/30_thirty.puc level_p/sym2_2.puc \
 level_p/03_three_1.puc level_p/08_eight.puc level_p/40_fourty.puc level_p/sym2_3.puc \
 level_p/03_three_2.puc level_p/09_nine.puc level_p/asym.puc level_p/sym4_1.puc \
 level_p/03_three_3.puc level_p/10_ten.puc level_p/bigger.puc level_p/sym4_2.puc \
 level_p/04_four.puc level_p/14_fourteen.puc level_p/doubles.puc
kisteexp.lnx: kisteexp.mak insert.o menu_lex.o intro.puc bllload.puc kmenu.puc kgame.puc \
		    optionneu1.puc optionneu2.puc option.puc menu.puc kontis.puc chip.puc scanib.puc score.puc scani.dat \
		    $(LEVELS) $(SETS) kgame.m65 kmenu.m65 neuebilder/rochen/rochen.p2dat
    lynxdir kisteexp.mak
pusharoundtheworld: kisteexp.lnx kisteexp.lyx
option_g3r.dat: option_g3r.bmp
    $(SPRPCK) -u -s4 -t6 option_g3r.bmp
    cat option_g3r.p16 option_g3r.spr > option_g3r.dat

Share this post


Link to post
Share on other sites

Looks like all the empty newlines got eaten up while posting, sorry for that.

But it should work anyway.

Share this post


Link to post
Share on other sites

It is a fantastic tutorial, I am really fired up on how buzzing this community is at the moment and with all the stuff LX.NET and Karri have done recently regards tutorials and improving CC65 I can see lots of new games coming to the Lynx. Keep up the great work, these tutorials really should be in a book or something - the quality is excellent.

Share this post


Link to post
Share on other sites

Do you plan to explain how to develop (espacially configuring makefiles) without Visual Studio ?

 

I don't know what you use but I wouldnt mind getting Code Blocks working with CC65. For the moment I've got Visual Studio working and a tonne of other bits and pieces on the go but if someone doesnt get Code Blocks working I might take a look sometime in 2013. You can get the free version of Visual Studio I think so its not a none starter.

Share this post


Link to post
Share on other sites

I can see why you might not have access to Visual Studio if you are using an other os than Windows. For the doubters out there: I could do a video on VS. I'll also do a part on non-VS like asked by sage, but I am still uncertain of the priority. I'd rather get some other topics covered first, such as interrupts, timers, controls and sound.

Share this post


Link to post
Share on other sites

The sound tutorial is tricky. There are many candidates out there. A tutorial should consider a way to do simple sounds in a controlled way.

 

Something like

 

unsigned char pong_sound[] = {
 some bytes
}

 

On the other hand I would also like to have some intuitive way to output a note from C-code directly like:

 

unsigned char tune[] = {
 piano,
 note2C,
 delay1,
 end
}

 

Or something like this. You can of course use Chipper as a sequencer and edit the whole tune on a PC. But it would be nice to be able to create and output simple stuff manually.

 

--

Karri

Share this post


Link to post
Share on other sites

I can see why you might not have access to Visual Studio if you are using an other os than Windows. For the doubters out there: I could do a video on VS. I'll also do a part on non-VS like asked by sage, but I am still uncertain of the priority. I'd rather get some other topics covered first, such as interrupts, timers, controls and sound.

 

What about Eclipse? Wouldn't that cover a large amount of operating systems with one dev environment?

Share this post


Link to post
Share on other sites

Eclipse would be cool, I can use the Mac then =)

 

Edit: That said, with the instructions already provided for Visual Studio I should be able to setup Code Blocks or Eclipse. I would focus on the other things youve mentioned - interrupts and sound etc.

Edited by GadgetUK

Share this post


Link to post
Share on other sites

Hello,

I'm looking for advice or perhaps something else. I'm new to Lynx development and Lynx in general. I once talked a bit to Sage and he encouraged me to use LyxAss rather than cc65 (especially that new cc65). I totally agreed then and agree now, that it's a pain in the ass that the new cc65 is incompatible with the old version - I mean the libraries and all that stuff required to do some serious coding. On the other hand, however, LyxAss is really poorly documented and some functions don't seem to work as expected (or maybe as I expect them to work). That slows down the coding and kills all the fun of it.

So, my question is: what would you say? I know that cc65 is the "gold standard" here, but what if you had to write down the pros and cons of both LyxAss and cc65?

Looking forward to a discussion :-)

Cosi

Share this post


Link to post
Share on other sites

For C-code the cc65.org is the choice.

 

For asm-coding I like the bll-kit plus lyxass.

 

I would very much like to create a bll-style macro kit for the ca65 compiler. After that ca65 could be the best choice.

  • Like 1

Share this post


Link to post
Share on other sites

Well, you can use the macros which you find in the chip code example.

They are at least the basic if then else endif

  • Like 1

Share this post


Link to post
Share on other sites

Thanks, guys.

Well, the main drawback of LyxAss is the lack of code examples, compared to cc65 (except that what I got from Sage - thanks!). I think I'll stay by Lyx, since I've already commited a bit of code in it. Patience is the key ;)

Share this post


Link to post
Share on other sites

I do not get your point: the BLL kit contains quiet a lot of code-examples.

Like Bastians 3d qube, times examples. actually everything which pops up the ROM sites as lynx "homebrew" haha

lynx_asm/apfel_2a.asm lynx_asm/demo0006.asm lynx_asm/irq_test.asm

lynx_asm/boing.asm lynx_asm/disass.asm lynx_asm/play_smp.asm

lynx_asm/brk.asm lynx_asm/drawtest.asm lynx_asm/raw.asm

lynx_asm/check_ee.asm lynx_asm/fonttst2.asm

lynx_asm/cir_tunn.asm lynx_asm/i2c_test.asm

  • Like 1

Share this post


Link to post
Share on other sites

The biggest difference between lyxass and ca65 is the syntax of labels and keywords. I have been thinking to add an automatic converter to ca65 to understand lyxass sources. Then you could use ca65 for bll sources directly.

 

The good thing with cc65 is that you don't have to use the provided startup code. It can also use the techniques provided by bll.

Share this post


Link to post
Share on other sites

CC65 is great, you can start quickly without much Lynx knowledge and while you are progressing in understanding the hardware and the compiler you can check CC65 output and fine tune, correct what you think could be better done with inline asm or even directly ca65 assembly source.

And the project is alive, cc65 team constantly improves it, and karri continuously update the lynx library when new ideas, suggestions come.

Edited by obschan
  • Like 2

Share this post


Link to post
Share on other sites

Hello everyone,

 

I cannot believe it has been more than half a year since the last episode.

Anyway, for your reading comfort and education: part 12 discusses the memory management of the Lynx.

http://atarilynxdeveloper.wordpress.com/2013/08/31/programming-tutorial-part-12memory-management/

Proofreading, corrections and suggestions are very welcome.

Enjoy.

 

Alex

Edited by LX.NET

Share this post


Link to post
Share on other sites

That update with part 12 is awesome, I've just learnt a fair bit from that - probably obvious things to other people but I wasn't familiar with how the internal ROM was mapped and I never realised up until this point how to toggle the memory mapping in order to access RAM, Suzi or Mikie etc.

 

Great work =)

  • Like 1

Share this post


Link to post
Share on other sites

Hi Gadget,

 

Thanks for your kind words.

 

I might rename the part to Memory Mapping like you mentioned. Seems like a better term for what is covered.

Share this post


Link to post
Share on other sites

Wow, that is detailed!! I will have a thorough read later on when I have more time. Looks fantastic though, you really got your hands dirty on that part of the tutorial!

Share this post


Link to post
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.

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