Jump to content
IGNORED

Colecovision wonder-tastic BASIC compiler: CVBasic v0.5.0 (now with bank-switching support!)


Recommended Posts

Hi all.

 

CVBasic the integer BASIC cross-compiler for Colecovision, MSX, and SG1000 has come a long way in a few months! I'm surprised how so fast people are making games with it.

 

After thinking about it a lot, I've decided on a way to implement bank-switching on CVBasic!

 

Bank-switching is supported for Colecovision with Megacart-style banking, for SG1000 using Sega mapper ($fffe), and for MSX using ASCII16 mapper. Again all the platform details are handled by CVBasic, you only need to code the best possible program 😉

 

What can you code in 1 MB of ROM?

 

Changes in v0.5.0:

 

* New statements BANK ROM (for selection ROM size from 128K, 256K, 512K, or 1MB!), BANK to select a bank for following code/data, and BANK SELECT to select a bank to access.

* Added example bank.bas for basic usage of BANK.

* New statement SPRITE FLICKER ON/OFF.

* Optimization of code generation for NEXT.

* Optimization of several 8-bit and 16-bit operations in common usage (typically saving hundreds of bytes in medium-size programs)

* Added patch to make SG1000 compilations compatible with SC3000.

 

Enjoy it!

 

Edit: Book now available! Programming Games for Colecovision (250 pages, paperback) from lulu.com you can see also a preview video

Edit2: Hardcover now available! And also ebook.

 

20240515_134104.thumb.jpg.d09c3402ce88cb2f46dade43a318abf9.jpg

 

cvbasic_v0.5.0.zip

  • Like 11
  • Thanks 2
Link to comment
Share on other sites

Oh wow, the generated assembly code looks much better now :) On my small code (~1KB) the new version saves about 160 bytes!

 

There's still room for improvement, for example when you use a logical operator in an IF-statement the generated assembly code is a bit weird compared to when using logical operators in assignments.

	; 		IF level(cursor_index) AND 64 THEN
	LD A,(cvb_CURSOR_INDEX)
	LD L,A 
	LD H,0
	LD DE,array_LEVEL
	ADD HL,DE
	LD L,(HL)
	LD H,0
	LD A,L
	AND 64
	LD L,A
	LD H,0
	LD A,H
	OR L
	JP Z,cv27

vs.

	; 		tile = level(cursor_index) AND (32+3)
	LD A,(cvb_CURSOR_INDEX)
	LD L,A
	LD H,0
	LD DE,array_LEVEL
	ADD HL,DE
	LD A,(HL)
	AND 35
	LD (cvb_TILE),A

 

In this case LD HL,(cvb_CURSOR_INDEX) / LD H,0 will also save one byte and two cycles.

 

You probably now these 'tricks':

When subtracting a 16bit constant number, just make it negative and add it.

Increasing/decreasing an 8bit number by one can be optimized, LD HL,variable / INC (HL) or DEC (HL).

 

When assigning the same value to multiple variables, it can be loaded in a register just once.

 

In my game players can use both joysticks, so I just use CONT.<DIRECTION> all the time. This could probably just be LD HL,(joy1_data) / LD A,H / OR L.

 

I just skimmed through the assembly code, but there's probably more, I can check more thoroughly if you'd like. Or use the excellent MDL tool made by Santiago Ontañón (it doesn't like the currently generated assembly code due to the # character in labels).

  • Like 1
Link to comment
Share on other sites

41 minutes ago, abeker said:

Oh wow, the generated assembly code looks much better now :) On my small code (~1KB) the new version saves about 160 bytes!

 

There's still room for improvement, for example when you use a logical operator in an IF-statement the generated assembly code is a bit weird compared to when using logical operators in assignments.

	; 		IF level(cursor_index) AND 64 THEN
	LD A,(cvb_CURSOR_INDEX)
	LD L,A 
	LD H,0
	LD DE,array_LEVEL
	ADD HL,DE
	LD L,(HL)
	LD H,0
	LD A,L
	AND 64
	LD L,A
	LD H,0
	LD A,H
	OR L
	JP Z,cv27

vs.

	; 		tile = level(cursor_index) AND (32+3)
	LD A,(cvb_CURSOR_INDEX)
	LD L,A
	LD H,0
	LD DE,array_LEVEL
	ADD HL,DE
	LD A,(HL)
	AND 35
	LD (cvb_TILE),A

 

In this case LD HL,(cvb_CURSOR_INDEX) / LD H,0 will also save one byte and two cycles.

 

You probably now these 'tricks':

When subtracting a 16bit constant number, just make it negative and add it.

Increasing/decreasing an 8bit number by one can be optimized, LD HL,variable / INC (HL) or DEC (HL).

 

When assigning the same value to multiple variables, it can be loaded in a register just once.

 

In my game players can use both joysticks, so I just use CONT.<DIRECTION> all the time. This could probably just be LD HL,(joy1_data) / LD A,H / OR L.

 

I just skimmed through the assembly code, but there's probably more, I can check more thoroughly if you'd like. Or use the excellent MDL tool made by Santiago Ontañón (it doesn't like the currently generated assembly code due to the # character in labels).

Thanks for the suggestions!

 

I'm glad you have nice savings in byte usage.

 

Your first IF can be optimized if you add the period character to the 64 constant. This way, CVBasic gets it as an 8-bit constant.

 

Link to comment
Share on other sites

So that's one megabyte? Like eight megabits, as advertised on Strider for the Sega Genesis? Dang. Will someone have the dedication and sheer force of will to make a ColecoVision game of that size? That falls into "epic RPG" status. Not even Kirby's Adventure at six megabits was that large!

Link to comment
Share on other sites

21 minutes ago, Jess Ragan said:

So that's one megabyte? Like eight megabits, as advertised on Strider for the Sega Genesis? Dang. Will someone have the dedication and sheer force of will to make a ColecoVision game of that size? That falls into "epic RPG" status. Not even Kirby's Adventure at six megabits was that large!

If it helps, my boards can handle up to "HalfMega", or 512KB. 128KB is more common, and is somewhat cheaper.

  • Like 2
Link to comment
Share on other sites

1 hour ago, Jess Ragan said:

So that's one megabyte? Like eight megabits, as advertised on Strider for the Sega Genesis? Dang. Will someone have the dedication and sheer force of will to make a ColecoVision game of that size? That falls into "epic RPG" status. Not even Kirby's Adventure at six megabits was that large!

That's right. Eight megabits.

  • Like 1
Link to comment
Share on other sites

I'm so glad to see bank-switching on CVBASIC, thank you so much!

 

This last version made me save 0,2kb on my game^^

 

Are you planning to release and sell a book about CVBASIC? Where is that Donkey Kong clone game?

  • Like 2
Link to comment
Share on other sites

2 hours ago, Révo said:

I'm so glad to see bank-switching on CVBASIC, thank you so much!

 

This last version made me save 0,2kb on my game^^

 

Are you planning to release and sell a book about CVBASIC? Where is that Donkey Kong clone game?

 

7 minutes ago, ZippyOasys said:

I think he said he is, along with the Monkey Moon example.

That's right. The game is Monkey Moon, and the book is almost around the corner.

 

  • Like 3
Link to comment
Share on other sites

Hi, 

reading in SMS memory mapper info I found this:

 

$fffc Cartridge RAM mapper control
$fffd Mapper slot 0 control
$fffe Mapper slot 1 control
$ffff Mapper slot 2 control

 

 

If you want to change page 2 ($8000-BFFF) you probably need to use ld ($ffff),a

 

In the initializazion part of mapper the code you can find is:

 

ld hl, $0000        ; Set FFFC to 0, FFFD (Slot 0, $0400-$3FFF) to 0

ld ($FFFC), hl

 

ld hl, $0201         ; Set FFFE (Slot 1, $4000-$7FFF) to 1, FFFF (Slot 2, $8000-$BFFF) to 2

ld ($FFFE), hl

 

 

https://www.smspower.org/Development/MemoryMap

 

 

  • Like 1
Link to comment
Share on other sites

5 hours ago, Tony Cruise said:

I have updated my sprite and tile editor to support CVBasic format, let me know if I have missed anything.  New version is available here.

 

Pretty cool. Thanks! People working in Windows surely will appreciate it.

 

A question because I don't see a edit control to enter the label. Can be used a label name like cvb_sprites_bitmap? It is because CVBasic adds the cvb_* part to access labels.

 

1 hour ago, SiRioKD said:

Hi, 

reading in SMS memory mapper info I found this:

 

$fffc Cartridge RAM mapper control
$fffd Mapper slot 0 control
$fffe Mapper slot 1 control
$ffff Mapper slot 2 control

 

 

If you want to change page 2 ($8000-BFFF) you probably need to use ld ($ffff),a

 

In the initializazion part of mapper the code you can find is:

 

ld hl, $0000        ; Set FFFC to 0, FFFD (Slot 0, $0400-$3FFF) to 0

ld ($FFFC), hl

 

ld hl, $0201         ; Set FFFE (Slot 1, $4000-$7FFF) to 1, FFFF (Slot 2, $8000-$BFFF) to 2

ld ($FFFE), hl

 

 

https://www.smspower.org/Development/MemoryMap

 

 

Yes, CVBasic already initializes $fffe for SG1000. The other parts are set on RESET.

 

For compatibility reasons, I've set $0000-$3fff as a fixed bank, and $4000-$7fff as the switchable bank, so it reflects the MSX and Colecovision mappers.

 

Of course, this mapper for SG1000 is kind of extending the standard because so far I don't know any SG1000 game using bank switching, so it would be more for Sega Master System consoles.

  • Like 1
Link to comment
Share on other sites

7 hours ago, Tony Cruise said:

I have updated my sprite and tile editor to support CVBasic format, let me know if I have missed anything.  New version is available here.

 

 

Outstanding - this is awesome news! @Tony Cruise  Would it be possible to add a button to the Screen Layouts tab that will remove any unused chars from the character set list?  Thanks

Edited by OriginalJohn
Link to comment
Share on other sites

9 hours ago, OriginalJohn said:

 

Outstanding - this is awesome news! @Tony Cruise  Would it be possible to add a button to the Screen Layouts tab that will remove any unused chars from the character set list?  Thanks

That's a good idea - I will have a look at that for the next update.

  • Like 1
Link to comment
Share on other sites

10 hours ago, nanochess said:

Pretty cool. Thanks! People working in Windows surely will appreciate it.

 

A question because I don't see a edit control to enter the label. Can be used a label name like cvb_sprites_bitmap? It is because CVBasic adds the cvb_* part to access labels.

 

Yes, CVBasic already initializes $fffe for SG1000. The other parts are set on RESET.

 

For compatibility reasons, I've set $0000-$3fff as a fixed bank, and $4000-$7fff as the switchable bank, so it reflects the MSX and Colecovision mappers.

 

Of course, this mapper for SG1000 is kind of extending the standard because so far I don't know any SG1000 game using bank switching, so it would be more for Sega Master System consoles.

Yes, you can add labels to individual sprites, each tileset and each tile layout.  Just type over the automatically generated name with the new name.

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

I hope moving up the chain of sega consoles eventually leads to Sega Master System support.  Perhaps Sega Genesis support by using the z80 and compatible VDP modes.

 

Flashable boards and shells for Sega Genesis are cheap and easy.  Plus, many more Sega Genesis enthusiasts out there :)

Link to comment
Share on other sites

Heh, I think I've been talking to you on another forum!

 

For the record, I don't know if I can compress the graphics in the game without losing visual quality. (Which would be a shame, as graphics are a highlight in WESEB.) I know Nanochess mentioned something called "pletter" in the instructions, but I don't know how that works. I'm pretty sure I don't want the code to get so complicated that I can't keep track of it, though.

 

I've noticed that SG-1000 games can be slightly larger than ColecoVision games, up to 48K. How does CV Basic handle games for that system and the MSX? Same hard limit on cart size?

  • Like 1
Link to comment
Share on other sites

Pletter is a file compressor. It compress your files on PC and provide you a fast decompressor in Z80 asm to be included in your sources.

I presume that if CVBasic will support pletter compression then it will be totally automatic by some dedicated new command (as the ones he added for cartrige pages switching)

There are megarom cartridges also for colecovision, so no worry about it

  • Like 1
Link to comment
Share on other sites

When you generate graphics through tmscolor -z, your data will be compressed with the Pletter algorithm. Once you insert it into your program, you load as characters or sprites by adding the PLETTER keyword so the compiler knows this data actually is compressed. That is a non-destructive compression, think ZIP in order to save ROM space. While the manual doesn't say, I suppose it might take a little longer to load such data than if it was uncompressed straight from ROM.

 

Since you can DEFINE VRAM at any address with compressed data, I suppose it could be a use case if you keep e.g. changeable level data in a part of VRAM that you VPEEK and VPOKE against all the time. In that case, you would have compressed your levels manually using a Pletter compressor, which is not what you asked for.

  • Like 1
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...
×
×
  • Create New...