<file_sep>
# gfx2col graphic converter for Colecovision PVcollib development

## Usage
```
gfx2col [options] png/bmp/pcx/tga filename ...  
```
where filename is a 256 color PNG, BMP, PCX or TGA file  with only 1st palette used with default 16 colors of Coleco  

## Options  
### General options 
- `-c[no|rle|ple|dan]` Compression method [no]  
  
### Graphique options  
- `-s` Sprite mode   
- `-b` Bitmap mode (no more 256 tiles limits)  
- `-g[m1|m2]` TMS9918 Graphic mode (mode 2 or mode 1) [m2]  
- `-e[0|1|2|3]` Enhanced Color Mode (F18A only) [0]  
- `-t` Enable transparent tiles (color 0)  

### Map options  
- `-m!` Exclude map from output  
- `-m` Convert the whole picture  
- `-mR!` No tile reduction (not advised)  
- `-mn#` Generate the whole picture with an offset for tile number where # is the offset in decimal (0 to 2047)  

### Palette options  
- `-p!` Exclude palette from output  
- `-po` Export palette (16 colors (ecm0) or 64 colors(ecm1-3)  
- `-pR` Palette rounding  

### File options  
- `-f[bmp|pcx|tga|png]` Convert a bmp or pcx or tga or png file [bmp]  
  
### Misc options 
- `-q` Quiet mode  
  
## Example 
```
gfx2col -crle -fpng -m myimage.png
```
 This will will convert a myimage png file to a inc file with 8x8 tiles, rle compressed.

## History  
V1.2.0 : add f18a features  

V1.1.0 : add bitmap mode  

V1.0.0 : initial release  
<file_sep>/*---------------------------------------------------------------------------------

	Generic pad & spinner functions.

	Copyright (C) 2018-2019
		Alekmaul

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:

	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.
	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.
	3.	This notice may not be removed or altered from any source
		distribution.


---------------------------------------------------------------------------------*/
/**
 * \file pad.h
 * \brief coleco generic pad & spinner support.
 *
 * This unit provides methods to read controller state.<br>
 *<br>
 * Here is the list of supported controller devices:<br>
 * - coleco default pad <br>
 * - coleco spinner<br>
*/

#ifndef COL_PAD_H
#define COL_PAD_H

#include <coleco/coltypes.h>

#define	PAD_UP			1
#define	PAD_RIGHT		2
#define	PAD_DOWN		4
#define	PAD_LEFT		8
#define	PAD_FIRE4		16
#define	PAD_FIRE3		32
#define	PAD_FIRE2		64
#define	PAD_FIRE1		128
#define PAD_FIRES       (PAD_FIRE1 | PAD_FIRE2)

#define	PAD_KEY0		0
#define	PAD_KEY1		1
#define	PAD_KEY2		2
#define	PAD_KEY3		3
#define	PAD_KEY4		4
#define	PAD_KEY5		5
#define	PAD_KEY6		6
#define	PAD_KEY7		7
#define	PAD_KEY8		8
#define	PAD_KEY9		9
#define	PAD_KEYSTAR		10
#define	PAD_KEYSHARP	11
#define	PAD_KEYNONE		15

/**
 * \brief PAD 1 value
 */
extern volatile u8 joypad_1;

/**
 * \brief PAD 2 value
 */
extern volatile u8 joypad_2;

/**
 * \brief SPINNER 1 value<br>
 * <b>/!\ spinner 1 value is reversed</b>
 */
extern volatile char spinner_1;

/**
 * \brief SPINNER 2 value
 */
extern volatile char spinner_2;

/**
 * \brief KEYBOARD from PAD 1 values
*/
extern volatile u8 keypad_1;

/**
 * \brief KEYBOARD from PAD 2 values
*/
extern volatile u8 keypad_2;
 
/**
 * \fn void pad_resetspin(void)
 * \brief reset spinners 1 & 2 values
*/
void pad_resetspin(void);

/**
 * \fn void pad_disablespin(void)
 * \brief enable spinners functions 
*/
void pad_disablespin(void);

/**
 * \fn void pad_enablespin(void)
 * \brief enable spinners functions to get their values
*/
void pad_enablespin(void);

#endif
<file_sep>/*---------------------------------------------------------------------------------

	coltypes.h -- Common types (and a few useful macros)

	Copyright (C) 2018-2019
		Alekmaul

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:

	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.
	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.
	3.	This notice may not be removed or altered from any source
		distribution.

---------------------------------------------------------------------------------*/
/*! \file coltypes.h
	\brief Custom types used by pvcollib
*/

#ifndef _COLTYPES_INCLUDE
#define _COLTYPES_INCLUDE

//! bit field 
#define BIT(n) (1<<n)

//! 8 bit and 16 bit signed and unsigned.
typedef	signed char		s8;
typedef	unsigned char	u8;
typedef	signed s16;
typedef	unsigned u16;

//! boolean definitions
typedef unsigned char bool;
#define FALSE 0
#define TRUE 0xff
#define false 0
#define true 0xff

// stdio definitions
#ifndef NULL
#define NULL 0
#endif

#endif
<file_sep>## Configuring tools

We will begin with a Programmer's Notepad Tools menu configuration to have the make command with **Alt+&** shortcut on our keyboard (but you are free to use something else :-D).
First of all, go to **Tools/Options** Menu and select Tools entry to the left. On the **Scheme** dropdown list, select **None** to have the "global tools" selections.

![PNT1](http://www.portabledev.com/wp-content/uploads/2018/02/pn_tools_01.jpg)

Click on **Add** button to the right and type text as in the following screen.  

![PNT2](http://www.portabledev.com/wp-content/uploads/2018/02/pn_tools_02.jpg)

Do same thing for the **make clean** entry, you just have to add the word **clean** in **parameters** text box, and add shortcut **Alt+é** on your keyboard (or what you want ;-)).  
That's all, now you have the _make_ and _make clean_ command defined.  

![PNT3](http://www.portabledev.com/wp-content/uploads/2018/02/pn_tools_03.jpg)

## Editing Path and compiling

With Programmer's Notepad menu **File/Open project(s)**, open the //helloworld.pnproj// file that is in the pvcollib **helloworld** directory example.  
You will see 3 files on the Project Window.  
* helloworld.c is the C source file.
* helloworld.h is the header file of the helloworld.c source file.
* Makefile is the file used to make the .rom file.

Open **Makefile** and change the path to use the correct directory for your colecodev installation. Example below show a **c:/colecodev/** root entry for my coleco developments, if you have **c:\colecodev**, you just have to change it to **/c/colecodev**. Same thing for your devkitcol entry.  

```
  # path to colecodev root directory (for emulators, devkitcol, pvcollib)
  export DEVKITCOL := /c/colecodev/
  
  # path to devkitcol root directory for compiler
  export DEVKITSDCC := /c/colecodev/devkitcol
```

Now, just do a //make clean// command (with the shortcut you configured below, for example Alt+é for me).
You must see a new Output window with the result of your make clean command.

```
  > "make" clean
  clean ...
  
  > Process Exit Code: 0
  > Time Taken: 00:00
```

If an error occurs, that's because your installation is not good, sorry about that. You can post your problem in our 
[Portabledev Forum](http://www.portabledev.com/smf/index.php) or here in [Issues Part](https://github.com/alekmaul/pvcollib/issues), we will help you as soon as possible.

Ok, now your template directory is cleaned, you can run the //make// command (with shortcut, remember ).
You will have the following things in your Programmer's Notepad output window.

```
> "make.exe" 
Compiling C to .rel ... helloworld.c
sdcc -mz80 -c -I/c/colecodev//include -I/c/colecodev/devkitcol/include --std-c99 --opt-code-size --fverbose-asm --max-allocs-per-node 20000 --vc   -I/c/colecodev/coleco-examples/helloworld/  helloworld.c
Linking ... helloworld.rom
sdcc -mz80 --no-std-crt0  --code-loc 0x8048 --data-loc 0x7000   /c/colecodev//lib/collib.lib /c/colecodev//lib/crtcol.rel  helloworld.rel 
sdobjcopy -R .sec5 -I ihex -O binary --pad-to 0xffff --gap-fill 0xff crtcol.ihx helloworld.rom
_CODE                               00008048    000003B5 =         949. bytes (REL,CON)
_GSINIT                             000083FD    0000000F =          15. bytes (REL,CON)
_GSFINAL                            0000840C    00000001 =           1. bytes (REL,CON)
_DATA                               00007000    000000F5 =         245. bytes (REL,CON)
_HEADER0                            00000000    00000024 =          36. bytes (ABS,CON)
_CODE = 0x8048
_DATA = 0x7000
Generate rom ... all

> Process Exit Code: 0
> Time Taken: 00:06
```

That's all, you've compiled your first program that does nothing except display the fantastic "Hello World!" message but it's a first step !.  

Welcome to PVcollib world and enjoy doing some homebrews for your Colecovision :-P !<file_sep>/*---------------------------------------------------------------------------------

	Generic sgm system functions

	Copyright (C) 2021
		Alekmaul

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:

	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.
	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.
	3.	This notice may not be removed or altered from any source
		distribution.

---------------------------------------------------------------------------------*/
/**
 * \file sgm.h
 * \brief contains the basic definitions for controlling the sgm system device.
 *
 * This unit provides generic features related to sgm device.<br>
 *<br>
 * Here is the list of features:<br>
 * - enable and disable sgm<br>
*/

#ifndef COL_SGM_INCLUDE
#define COL_SGM_INCLUDE

#include <coleco/coltypes.h>

/**
 *  \brief sys_sgmok is set if sgm module is present<br>
 *	when calling sys_sgminit function<br>
 */
extern volatile u8 sys_sgmok;

/**
 * \fn void sys_sgminit(void)
 * \brief Activate sgm device<br>
 * Activate SGM and init sys_sgmok variable with 1 if it is ok<br>
*/
void sys_sgminit(void);

#endif
<file_sep>/*---------------------------------------------------------------------------------

	Generic sound functions.

	Copyright (C) 2018-2019
		Alekmaul

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:

	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.
	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.
	3.	This notice may not be removed or altered from any source
		distribution.


---------------------------------------------------------------------------------*/
/**
 * \file sound.h
 * \brief coleco generic sound support.
*/

#ifndef COL_SOUND_H
#define COL_SOUND_H

#include <coleco/coltypes.h>

/** 
	\brief definition of sound area
*/
typedef struct
{
 void *sound_data;
 unsigned sound_area;
} sound_t;

/** 
	\brief sound areas 1 to 6 available pour channels
*/
#define SOUNDAREA1  0x702b
#define SOUNDAREA2  0x702b+10
#define SOUNDAREA3  0x702b+20
#define SOUNDAREA4  0x702b+30
#define SOUNDAREA5  0x702b+40
#define SOUNDAREA6  0x702b+50

/** 
  \brief definition of music area.
	music_duration, [NBR-1 sounds to start | sound_no1 in 6 bits ], sound_no2*, sound_no2*, sound_no2*
	So, for 1 channel, channel_data will have directly the sound entry (ex: 0x01),
	for 2 channels, it will be 0x41,0x02 for example
	for 3 channels, it will be 0x81,02,03
	for 4 channels (maximum), it will be 0xc1,02,03,04
	these sound_no are not essential, it depends on the value of NBR.
	IF music_duration = 0000, END MARKER.
	IF music_duration > 7FFF, SET MUSIC TABLE POINTER TO THIS NEW LOCATION TO CONTINUE.
*/
typedef struct
{
 unsigned music_duration;
 char channel_data[];
} music_t;


/**
 * \brief
 * put 1 to snd_mute to disable sound update.
 */
extern volatile u8 snd_mute;

/**
 * \fn snd_settable (void *snd_table)
 * \brief define the sound table used for playing sound
 *
 * \param snd_table address of sound table
*/
void snd_settable (void *snd_table);

/**
 * \fn snd_startplay (u8 sound_number)
 * \brief play a sound specified but sound_number
 *
 * \param sound_number aid of sound in sound table
*/
void snd_startplay(u8 sound_number);

/**
 * \fn snd_stopplay (u8 sound_number)
 * \brief stop a sound specified but sound_number
 *
 * \param sound_number aid of sound in sound table
*/
void snd_stopplay(u8 sound_number);

/**
 * \fn snd_stopall (void)
 * \brief mute all channels
 *
*/
void snd_stopall(void);

/**
 * \fn snd_isplaying (u8 sound_number)
 * \brief retrieve if channel is playing or not
 *
 * \param sound_number aid of sound in sound table
 * \return 0xff is sound_number is still playing, 0x00 if not
*/
u8 snd_isplaying(u8 sound_number);

/**
 * \fn mus_startplay(void *mudata)
 * \brief play a music specified but mudata.
 *
 * \param mudata entry point of music data (see music_t)
*/
void mus_startplay(void *mudata);

/**
 * \fn mus_nextplay (void *mudata)
 * \brief stop the current music and play the music specified but mudata.
 *
 * \param mudata entry point of music data (see music_t)
*/
void mus_nextplay(void *mudata);

/**
 * \fn mus_stopplay (void)
 * \brief Stop the current music.
*/
void mus_stopplay(void);

/**
 * \fn mus_update (void)
 * \brief This routine can be called at the end of the NMI routine, in project code.
 * To use this routine, the program should not use the first 4 SOUNDAREAs to play sound effects, because they are reserved for the music.
 * Because the first 4 AREAs are low priotity and because of that the sound effect in AREAs 5+ will play while continuing playing logically the music in the background.
*/
void mus_update(void);

#endif
<file_sep>.SECONDARY:
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(PVCOLLIB_HOME)),)
$(error "Please create an environment variable PVCOLLIB_HOME with path to its folder and restart application. (you can do it on windows with <setx PVCOLLIB_HOME "/c/colecodev">)")
endif

include ${PVCOLLIB_HOME}/devkitcol/col_rules

#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
C_SRC	:=	

CFLAGS	:=	

S_SRC	:=	console.s console1.s console1_1.s console2.s console3.s console4.s console5.s console5_1.s console6.s \
    console7.s \
	pad.s \
	sound0.s sound.s sound1.s sound2.s sound3.s sound4.s \
	sprite.s sprite1.s sprite2.s sprite3.s sprite4.s sprite5.s sprite6.s sprite7.s sprite8.s \
	score.s score1.s score2.s score3.s score4.s \
	video.s video1.s video1_1.s video1_2.s video2.s video3.s video3_1.s video4.s video5.s video6.s video7.s video8.s video9.s \
	video10.s video11.s  video11_1.s video12.s video13.s video13_1.s video14.s video15.s video16.s video17.s video18.s video19.s \
	video20.s video21.s video22.s video23.s video24.s video25.s video26.s video27.s video28.s \
    video29.s

ASFLAGS	:=	

INCLUDES	:=	. ../include 

#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS	:= 
 
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS	:= $(DEVKITSDCC) 

export INCLUDE	:=	$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
					$(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
					-I$(CURDIR)/$(BUILD)

CFLAGS	+=	$(INCLUDE)

export COLOBJS = collib.lib crtcol.rel
export OFILES	:=	$(C_SRC:.c=.rel) $(S_SRC:.s=.rel)


#---------------------------------------------------------------------------------
crtcol.rel: crtcol.s 
#	@echo Making entry point ... $(notdir $<)
	$(AS) $(ASFLAGS) -o crtcol.rel $<

collib.lib: $(OFILES)
#	@echo Making lib ... $(notdir $@)
	$(LK) r collib.lib $(OFILES)

all: $(COLOBJS)
	@mv *.lib ../lib
	@mv crtcol.rel ../lib

#---------------------------------------------------------------------------------
clean:
	@echo clean ...
	@rm -f *.rel *.sym *.lst
	@rm -f ../lib/*
<file_sep># ColecoVision Specifications  
This is a **WIP**, I will completed it as long I'm working on the lib and EmulTwo emulator :)

About this Document  
====
**Colecovision Doc Version 1.0, last updated 12 December 2019 by Alekmaul**  
This document describes the I/O Map of Colecovision console, attempting to supply a very compact and mostly complete document about COLECO hardware. 

**Portar doc of MSX by <NAME> for layout, sentences inspiration and MSX info too** http://problemkaputt.de/portar.htm  
**Datasheet for the TMS9918A and TMS9928A** http://www.cs.columbia.edu/~sedwards/papers/TMS9918.pdf  
**TMS9918 Programmer's Guide** http://www.madrigaldesign.it/creativemu/files/tms9918_guide.pdf  
**F18 support thread** https://atariage.com/forums/topic/207586-f18a-programming-info-and-resources/  
**"The new COLECOVISION FAQ" - Version 3.6** Copyright (c) 1994, 1995, 1996   <NAME> and <NAME>.  
**"CV programming guide" - Version 1-k** Last update: October 26, 2005 Amy Purple.

**Copyright**  
This text may not be sold, or included in commercial software/hardware or firmware packages, or used or duplicated for other commercial purposes without the authors permission.  

I/O Port Summary
====
Most internal Coleco hardware is accessed by I/O instructions. In all cases only the lower 8 bits of the I/O addresses are relevant.  
### I/O Ports  
<pre>
80-9F (W) = Controls _ Set to keypad mode
80-9F (R) = Not Connected

A0-BF (W) = Video \___ A0 also decoded by video chip
A0-BF (R) = Video /

C0-DF (W) = Controls _ Set to joystick mode
C0-DF (R) = Not Connected

E0-FF (W) = Sound
E0-FF (R) = Controls _ A1 also decoded by chips  (A1=0 ctrl 1; A1=1 ctrl 2)
</pre>  

Memory
====
The CV uses 2 74138 3-8 line decoders to generate the memory and IO maps. As you would expect, memory is broken up into 8 8K blocks.  

### Memory Map
<pre>
0000-1FFF = BIOS ROM
2000-3FFF = Expansion port
4000-5FFF = Expansion port
6000-7FFF = RAM (1K mapped into an 8K spot)
8000-9FFF = Cart ROM 
A000-BFFF = Cart ROM 
C000-DFFF = Cart ROM      
E000-FFFF = Cart ROM 
</pre>

VDP I/O Ports
===
Port BE-BF are used by the internal VDP TMS9918a

### Internal VDP
<pre>
Port BE VRAM Data (Read/Write)  
Port BF VDP Status Registers (Read Only)  
Port BF 2nd Byte b7=0: VRAM Address setup (Write Only)  
Port BF 2nd Byte b7=1: VDP Register write (Write Only)  
</pre>
### External VDP F18A
to do  

Video Modes
===
This chapter describes the standard VRAM map for the different Colecovision video modes. Note that these default addresses can be changed by modifying VDP registers 2-6.

The VDP Video Modes is selected by the Bits M1-M3 of VDP Register 0 and 1. The relationship between the bits and the screen is:
<pre>
  M1 M2 M3 Screen format
  0  0  0  Half text  32x24             (Mode 0 - Graphic 1)
  1  0  0  Text       40x24             (Mode 1 - Text)
  0  0  1  Hi resolution 256x192        (Mode 2 - Graphic 2)
  0  1  0  Multicolour  4x4pix blocks   (Mode 3 - Multicolor)
</pre>
**Mode 0**: 256x192 pixels total, as 32x24 characters, pulled from 1 character set of 256 8x8 pixel characters. Each group of 8 characters in the character set has a 2-color limitation. For example, the characters "0" through "7" will all have the same color attributes.  
**Mode 1**: 240x192 pixels total, as 40x24 characters, pulled from 1 character set of 256 6x8 pixel characters. The entire character set has a 2-color limitation. This mode doesn't support sprites.  
**Mode 2**: 256x192 pixels total, as 32x24 characters, pulled from 3 character sets of 256 8x8 pixel characters. Each 8-pixel-wide line of a character in the character sets has a 2-color limitation. This mode provides a unique character for every character location on screen, allowing for the display of bitmapped images.  
**Mode 3**: 256x192 pixels total, 64x48 changeable virtual pixels, as 32x24 "semi-graphics" characters. These semi-graphics are defined in a special character set of 256 characters defined by 2x2 "fat-pixels". There are 4x4 pixels in each fat-pixel, but the pixels within a fat-pixel cannot be individually defined, although each fat-pixel can have its own color, hence the name of this mode (Multicolor). This mode is very blocky, and rarely used.  

Foreground Sprites
===
OBJ Attributes (Sprite attribute) define 'OAM' data for up to 32 foreground sprites.  

Each entry consists of four bytes:
<pre>
  0: Y-pos, Vertical position (FFh is topmost, 00h is second line, etc.)
  1: X-pos, Horizontal position (00h is leftmost)
  2: Pattern number
  3: Attributes. b0-3:Color, b4-6:unused, b7:EC (Early Clock)
</pre>
If EC is set to 1, the X-pos is subtracted by 32 (can be used to place sprites particulary offscreen to the left.

When using 16x16 pixel sprites the lower two bits of the sprite number are ignored (should be zero).  
A 16x16 sprite logically consists of four 8x8 sprites, whereas the first 8x8 sprite is displayed in upperleft, the second one in lower left, the third in upper right, and the fourth in lower right.

If Y-pos is set to 208 (D0h), the sprite AND ALL FOLLOWING sprites are hidden! 

This behavior is the same with F18A device, in locked mode (compatible with original VDP).  
In F18A unlocked mode, for all modes and ECM modes settings:
<pre>
  Bit  Name       Expl.
  0-3  PS3-0      Palette select per sprite (b0=PS3, b3=PS0)
  4    SIZE       Size: 0 = global VR1 setting, 1 = 16x16
  5    FLIPY      Sprite flip Y axis 
  6    FLIPX      Sprite flip X axis
  7    EC         Early Clock
</pre>

VRAM Data Read/Write  
===
Port BE VRAM Data (Read/Write)  
Port BF VRAM Address setup (2nd Byte b7=0) (Write Only)  

**Port BEh, Accessing VRAM Data**  
Read data from VRAM, or write data to VRAM. In either case the VRAM read/write pointer is automatically incremented, allowing to read/write a stream of bytes without having to setup the pointer each time.  
  
**Port BFh, VRAM Address Pointer Setup**  
The VRAM read/write pointer is initalized by writing TWO BYTES to port BEh with BIT 7 CLEARED in the second byte.  
<pre>
  Byte 1/Bit 0-7  Lower bits of VRAM Pointer
  Byte 2/Bit 0-5  Upper bits of VRAM Pointer
  Byte 2/Bit 6    Desired VRAM Direction (0=Reading, 1=Writing)
  Byte 2/Bit 7    Must be "0" for VRAM Pointer setup
</pre>
This 14bit Pointer value allows to address 16Kbytes of VRAM 

VDP Status Registers
===
Port BF VDP Status Registers (Read Only)

The Colecovision includes only one VDP Status Register (Register 0), for F18A device VDP Status Registers 0-Fh exist.

Status register 0 (default):  
<pre>
  Bit  Name       Expl.
  0-4  SP4-0      Number for the 5th sprite (9th in screen 4-8) on a line (b0=SP4, b4=SP0)
  5    C          1 if overlapping sprites
  6    5S         1 if more than 4 sprites on a horizontal line (8 in screen 4-8)
  7    F          V-Blank IRQ Flag (1=interrupt) (See also IE0 flag)
</pre>
In mode 1-3 only 4 sprites can be displayed per line. Bit 6 indicates if too many sprites have been (attempted to be) displayed. If the bit is set, Bit 0-4 indicate the number of the sprite that wasn't displayed properly. If more than one sprite haven't displayed properly, then Bit 0-4 specify the first of these bad sprites.  
A sprite is overlapping another if a non-transparent pixel of a sprite hits a non-transparent pixel of another sprite.  
The IRQ flag in bit 7 gets set at the beginning of the VBlank period, if IE0 in VDP Register 1 is set (or gets set at a later time, while the IRQ flag is still set) then an interrupt is generated.  
The IRQ flag (bit 7) and the collision flag (bit 5) get cleared after reading Status register 0.  

VDP Register Write
===
### VDP Registers 00h-07h: Basic Colecovision Video Registers

**Register 00: VR0**  
<pre>
  Bit  Name       Expl.
  0    EXTVID     External video input       (0=input disable, 1=enable)
  1-2  M3-4       Mode M4 M3 (M4 only for F18A)
  3    0          Not Used
  4    IE1        H-Blank Interrupt Enable   (F18A, see also VDP Reg 13h)
  5-7  0          Not Used
</pre>

**Register 01: VR1**  
<pre>
  Bit  Name       Expl.
  0    MAG        Sprite zoom                (0=x1, 1=x2)
  1    SZ         Sprite size                (0=8x8, 1=16x16)
  2    0          Not Used
  3-4  M1-2       Mode M2 M1
  5    IE0        V-Blank Interrupt Enable   (0=Disable, 1=Enable)
  6    BLK        Screen output control      (0=Disable, 1=Enable)
  7    4K16K      VRAM size control          (0=4K, 1=16K, ignored for F18A)
</pre>

The video modes are:  
<pre>
Mode=M4 M3 M2 M1  
GM1 = 0  0  0  0  
GM2 = 0  1  0  0  
MCM = 0  0  1  0  
T40 = 0  0  0  1 (40 col)  
T80 = 1  0  0  1 (80 col)  
</pre>
M4 is only available for F18A device.  

**Register 2: VR2 Name Table Base Address, 1K boundaries**  
<pre>
  Bit     7    6    5    4    3    2    1    0
  Name    0    0    0    0   A00  A01  A02  A03
</pre>
768-bytes per table for 24 rows  
960-bytes per table for 30 rows  
Multiply this value by 400h to have the real address  

**Register 3: VR3 Color Table Base Address, 64-byte boundaries**  
<pre>
  Bit     7    6    5    4    3    2    1    0
  Name   A00  A01  A02  A03  A04  A05  A06  A07
</pre>
32-bytes long for original color mode (default)  
For the F18A enhanced color modes, this becomes Tile Attribute Table Base Address  
The Tile Attribute Table is 256 bytes long  
768 to 4K when in position-attribute mode depending on the size of the horz / vert pages.  
Multiply this value by 40h to have the real address  

**Register 4: VR4 Pattern Generator Base Address, 2K boundaries** 
<pre>  
  Bit     7    6    5    4    3    2    1    0
  Name    0    0    0    0    0   A00  A01  A02
</pre>
2K for 256 tiles  
4K for 2-bit color mode, 6K for 3-bit color mode  
Multiply this value by 800h to have the real address  

**Register 5: VR5 Sprite Attribute Table Base Address, 128-byte boundaries**  
<pre>
  Bit     7    6    5    4    3    2    1    0
  Name    0   A00  A01  A02  A03  A04  A05  A06
</pre>
128-bytes (32 sprites, 4 bytes each)  
Multiply this value by 80h to have the real address  

**Register 6: VR6 Sprite Pattern Generator Base Address, 2K boundaries** 
<pre>
  Bit     7    6    5    4    3    2    1    0
  Name    0    0    0    0    0   A00  A01  A02
</pre>
2K for 256 patterns  
4K for 2-bit color mode, 6K for 3-bit color mode  
Multiply this value by 800h to have the real address  

**Register 7: VR7 Text color / background color**  
<pre>
  Bit  Name       Expl.
  0-3  BG0-3      Background colour 
  4-7  FG0-3      Foreground colour
</pre>
The bits 0-3 and 4-7 can hold a number in the range of 0-15.  

The corresponding colours are:  
<pre>
  0 = Transparent         8 = Medium red
  1 = Black               9 = Light red
  2 = Medium green        10= Dark yellow
  3 = Light green         11= Light yellow
  4 = Dark blue           12= Dark green
  5 = Light blue          13= Magenta
  6 = Dark red            14= Gray
  7 = Cyan                15= White
</pre>

### VDP Registers 0Ah-39h: Additional VR10-VR57 F18A Video Registers  

**Register 0A: VR10 Name Table 2 Base Address, 1K boundaries** 
<pre>
  Bit     7    6    5    4    3    2    1    0
  Name    0    0    0    0   A00  A01  A02  A03
</pre>

768-bytes per table for 24 rows  
960-bytes per table for 30 rows  

**Register 0B: VR11 Color Table 2 Base Address, 64-byte boundaries**
<pre>
  Bit     7    6    5    4    3    2    1    0
  Name   A00  A01  A02  A03  A04  A05  A06  A07
</pre>

Works the same as VR3 in Enhanced Color Modes / Position-Attribute Mode  

**Register 18: VR24 Extra palette-select bits for original color modes**  
<pre>
  Bit  Name       Expl.
  0-1  T1PS0-1    Tile 1 layer palette selector
  2-3  T2PS0-1    Tile 2 layer palette selector
  4-6  SPS0-1     Sprite palette selector
  6-7  0          Not used
</pre>

**Register 1D: VR29 Page size for scrolling**  
<pre>
  Bit  Name       Expl.
  0    VPSIZE1    VPSIZE = vertical page size layer 1, 0 = 1 page, 1 = 2 pages
  1    HPSIZE1	  HPSIZE = horizontal page size  layer 1, 0 = 1 page, 1 = 2 pages
  2-3  TPGS0-1    TPGS = tile pattern generator offset size, 11=256, 10=512, 01=1K, 00=2K
  4    VPSIZE2	  VPSIZE = vertical page size layer 2, 0 = 1 page, 1 = 2 pages
  5    HPSIZE2	  HPSIZE = horizontal page size  layer 2, 0 = 1 page, 1 = 2 pages
  6-7  SPGS0-1    SPGS = sprite pattern generator offset size, 11=256, 10=512, 01=1K, 00=2K
</pre>

**Register 1E: VR30 Max sprite per scan line**  
<pre>
  Bit  Name       Expl.
  0-4  SPRTMAX0-4 Max sprites per scan line
  5-7  0          Not used
</pre>
Max sprites per scan line are set to 0 to reset sprite max to jumper setting  

**Register 2F: VR47**  
<pre>
  Bit  Name       Expl.
  0-5  PR0-5      Palette register #
  6    AUTO INC   Auto inc palette index after each write
  7    DPM        Data-port mode, 1 to enable
</pre>

**Register 30: VR48 SIGNED two's-complement increment amount for VRAM address, defaults to 1**  
<pre>
  Bit  Name       Expl.
  0-6  INC0-6     Value
  7    SIGN-BIT   Signed bit  
</pre>

**Register 31: VR49** 
<pre>
  Bit  Name       Expl.
  0-1  ECMS0-1    ECM (S)prite
  2    0          Not Used
  3    Y_REAL     Real sprite Y-coord
  4-5  ECMT0-1    ECM (T)ile
  6    ROW30      24 / 30 tile rows (30 rows disables 0xD0 in SAL)
  7    TILE2_EN   Tile Map 2 enable, 1 to enable
</pre>

ECM = enhanced color mode for (T)ile and (S)prite  
<pre>
  0=nomal/original color
  1=1-bit color mode, tile attributes
  2=2-bit color mode, tile attributes
  3=3-bit color mode, tile attributes
</pre>

**Register 32: VR50**  
<pre>
  Bit  Name       Expl.
  0    TILE2_PRI  0 = TL2 always on top, 1 = TL2 vs sprite priority is considered
  1    POS_ATTR   Position vs name attributes		0 = per name attributes in ECMs, 1 = per position attributes
  2    SCANLINES  Show virtual scan lines			0 = no virtual scan lines, 1 = enable virtual scan lines
  3    RPTMAX     Report sprite max vs 5th sprite				0 = report 5th sprite, 1 = report max sprite (VR30)	
  4    TL1_OFF    0 = normal, 1 = disable GM1, GM2, MCM, T40, T80    	
  5    GPU_VTRIG  0 = disable, 1 = trigger GPU on VSYNC	
  6    GPU_HTRIG  0 = disable, 1 = trigger GPU on HSYNC    	
  7    VR_RESET   0 = ignored, 1 = reset all VDP registers to power-on defaults
</pre>

**Register 36: VR54**  
<pre>
  Bit  Name       Expl.
  0-7  GPU0-7     GPU address MSB
</pre>

**Register 37: VR55**  
<pre>
  Bit  Name       Expl.
  0-7  GPU8-15    GPU address LSB, writing resets and loads, then triggers the GPU
</pre>

**Register 38: VR56**  
<pre>
  Bit  Name       Expl.
  0-6  0          Not used
  7    GPUOP      GPU Operation performed when register is written: 0 = reset and load PC, 1 = trigger GPU to begin execution
</pre>

**Register 39: VR57**
<pre>
  Bit  Name       Expl.
  0-7  VALUE      Unlock: Enable registers over 7, write 000111xx to VR57 twice
</pre>

F18A Tile attribute byte in Enhanced Color Modes  
===
Color Table becomes Tile Attribute Table Base Address and goes from 32 to 256 or 2K (same as name table) bytes long.  <pre>
  Bit  Name       Expl.
  0-3  PS3-0      Palette selection (b3=PS0, b0=PS3)
  4    TRANS      When 1, colors with 0, 00 or 000 will be transparent instead of a palette index
  5    FLIPY      Tile flip over Y
  6    FLIPX      Tile flip over X
  7    PRI        Tile priority over sprite
</pre>

When T40/T80 Mode, ECM0, and Position-Based Attributes is Enabled									
<pre>
  Bit     7    6   5   4   3   2   1   0
  Name   FG0	FG1	FG2	FG3	BG0	BG1	BG2	BG3	T40/80 fg / bg color
</pre>

SN76489 sound chip
===
The sound chip in the CV is a SN76489AN manufactured by Texas Instruments.  
It has 4 sound channels- 3 tone and 1 noise.  

The volume of each channel can be controlled seperately in 16 steps from full volume to silence.  

A byte written into the sound chip determines which register is used, along with the frequency/ attenuation information.

The frequency of each channel is represented by 10 bits.  10 bits won't fit into 1 byte, so the data is written in as 2 bytes.  

Here's the control word:  
<pre>
+--+--+--+--+--+--+--+--+
|1 |R2|R1|R0|D3|D2|D1|D0|
+--+--+--+--+--+--+--+--+
</pre>

1: This denotes that this is a control word  
R2-R0 the register number:  

000 Tone 1 Frequency
001 Tone 1 Volume
010 Tone 2 Frequency
011 Tone 2 Volume
100 Tone 3 Frequency
101 Tone 3 Volume
110 Noise Control
111 Noise Volume

D3-D0 is the data

Here's the second frequency register:
<pre>
+--+--+--+--+--+--+--+--+
|0 |xx|D9|D8|D7|D6|D5|D4|
+--+--+--+--+--+--+--+--+
</pre>
0: This denotes that we are sending the 2nd part of the frequency

D9-D4 is 6 more bits of frequency 


To write a 10-bit word for frequenct into the sound chip you must first send the control word, then the second frequency register.  
Note that the second frequency register doesn't have a register number.  
When you write to it, it uses which ever register you used in the control word.  

So, if we want to output 11 0011 1010b to tone channel 1:

First, we write the control word:  
<pre>
LD A,1000 1010b
OUT (F0h),A
</pre>

Then, the second half of the frequency: 
<pre>
LD A,0011 0011b
OUT (F0h),A
</pre>

To tell the frequency of the wave generated, use this formula:  


   3579545
f= -------
     32n

Where f= frequency out,
and n= your 10-bit binary number in


To control the Volume:  
<pre>
+--+--+--+--+--+--+--+--+
|1 |R2|R1|R0|V3|V2|V1|V0|
+--+--+--+--+--+--+--+--+
</pre>

R2-R0 tell the register  
V3-V0 tell the volume:  

0000=Full volume  
.  
.  
.  
1111=Silence  


The noise source is quite intresting.  It has several modes of operation.  
Here's a control word:  

+--+--+--+--+--+--+--+--+
|1 |1 |1 |0 |xx|FB|M1|M0|
+--+--+--+--+--+--+--+--+

FB= Feedback:

0= 'Periodic' noise
1= 'white' noise 

The white noise sounds, well, like white noise.
The periodic noise is intresting.  Depending on the frequency, it can
sound very tonal and smooth.

M1-M0= mode bits:

00= Fosc/512  Very 'hissy'; like grease frying
01= Fosc/1024 Slightly lower
10= Fosc/2048 More of a high rumble
11= output of tone generator #3

You can use the output of gen. #3 for intresting effects.  
If you sweep the frequency of gen. #3, it'll cause a cool sweeping effect of the noise.  
The usual way of using this mode is to attenuate gen. #3, and use the output of the noise source only.  

The attenuator for noise works in the same way as it does for the other channels.    

Colecovision Models  
===
**ColecoVision:**  
<pre>
             Resolution: 256 x 192
                    CPU: Z-80A
                   Bits: 8
                  Speed: 3.58 MHz
                    RAM: 8K
	      Video RAM: 16K (8x4116)
Video Display Processor: Texas Instruments TMS9928A
                Sprites: 32
                 Colors: 16
                  Sound: Texas Instruments SN76489AN; 3 tone channels, 1 noise
          Cartridge ROM: 8K/16K/24K/32K
</pre>

**ADAM:**  
<pre>
             Resolution: 256 x 192
                    CPU: Z-80A
                   Bits: 8
                  Speed: 3.58 MHz
	    Video Speed: 10.7 MHz
                    RAM: 64K (128K optional)
	      Video RAM: 16K (8x4116)
                    ROM: 8K
Video Display Processor: Texas Instruments TMS9928A
                Sprites: 32
                 Colors: 16
                  Sound: Texas Instruments SN76489AN; 3 tone channels, 1 noise
          Cartridge ROM: 8K/16K/24K/32K
	    Disk Drives: 2 * 160K (opt)
    Digital Data Drives: 2 * 256K
		  Modem: 300 Baud (opt)
	        Printer: 120 wpm Daisy Wheel, 16K buffer
		  Other: Serial/Parallel Port (opt), Auto Dialer (opt)
</pre>

JUMP functions   
===
ColecoVision BIOS is also refered as OS 7prime, also refered simply as OS7.  
Because it was the 7th revision of the BIOS when the console was released.  

OS 7prime BIOS Jump table  
Legend:
P (at the end): function specifically done for Pascal programs.  
<pre>
1F61 > 0300 : PLAY_SONGS                      1F64 > 0488 : ACTIVATEP
1F67 > 06C7 : PUTOBJP                         1F6A > 1D5A : REFLECT_VERTICAL
1F6D > 1D60 : REFLECT_HORIZONTAL              1F70 > 1D66 : ROTATE_90
1F73 > 1D6C : ENLARGE                         1F76 > 114A : CONTROLLER_SCAN
1F79 > 118B : DECODER                         1F7C > 1979 : GAME_OPT
1F7F > 1927 : LOAD_ASCII                      1F82 > 18D4 : FILL_VRAM
1F85 > 18E9 : MODE_1                          1F88 > 116A : UPDATE_SPINNER
1F8B > 1B0E : INIT_TABLEP                     1F8E > 1B8C : GET_VRAMP
1F91 > 1C10 : PUT_VRAMP                       1F94 > 1C5A : INIT_SPR_ORDERP
1F97 > 1C76 : WR_SPR_NM_TBLP                  1F9A > 0F9A : INIT_TIMERP
1F9D > 0FB8 : FREE_SIGNALP                    1FA0 > 1044 : REQUEST_SIGNALP
1FA3 > 10BF : TEST_SIGNALP                    1FA6 > 1CBC : WRITE_REGISTERP
1FA9 > 1CED : WRITE_VRAMP                     1FAC > 1D2A : READ_VRAMP
1FAF > 0655 : INIT_WRITERP                    1FB2 > 0203 : SOUND_INITP
1FB5 > 0251 : PLAY_ITP                        1FB8 > 1B08 : INIT_TABLE
1FBB > 1BA3 : GET_VRAM                        1FBE > 1C27 : PUT_VRAM
1FC1 > 1C66 : INIT_SPR_ORDER                  1FC4 > 1C82 : WR_SPR_NM_TBL
1FC7 > 0FAA : INIT_TIMER                      1FCA > 0FC4 : FREE_SIGNAL
1FCD > 1053 : REQUEST_SIGNAL                  1FD0 > 10CB : TEST_SIGNAL
1FD3 > 0F37 : TIME_MGR                        1FD6 > 023B : TURN_OFF_SOUND
1FD9 > 1CCA : WRITE_REGISTER                  1FDC > 1D57 : READ_REGISTER
1FDF > 1D01 : WRITE_VRAM                      1FE2 > 1D3E : READ_VRAM
1FE5 > 0664 : INIT_WRITER                     1FE8 > 0679 : WRITER
1FEB > 11C1 : POLLER                          1FEE > 0213 : SOUND_INIT
1FF1 > 025E : PLAY_IT                         1FF4 > 027F : SOUND_MAN
1FF7 > 04A3 : ACTIVATE                        1FFA > 06D8 : PUTOBJ
1FFD > 003B : RAND_GEN 
</pre>

RAM MAP  
===
Complete OS 7prime RAM Map
<pre>
Address   Name                 Description                 
7020-7021 PTR_LST_OF_SND_ADDRS Pointer to list (in RAM) of sound addrs
7022-7023 PTR_TO_S_ON_0        Pointer to song for noise
7024-7025 PTR_TO_S_ON_1        Pointer to song for channel#1
7026-7027 PTR_TO_S_ON_2        Pointer to song for channel#2
7028-7029 PTR_TO_S_ON_3        Pointer to song for channel#3
702A      SAVE_CTRL            CTRL data (byte)
73B9      STACK                Beginning of the stack
73BA-73BF PARAM_AREA           Common passing parameters area (PASCAL)
73C0-73C1 TIMER_LENGTH         Length of timer
73C2 TEST_SIG_NUM              Signal Code
73C3-73C4 VDP_MODE_WORD        Copy of data in the 1st 2 VDP registers
73C5      VDP_STATUS_BYTE      Contents of default NMI handler
73C6      DEFER_WRITES         Defered sprites flag
73C7      MUX_SPRITES          Multiplexing sprites flag
73C8-73C9 RAND_NUM             Pseudo random number value
73CA      QUEUE_SIZE           Size of the defered write queue
73CB      QUEUE_HEAD           Indice of the head of the write queue
73CC      QUEUE_TAIL           Indice of the tail of the write queue
73CD-73CE HEAD_ADDRESS         Address of the queue head
73CF-73D0 TAIL_ADDRESS         Address of the queue tail
73D1-73D2 BUFFER               Buffer pointer to defered objects
73D3-73D4 TIMER_TABLE_BASE     Timer base address
73D5-73D6 NEXT_TIMER_DATA_BYTE Next available timer address
73D7-73EA DBNCE_BUFF           Debounce buffer. 5 pairs (old and state)
                                of fire, joy, spin, arm and kbd for each player.
73EB      SPIN_SW0_CT          Spinner counter port#1
73EC      SPIN_SW1_CT          Spinner counter port#2
73ED                           (reserved)
73EE      S0_C0                Segment 0 data, Controller port #1
73EF      S0_C1                Segment 0 data, Controller port #2
73F0      S1_C0                Segment 1 data, Controller port #1
73F1      S1_C1                Segment 1 data, Controller port #2
73F2-73FB VRAM_ADDR_TABLE      Block of VRAM table pointers
73F2-73F3 SPRITENAMETBL        Sprite name table offset
73F4-73F5 SPRITEGENTBL         Sprite generator table offset
73F6-73F7 PATTERNNAMETBL       Pattern name table offset
73F8-73F9 PATTERNGENTBL        Pattern generator table offset
73FA-73FB COLORTABLE           Color table offset
73FC-73FD SAVE_TEMP            (no more used - in VRAM routines)
73FE-73FF SAVED_COUNT          Copy of COUNT for PUT_VRAM and GET_VRAM
</pre>

ROM Header  
===
All carts start at 8000h with a header that tells the BIOS what to do.  
<pre>
8000 - 8001:   If bytes are AAh and 55h, the CV will show a title screen
               and game name, etc.
               If bytes are 55h and AAh, the CV will jump directly to the
               start of code vector.

8002 - 8003:   Pointer to RAM copy of the sprite name table 
8004 - 8005:   Pointer to RAM sprite table
8006 - 8007:   Pointer to free buffer space in RAM
8008 - 8009:   Pointer to controller memory map
800A - 800B:   Pointer to start of code
800C - 800E:   Jmp to: RST 08h
800F - 8011:   Jmp to: RST 10h
8012 - 8014:   Jmp to: RST 18h
8015 - 8017:   Jmp to: RST 20h
8018 - 801A:   Jmp to: RST 28h
801B - 801D:   Jmp to: RST 30h
801E - 8020:   Jmp to: RST 38h
8021 - 8023:   JMP to: NMI (Vertical Blanking Interrupt from video chip)
8024 - nnnn:   String with two delemiters "/" as "LINE2/LINE1/YEAR"
</pre>

Data for the title screen is composed of 4 lines in the format:  
<pre>
+--------------+
| COLECOVISION |
|              |
|    LINE 2    |
|    LINE 3    |
|(c)xxxx COLECO|
+--------------+
</pre>

**Typical Screen**  
The '**ColecoVision**' line cannot be changed, as well as the '(C)xxxx Coleco' part of the bottom line.  Only the xxxx part can be changed.
The data is stored as one string with the '/' character (2Fh) used as a delimiter.  It signals the end of a line, and isn't printed.  
The lines are stored out of order like so:  
"LINE 3/LINE 2/xxxx"  There isn't an end-of-line delimiter, because the last line is always 4 characters (it's meant for a year like 1983)

So, if we want to see the following:  
<pre>
+--------------+
| COLECOVISION |
|              |
|   MY GAME!   |
|    BY: ME    |
|(c)1995 COLECO|
+--------------+
</pre>

We would use the string:  
<pre>
"BY: ME!/MY GAME!/1995"
</pre>
Remember, we cannot change the "(c)xxxx COLECO" part, only the xxxx in the middle of the line.
The lines are self-centering on the screen.  
Altho the BIOS ROM has both upper-case and lower-case characters in the character set, only upper-case is supported.  

All printable characters are based on the ASCII character set:  
(all values in hex)  
<pre>
00-1C:     Blank
1D   :     (c)    (Copyright symbol)
1E-1F:     tm     (TradeMark symbol, uses 2 chars side-by-side)
20-2E: (respectively)  space ! " # $ % & ' ( ) * + , - .
2F   :     Delimiter- used to end a line, not printable
30-39:     0-9
3A-40: (respectively)  : ; < = > ? @
41-5A:     A-Z
5B-5F: (respectively)  [ \ ] ^ _
</pre>
The chars # 60-8F are the 4-char blocks that make up the '**COLECOVISION**' name at the top, arranged like so:  
<pre>
         6062 6466 686A 6C6E 7072 7476 787A 7C7E 8082 8486 888A 8C8E
         6163 6567 696B 6D6F 7173 7577 797B 7D7F 8183 8587 898B 8D8F

          C    O    L    E    C    O    V    I    S    I    O    N
         (purple)  (orange)   (pink)   (yellow)   (green)   (blue)
</pre>

What's intresting, is when these are in the title lines, they show up in their respective colours!  All other printable chars are white.  
Chars 90-FF are all blank

Cartridge Memory Mappers  
===
**Magecart from <NAME>** (created in August 2005)  
Megacart EPROMs are broken up into 16k pages, and are banked by accessing the last 64 addresses of the cartridge space (0xFFC0 - 0xFFFF).  
Accessing 0xFFFF maps the top 16k of the EPROM (or page 0), 0xFFFE maps the second-to-last 16k (or page 1), 0xFFFD maps the third-to-last 16k (or page 2), etc.  
Megacarts are limited to a maximum size of 1MB.

The first 16K of the cartridge (CV 8000h-BFFFh) is fixed and will always contain the highest/last 16K segment of the EPROM.  
Therefore, this data will appear twice (CV 8000h-BFFFh and C000h-FFFFh) if the last bank is selected.

It is recommended that the following addresses be read to select banks:  
<pre>
128K -  8 banks - FFF8h-FFFFh.
256K - 16 banks - FFF0h-FFFFh.
512K - 32 banks - FFE0h-FFFFh.
 1MB - 64 banks - FFC0h-FFFFh.
</pre>
Remember that strobing FFFFh places the same data in both halves of the cartridge memory



# END  
<file_sep>#ifndef __SDCC_STDNORETURN_H
#define __SDCC_STDNORETURN_H 1

#define noreturn _Noreturn

#endif

<file_sep># Installation #

  1. **[Installation with Windows](https://github.com/alekmaul/pvcollib/wiki/Installation-with-Windows)**
  1. **[PVcollib and Programmer Notepad](https://github.com/alekmaul/pvcollib/wiki/PVcollib-and-Programmer-Notepad)**

# Programming #

# Tips #
  1. **[Colecovision Specs](https://github.com/alekmaul/pvcollib/wiki/Complete-Colecovision-Specs)**<file_sep>// this file contains only graphics generated by gfx2col
// it's here because we need a file to compile for pvcollib, 
//  not one auto generated

#include "pacspritegfx.inc"		// generetad by gfx2col
<file_sep>#ifndef COMPDAN2_H
#define COMPDAN2_H

#include <stdio.h>
#include <stdlib.h>
#include <mem.h>

#define bool unsigned char
#define byte unsigned char
#define false 0
#define true 0xff

extern int dan2Compress(byte *src,byte *dst,int n);

#endif<file_sep>#ifndef _SCORING_MAIN_
#define _SCORING_MAIN_

#include <coleco.h>


#endif
<file_sep>/*---------------------------------------------------------------------------------

	Generic video functions

	Copyright (C) 2018-2020
		Alekmaul

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:

	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.
	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.
	3.	This notice may not be removed or altered from any source
		distribution.

---------------------------------------------------------------------------------*/
/**
 * \file video.h
 * \brief contains the basic definitions for controlling the video hardware.
 *
 * This unit provides generic features related to video management.<br>
 *<br>
 * Here is the list of features:<br>
 * - enable and disable screen or vdp or nmi<br>
 * - clear, fill vram <br>
 * - retreive or set some vram area<br>
 * - update vram with some specific algorithm like Run Length, Pletter or Amy Purple DAN1 compression algorithm<br>
*/

#ifndef COL_VIDEO_INCLUDE
#define COL_VIDEO_INCLUDE

#include <coleco/coltypes.h>

#define FNTNORMAL          0
#define FNTITALIC          1
#define FNTBOLD            2
#define FNTBOLD_ITALIC     (FNTITALIC | FNTBOLD)

#define chrgen  			0x0000
#define coltab  			0x2000
#define chrtab 				0x1800
#define chrtab2				0x1B00
#define sprtab  			0x3800
#define sprgen  			0x1f00

#define COLTRANSP			0
#define COLBLACK			1
#define COLMEDGREEN			2
#define COLLITGREEN			3
#define COLDRKBLUE			4
#define COLLITBLUE			5
#define COLDRKRED			6
#define COLCYAN				7
#define COLMEDRED			8
#define COLLITRED			9
#define COLDRKYELLOW		10
#define COLLITYELLOW		11
#define COLDRKGREEN			12
#define COLMAGENTA			13
#define COLGREY				14
#define COLWHITE			15

/**
 *  \fn void vdp_setreg(u8 reg,u8 val)
 *  \brief Set a value to a TMS9918 register
 *
 *  \param  reg register number
 *  \param val value to assign
*/
void vdp_setreg(u8 reg,u8 val);

/**
 *  \fn void vdp_waitvblank(u16 numtime)
 *  \brief Waits for a vertical blank interrupt a number of time
 *
 *  \param numtime number of vblank to wait
*/
void vdp_waitvblank(u16 numtime);

/**
 * \fn void vdp_enablenmi(void)
 * \brief Enable NMI interruption
 *
*/
void vdp_enablenmi(void);

/**
 * \fn void vdp_disablenmi(void)
 * \brief Disable NMI interruption
*/
void vdp_disablenmi(void);

/**
 * \fn void vdp_enablevdp(void)
 *\brief Allows VDP to work (so screen is now active)
*/
void vdp_enablevdp(void);

/**
 * \fn void vdp_disablevdp(void)
 * \brief Disallows VDP to work (so screen is not active)
*/
void vdp_disablevdp(void);

/**
 * \fn void vdp_enablescr(void)
 * \brief Allows VDP to work and NMI to be catch
*/
void vdp_enablescr(void);

/**
 * \fn void vdp_disablescr(void)
 * \brief Disallows VDP to work and NMI to occur
*/
void vdp_disablescr(void);

/**
 * \fn void vdp_setmode1txt(void)
 * \brief Activate mode 1 in text mode<br>
 * Activate Mode 1 of TMS in text mode, 16K of VRAM, sprites 16x16<br>
 * 1 VRAM (duplicated each for 8 lines) that can be populate<br>
* CHRGEN is located at $0000, COLTAB is located at $2000<br>
*/
void vdp_setmode1txt(void);

/**
 * \fn void vdp_setmode2txt(void)
 * \brief Activate mode 2 in text mode<br>
 * Activate Mode 2 of TMS in text mode, 16K of VRAM, sprites 16x16<br>
 * 3 VRAM areas (each for 8 lines) that can be populate<br>
*/
void vdp_setmode2txt(void);

/**
 * \fn void vdp_setmode2bmp(void)
 * \brief Activate mode 2 in bitmap mode<br>
 * Activate Mode 2 of TMS in bitmap mode, 16K of VRAM, sprites 16x16<br>
 * 1 VRAM area (complete screen of 24 lines) that can be populate<br>
*/
void vdp_setmode2bmp(void);

/**
 * \fn void vdp_setcharex(u8 first,u8 count, unsigned offset,u8 flags)
 * \brief  Put some chars of default font
 *
 * \param first 1st char to put
 * \param count number of chars
 * \param offset address location in video memory for the chararter patterns
 * \param flags type of font<br>
 *  FNTNORMAL for the normal font<br>
 *  FNTITALIC for the italic font<br>
 *  FNTBOLD for the bold font<br>
 *  FNTBOLD_ITALIC fot both italic and bold font<br>
*/
void vdp_setcharex(u8 first,u8 count, unsigned offset,u8 flags);

/**
 * \fn void vdp_putchar (u8 x, u8 y, char value)
 * \brief  Put a single char on screen
 *
 * \param x colum to print
 * \param y line to print
 * \param value ascii value of char to print
*/
void vdp_putchar (u8 x, u8 y, char value);

/**
 * \fn u8  vdp_getchar (u8 x, u8 y)
 * \brief  Get a single char from screen
 *
 * \param x column of the char
 * \param y line of the char
 * \return char value from screen
*/
u8  vdp_getchar (u8 x, u8 y);

/**
 * \fn void vdp_getarea (void *table, u8 x, u8 y, u8 width, u8 height)
 * \brief  Get an area of chars from screen
 *
 * \param table area in ram to save chars
 * \param x column of the chars
 * \param y line of the chars
 * \param width length of x chars to get
 * \param height length of y chars to get
*/
void vdp_getarea (void *table, u8 x, u8 y, u8 width, u8 height);

/**
 * \fn void vdp_putarea (void *table, u8 x, u8 y, u8 width, u8 height)
 * \brief  Put an area of chars to screen
 *
 * \param table area in ram to load chars
 * \param x column of the chars
 * \param y line of the chars
 * \param width length of x chars to put
 * \param height length of y chars to put
*/
void vdp_putarea (void *table, u8 x, u8 y, u8 width, u8 height);

/**
 * \fn  void vdp_setdefaultchar(u8 flags)
 * \brief Put default font
 *
 * \param flags	character format<br>
 * FNTNORMAL for the normal font<br>
 * FNTITALIC for the italic font<br>
 * FNTBOLD for the bold font<br>
 * FNTBOLD_ITALIC fot both italic and bold font<br>
*/
void vdp_setdefaultchar(u8 flags);

/**
 * \fn  void vdp_putstring(u8 x, u8 y, char* text)
 * \brief Put a string on screen at coordinates x,y
 *
 * \param x column x
 * \param y line y
 * \param text text to display
*/
void vdp_putstring(u8 x, u8 y, char* text);

/**
 * \fn void vdp_fillvram(u16 offset,u8 value,u16 count)
 * \brief  Change VRAM with a specific value
 *
 * \param offset  address in VRAM
 * \param value  value to set
 * \param count  number of time we set value
*/
void vdp_fillvram(u16 offset,u8 value,u16 count);

/**
 * \fn void vdp_putvram_repeat(unsigned offset,void *table, u8 count, u8 times)
 * \brief  Repeat n times an area of chars to screen
 *
 * \param offset  address in VRAM
 * \param table   area in ram to load chars
 * \param count   number of chars to repeat
 * \param times   number of time we set chars
*/
void vdp_putvram_repeat(unsigned offset,void *table, u8 count, u8 times);

/**
 * \fn void vdp_duplicatevram(void)
 * \brief Put 1st area of pattern vram to the 2nd and 3rd one
*/
void vdp_duplicatevram(void);

/**
 * \fn void vdp_putvram (unsigned offset,void *data,unsigned count)
 * \brief Fill the VRAM with some non compressed data 
 *
 * \param offset address in VRAM of 1st data to fill
 * \param data address of data to use
 * \param count number of data
*/
void vdp_putvram (unsigned offset,void *data,unsigned count);

/**
 * \fn void vdp_getvram (unsigned offset,void *data,unsigned count)
 * \brief Get from VRAM to a RAM pointer with some non compressed data 
 *
 * \param offset address in VRAM of 1st data to get
 * \param data address of RAM to use
 * \param count number of data
*/
void vdp_getvram (unsigned offset,void *data,unsigned count);

/**
 * \fn void *vdp_rle2vram (void *rledata,unsigned offset)
 * \brief Fill the VRAM with some RLE compressed data 
 * 
 * \param rledata address of data to use
 * \param offset address in VRAM of 1st data to fill
 * \return pointer to first unused free
*/
void *vdp_rle2vram (void *rledata,unsigned offset);

/**
 * \fn void vdp_ple2vram(void *pledata, unsigned offset)
 * \brief Put data in VRAM with some Pletter compressed data 
 *
 * \param pledata address of data to use
 * \param offset address in VRAM of 1st data to fill
*/
void vdp_ple2vram(void *pledata, unsigned offset);

/**
 * \fn void vdp_dan12vram(void *dan1data, unsigned offset)
 * \brief Put data in VRAM with some DAN1 compressed data 
 *
 * \param dan1data address of data to use
 * \param offset address in VRAM of 1st data to fill
*/
void vdp_dan12vram(void *dan1data, unsigned offset);

/**
 * \fn void vdp_dan22vram(void *dan2data, unsigned offset)
 * \brief Put data in VRAM with some DAN2 compressed data 
 *
 * \param dan2data address of data to use
 * \param offset address in VRAM of 1st data to fill
*/
void vdp_dan22vram(void *dan2data, unsigned offset);

/**
 * \fn void vdp_dan32vram(void *dan3data, unsigned offset)
 * \brief Put data in VRAM with some DAN2 compressed data 
 *
 * \param dan3data address of data to use
 * \param offset address in VRAM of 1st data to fill
*/
void vdp_dan32vram(void *dan3data, unsigned offset);

/*! \fn vdp_blocknmi 
	\brief set no_nmi flag to avoid nmi 
*/
#define vdp_blocknmi()  { __asm__("\tpush hl\n\tld hl,#_no_nmi\n\tset 0,(hl)\n\tpop hl"); }

/*! \fn vdp_releasenmi 
	\brief reset no_nmi flag to allow nmi 
*/
#define vdp_releasenmi() { __asm__("\tpush hl\n\tld hl,#_no_nmi\n\tres 0,(hl)\n\tpop hl"); }

#endif
<file_sep>/*---------------------------------------------------------------------------------


	Simple console 'hello world' demo
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "helloworld.h"

//---------------------------------------------------------------------------------
// The NMI routine. Gets called 50 or 60 times per second 
// nothing to update for Helloworld example
void nmi (void) {
}

//---------------------------------------------------------------------------------
void main (void) {
	// Put screen in text mode 2
	vdp_setmode2txt();
	
	// Put default char in VRAM and duplicate to all areas
	//  as we are going to write to line 10, it is in the second area
	vdp_setdefaultchar(FNTNORMAL);
	vdp_duplicatevram();
	vdp_fillvram(0x2000,0xf1,128*8); 	// Change color (or we will see nothing)
	vdp_enablescr();
	
	// Print at 10,text as we are not going to do something else
	vdp_putstring(10,10,"HELLO WORLD!");
	
	// Wait for nothing :P
	while(1) {
		// Wait Vblank
		vdp_waitvblank(1);
	}
	// startup module will issue a soft reboot if it comes here 
}
<file_sep>/*---------------------------------------------------------------------------------

	Copyright (C) 2018-2020
		Alekmaul 

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:

	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.
	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.
	3.	This notice may not be removed or altered from any source
		distribution.

	Image converter for colecovision.
	BMP BI_RLE8 compression support by <NAME>
	palette rounded option from <NAME>
    Dan1 & Dan2 & Dan3 compression support from Amy Purple aka newcoleco
	
***************************************************************************/

//INCLUDES
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <malloc.h>
#include <string.h>

#include "gfx2col.h"

#include "lodepic.h"
#include "lodepng.h"

#include "comptool.h"
#include "comprle.h"
#include "compdan1.h"
#include "compdan2.h"
#include "compdan3.h"

enum FILE_TYPE {
    BMP_FILE = 1,
    PCX_FILE,
    TGA_FILE,
    PNG_FILE
};

int output_palette=-1;		  // 64 colors output (F18A only) palettes
int palette_rnd=0;      	  // 1 = round palette up & down (F18A only)
int quietmode=0;              // 0 = not quiet, 1 = i can't say anything :P
int compress=0;               // 0 = not compressed, 1 = rle compression, 2 = ple compression, 3 = dan1 compression, 
                              //    4 = dan2 compression, 5 = dan3 compression
int sprmode=0;                // 0 = background 1 = sprite
int bmpmode=0;				  // 0 = normal tile mode, 1=bitmap mode
int gramode=0;				  // 0 = TMS9918a graphic mode 2, 1 = graphic mode 1
int ecmmode=0;				  // 0 = noactive, 1=ecm0,2=ecm1, etc ... (F18A only, will generate a palette)
int offset_tile=0;			  // n = offset in tile number
int transmode=0;			  // 0 = not transparent, 1 = transprent tiles activated
int highpriority=0;     	  // 1 = high priority for map

//---------------------------------------------------------------------------
void PutWord(int data, FILE *fp)
{
	putc(LOW_BYTE(data),fp);
	putc(HI_BYTE(data),fp);
} //end of PutWord

//---------------------------------------------------------------------------
unsigned char *ArrangeBlocks( unsigned char *img, int width, int height,
							 int size, int *xsize, int *ysize, int new_width)
{
	/*
	** img = image buffer
	** width = width (in pixels) of image buffer
	** height = height (in pixels) of image buffer
	**
	** size = size (in pixels) of image blocks in the image
	** *xsize = number of image block horizontally in image block grid
	** *ysize = number of image block vertically in image block grid
	**
	** new_width = how wide (in pixels) you want the new buffer to be
	**             must be a multiple of size
	**
	**
	** returns:
	**      pointer to new buffer, and updates xsize and ysize
	**
	*/
	unsigned char *buffer;
	int rows, num;
	int i,j, line;
	int x,y;

	//get number of full image block rows in the new buffer
	rows = (*xsize)*(*ysize)/(new_width/size);   // rows = num_blocks / new_xsize

	//if it doesn't divide evenly, add another full row
	if ( ((*xsize)*(*ysize))%(new_width/size) != 0 )
		rows++;

	if (quietmode == 0)
		printf("\nrows=%d",rows);

	//get memory for the new buffer
	buffer = (unsigned char *) malloc( rows*size*new_width*sizeof(char) );
	if(buffer == NULL) {
		return 0;
	}

	// Initially clear the buffer, so if there are empty image blocks or incomplete blocks, the empty parts will be blank
	memset(buffer,0,(size_t) rows*size*new_width*sizeof(char) );

	//position in new buffer (x,y) where x and y are in pixel co-ordinates
	x=0;
	y=0;

	//go through each image block(i,j) where i and j are in block co-ordinates
	for(j=0; j < *ysize; j++)
    {
    	for(i=0; i < *xsize; i++)
	    {
		    //move each line of the block into the new buffer
    		//don't worry about reading past the end of the image here
	    	//there is an extra 64 lines to read in.
		    for(line=0;line<size;line++)
    		{
	    		//find out how much to copy
		    	//this is needed because the screen mode files may not be
    			//a multiple of 8 pixels wide
	    		//or no-border files may have the wrong width
		    	num = width - (i*(size));
			    if(num>size)
				    num=size;

    			memcpy( &buffer[ (y+line)*new_width + x ], &img[ (j*(size) + line )*width + i*(size) ], num);
	    	}

		    // move to the next location in the new buffer
    		x+=size;
	    	if(x >= new_width)
		    {
			    x=0;
    			y+=size;
	    	}
	    }
    }

    *xsize = new_width/size;
    *ysize = rows;

	return buffer;
} //end of ArrangeBlocks()

//---------------------------------------------------------------------------
unsigned int MakeCol(unsigned char *buffer, unsigned int *tilemap, unsigned char *num_col, unsigned int *colmap,int *num_tiles,int mapw, int maph)
{
	int colval,nbcol;
	int i,j, t,x,y;
	int colidx, tilidx;
	unsigned char minv,maxv,actminv,actmaxv;
	unsigned char valtil[8];
	unsigned char newcol;
	unsigned char *tilreorg;
	unsigned int *mapreorg;
	unsigned int idxcoltil[256];

	// init color values
	newcol=0;
	for (t=0;t<32;t++)
		colmap[t]=0x100; 					// outside scope value 
	for (t=0;t<256;t++)
		idxcoltil[t]= 32;					// outside score value 
		
	//loop through tiles
	for (t=0;t<*num_tiles;t++) 
	{ 
		actminv=1; actmaxv=0xF;
		for(y=0;y<8;y++) {
			minv=0xFF; maxv=0x00;

			// get the 8 values
			for (x=0;x<8;x++) {
				valtil[x]=buffer[t*64 + y*8 + x];
				// get min and max value
				if (valtil[x]<minv)
					minv=valtil[x];
				if (valtil[x]>maxv)
					maxv=valtil[x];
			}
			// put 1 if max color
			if (maxv <= 0x01) maxv=0xF;
			if (minv == 0xff) minv=1;
			// if 1st time,assign it
			if (y==0)
			{
				if ( (minv!=1) && (maxv!=minv) ) actminv=minv;
				if (maxv!=0xF) actmaxv=maxv;
			}
			else
			{
				if ( (actminv!=minv) &&  (actmaxv!=maxv) ) 
				{
					printf("\nERROR: Too much color (4) for 8x8 tile #%d\n",t);
					return 0;
				}
				if ( (actminv!=minv) && (actminv!=1)  && (maxv!=minv) )
				{
					printf("\nERROR: Too much color (min) for 8x8 tile #%d\n",t);
					return 0;
				}
				else
					if (maxv!=minv) actminv=minv;
				if ( (actmaxv!=maxv) && (actmaxv!=0xF) && (maxv!=0xF) )
				{
					printf("\nERROR: Too much color (max) for 8x8 tile #%d\n",t);
					return 0;
				}
				else
					if (maxv!=0xF) actmaxv=maxv;
			}
			colval=(actmaxv<<4) | (actminv);		// FG color | BG color 
		}
		// try to assign for a color for the 8x8 square
		colidx=-1;
		for (i=0;i<32;i++)
		{
			if (colmap[i]==0x100) {
				colmap[i]=colval;
				colidx=i;
				newcol++;
				break;
			}
			else if (colmap[i]==colval)
			{
				colidx=i;
				break;
			}
		}
		// if not assigned, huston, we have a problem ;)
		if (colidx==-1) 
		{
			printf("\nERROR: Too much colors assigned (more than 32) encountered for 8x8 tile #%d\n",t);
			return 0;
		}
		idxcoltil[t]=colval;
	}
	
	// try to alloc for new tiles arrangement
	tilreorg=(unsigned char *) malloc((size_t)256*64);
	if(tilreorg==NULL) {
		return 0;
	}
	mapreorg=(unsigned int *) malloc((size_t)mapw*maph*sizeof(int));
	if(mapreorg==NULL) {
		return 0;
	}
	memset(tilreorg,0,256*64);
	memset(mapreorg,0,mapw*maph*sizeof(int));

	// Rearrange tiles & map to fit with colors (1 colors for 8 tiles)
	printf("\nRearrange tiles & map to fit with colors (1 colors for 8 tiles)...");fflush(stdout);
	tilidx=0;
	for (i=0;i<32;i++)
	{
		// check all tiles
		nbcol=0;
		for (t=0;t<*num_tiles;t++) 
		{
			// if we find the color, just put the tile
			if (idxcoltil[t]==colmap[i])
			{
				// if we have now more than 8 tiles, need to go next color entry
				if (nbcol==8)
				{
					nbcol=0;
					newcol++;
					for (j=31;j>i;j--)
					{
						colmap[j]=colmap[j-1];
					}
					i++;
					colmap[i]=colmap[i-1];
				}

				// Put the tile
				memcpy(&tilreorg[tilidx],&buffer[t*64],64);
				// Adapt the map
				for (j=0;j<mapw*maph;j++)
				{
					if (*(tilemap+j)==t)
					{
						*(mapreorg+j)=(tilidx/64);
					}
				}
				tilidx+=64;
				nbcol++;
			}
		}
		
		// one color is finished, if we are not near a 8 tiles border, need to adapt
		if (nbcol & 7)
		{
			tilidx+=(8-nbcol)*64;
		}
	}
	// now put back to buffer & map
	printf("\nNew number of tiles is %d...",tilidx/64);fflush(stdout);

	for (i=0;i<tilidx;i++)
		*(buffer+i)=*(tilreorg+i);
	for (i=0;i<mapw*maph;i++)
		*(tilemap+i)=*(mapreorg+i);
	
	free(mapreorg);
	free(tilreorg);

	// keep track of number of colors & number of tiles
	*num_col=newcol;
	*num_tiles=tilidx/64;
	
	return 1;
}

//---------------------------------------------------------------------------
unsigned int *MakeMap(unsigned char *img, unsigned int *colf18a, int *num_tiles, int xsize, int ysize, int tile_x, int tile_y, unsigned char optimize)
{
	unsigned int *map;
	int newtiles;
	int current,palette,oldpal;	//the current tile we're looking at
	int i,t;
	int x,y;

	//allocate map
	map=(unsigned int *) malloc((size_t)tile_x*tile_y*sizeof(int));
	if(map==NULL) {
		return 0;
	}

	//clear map
	memset(map,0,tile_x*tile_y*sizeof(int));

	current=0;
	t=0;
	newtiles=0;
	oldpal=-1;

	for(y=0;y<ysize;y++)
    {
    	for(x=0;x<xsize;x++)
	    {

			//get the palette number
			if (ecmmode==4) // ecm 3
				palette = (img[current*64] >> 3) & 0x07;
			else if (ecmmode==3) // ecm 2
				palette = (img[current*64] >> 2) & 0x0F;
			else				// ecm 1 and others
				palette = (img[current*64] >> 1) & 0x1F;
			/* test purpose if (ecmmode>1) 
			{
				if (oldpal!=palette) {
					printf("\npalette=%04x",palette);fflush(stdout);
					oldpal=palette;
				}
			}*/

    		//check for matches with previous tiles if tile_reduction on
            if (optimize)
            {
    			for(i=0;i<newtiles;i++)
	    			if( memcmp(&img[i*64],&img[current*64],64) == 0 )
		    			break;
            }
            else
                i=newtiles;

			// if ecm mode, put in color table for the tile attributre
			if (ecmmode>1) 
			{
				// How colors are managed:
				// ps  = palette select from VR24
				// cs  = color value from color table (256 bytes for ECM1..3)
				// px0 = pixel from byte from pattern table 0 (original mode and EMC1)
				// px1 = pixel from byte from pattern table 1 (ECM2)
				// px2 = pixel from byte from pattern table 2 (ECM3)
			
				// Bit  Name       Expl.
				// 0-3  PS3-0      Palette selection (b3=PS0, b0=PS3)
				// 4    TRANS      When 1, colors with 0, 00 or 000 will be transparent instead of a palette index
				// 5    FLIPY      Tile flip over Y
				// 6    FLIPX      Tile flip over X
				// 7    PRI        Tile priority over sprite
  				if (ecmmode==2) colf18a[newtiles]=(palette); 					// ECM1    : ps0 cs0 cs1 cs2 cs3 px0 
				else if (ecmmode==3) colf18a[newtiles]=(palette); 				// ECM2    : cs0 cs1 cs2 cs3 px1 px0
				else if (ecmmode==4) colf18a[newtiles]=(palette<<1)& 0xFE; 		// ECM3    : cs0 cs1 cs2 px2 px1 px0
				colf18a[newtiles]|=(transmode<<4) | (highpriority<<7);
			}
			
			//is it a new tile?
			if(i==newtiles)
			{
				// yes -> add it
				memcpy(&img[newtiles*64],&img[current*64],64);
				t=newtiles;
				newtiles++;
			}
			else
			{	// no -> find what tile number it is
				t=i;
			}

    		//put tile number in map
	    	map[y*tile_x+x] = t+offset_tile;
		}

		//goto the next tile
		current++;
	}

	//also return the number of new tiles
	*num_tiles = newtiles;

	return map;

}//end of MakeMap

//---------------------------------------------------------------------------
void ConvertPalette(RGB_color *palette, unsigned int *new_palette)
{
	int i,data;
	int rounded;
	int temp;

	//Convert the colors and put them in the new array
	//
	//alternate rounding down and rounding up
	//this is an attempt to preserve the brightness of a color
	//which the human eye notices easier than a change in color
	rounded=0;
	for(i=0;i<64;i++) 
	{
		if(palette_rnd) 
		{
			data=0;

			//get red portion and round it
			temp = (palette[i].red & 0x01);		//see if this needs rounding
			if(palette[i].red == 31) 			//if value == 63, then we can't round up
			{
				temp = 0;
				rounded = 1;
			}
			data = (palette[i].red >> 1) + (temp & rounded);				//round up if necessary
			rounded = (temp ^ rounded);			//reset rounded down flag after rounding up

			//get green portion and round it
			temp = (palette[i].green & 0x01);	//see if this needs rounding
			if(palette[i].green == 31) 			//if value == 63, then we can't round up
			{
				temp = 0;
				rounded = 1;
			}
			data = (data<<4) + (palette[i].green >> 1) + (temp & rounded);	 //round up if necessary
			rounded = (temp ^ rounded);			//reset rounded down flag after rounding up

			//get blue portion and round it off
			temp = (palette[i].blue & 0x01);	//see if this needs rounding
			if(palette[i].blue == 31) 			//if value == 63, then we can't round up
			{
				temp = 0;
				rounded = 1;
			}
			data = (data<<4) + (palette[i].blue >> 1) + (temp & rounded);				//round up if necessary
			rounded = (temp ^ rounded);			//reset rounded down flag after rounding up

			//store converted color
			new_palette[i] = data;
		}
		else
		{
			data=0;

			data = (palette[i].red >> 1);
			data = (data<<4) + (palette[i].green >> 1);
			data = (data<<4) + (palette[i].blue >> 1);

			//store converted color
			new_palette[i] = data;
		}
	}//loop through all colors

} //end of ConvertPalette

//---------------------------------------------------------------------------
void addcomment(FILE *fp, unsigned int ratio,unsigned int size,unsigned int compress) {
	if (compress==1)
		fprintf(fp, "// rle compression %d bytes (%d%%)\n", size,ratio);
	else if (compress==2)
		fprintf(fp, "// ple compression %d bytes (%d%%)\n", size,ratio);
	else if (compress==3)
		fprintf(fp, "// dan1 compression %d bytes (%d%%)\n", size,ratio);
	else if (compress==4)
		fprintf(fp, "// dan2 compression %d bytes (%d%%)\n", size,ratio);
	else if (compress==5)
		fprintf(fp, "// dan3 compression %d bytes (%d%%)\n", size,ratio);
}

int Convert2Pic(char *filebase, unsigned char *buffer, unsigned int *tilemap, unsigned int *palet, unsigned int *tilecol, int num_tiles, int mapw, int maph, int savemap, int savepal)
{
	char filenamec[256],filenameh[256],filenamef[256];
	unsigned int val16b;
	unsigned char bufsw1[8];
	unsigned char value, minv,maxv;
	unsigned char valtil[8];
	unsigned char *tiMem,*tiMemEncode,*coMem,*coMemEncode, *maMem, *maMemEncode;
	int x,y,t,b;
    int lenencode,lenencode1,lenencode2;
	int lenencodet1,lenencodet2,lenencodet3;
	FILE *fpc,*fph;
	unsigned char bitplanes,mask;
	
	int len = strlen(filebase)-1;
	int i;
	for (i = len; i >= 0; i--) {
		if (filebase[i] == '/') {
			break;
		}
	}
	if (i==-1)
	{
		sprintf(filenamef,"%sgfx",filebase);
	}
	else
	{
		sprintf(filenamef,"%sgfx",&filebase[i+1]);
	}

	sprintf(filenamec,"%sgfx.inc",&filebase[i+1]);
	sprintf(filenameh,"%sgfx.h",&filebase[i+1]);

	sprintf(filenamec,"%sgfx.inc",filebase);
	sprintf(filenameh,"%sgfx.h",filebase);

	if (quietmode == 0) {
		printf("\nSaving gfx source file: [%s]",filenamec);
		printf("\nSaving gfx header file: [%s]",filenameh);
	}
	fpc = fopen(filenamec,"wb");
	fph = fopen(filenameh,"wb");

	if(fpc==NULL)
	{
		printf("\nERROR: Can't open file [%s] for writing\n",filenamec);
		return 0;
	}
	if(fph==NULL)
	{
		printf("\nERROR: Can't open file [%s] for writing\n",filenameh);
		return 0;
	}
	if (bmpmode) num_tiles=768;
	
    //tiMem = (unsigned char *) malloc(num_tiles*8);
    //tiMemEncode = (unsigned char *) malloc(num_tiles*8);
    tiMem = (unsigned char *) malloc(256*8*3); 			// max number for bitmap mode or f18a emc3 mode
    tiMemEncode = (unsigned char *) malloc(256*8*3);	// max number for bitmap mode or f18a emc3 mode
	coMem = (unsigned char *) malloc(num_tiles*8);
    coMemEncode = (unsigned char *) malloc(num_tiles*8);
    maMem = (unsigned char *) malloc(mapw*maph);
    maMemEncode = (unsigned char *) malloc(mapw*maph);

	if ( (tiMem==NULL) || (coMem==NULL) || (maMem==NULL) || 
		 (tiMemEncode==NULL) || (coMemEncode==NULL) || (maMemEncode==NULL)  )
	{
		printf("\nERROR: Could not allocate enough memory\n");
		return 0;
	}
	
	if (quietmode == 0) {
		printf("\nDecode for %d tiles...\n",num_tiles);
	}

	// different check for ecm1-3
	if (ecmmode>1)
	{
		// grab number of planes
		bitplanes=(ecmmode-1);
		
		for(t=0;t<num_tiles;t++) //loop through tiles
		{
			for(b=0;b<bitplanes;b++) //loop through bitplane pairs
			{
				//get bit-mask
				mask = 1 << b;
				for(y=0;y<8;y++)
				{
					value = 0;

					//get row of bit-plane and save row
					for(x=0;x<8;x++)
					{
						value = value << 1;
						if(buffer[t*64 + y*8 + x] & mask)
							value = value+1;
					}
					*(tiMem+y+t*8+(b*256*8))=value;
				}
			}
			*(coMem+t)=*(tilecol+t);    // tile priority
		}
	}
	else
	{
		for(t=0;t<num_tiles;t++) { //loop through tiles
			for(y=0;y<8;y++) {
				value=0; minv=0xFF; maxv=0x00;

				// get the 8 values
				for (x=0;x<8;x++) {
					valtil[x]=buffer[t*64 + y*8 + x];
					// get min and max value
					if (valtil[x]<minv)
						minv=valtil[x];
					if (valtil[x]>maxv)
						maxv=valtil[x];
				}
				// put 1 if max color
				if (maxv <= 0x01) maxv=0xF;
				if (minv == 0xff) minv=1;
				for (x=0;x<8;x++) {
					if (valtil[x]==maxv)
						value=value | (1<<(7-x));
				}
				*(tiMem+y+t*8)=value;
				if (gramode!=1)
					*(coMem+y+t*8)=(maxv<<4) | (minv);    // FG color | BG color 
			}
		}
		if (gramode==1)
		{
			for (t=0;t<32;t++)
			 *(coMem+t)=*(tilecol+t);
		}
	}

	// sprites are 16x16 but we need to swap tile 2<>3  
	if (sprmode)
	{
		// different check for ecm1-3
		if (ecmmode>1)
		{
			// grab number of planes
			bitplanes=(ecmmode-1);
		
			for(t=0;t<num_tiles;t+=4)  //loop through tiles
			{
				for(b=0;b<bitplanes;b++) //loop through bitplane pairs
				{
					memcpy(bufsw1,(tiMem+(t+1)*8+(b*256*8)),8);
					memcpy((tiMem+(t+1)*8+(b*256*8)),(tiMem+(t+2)*8+(b*256*8)),8);
					memcpy((tiMem+(t+2)*8+(b*256*8)),bufsw1,8);
				}
			}
		}
		else 
		{
			for(t=0;t<num_tiles;t+=4) { //loop through tiles
				memcpy(bufsw1,(tiMem+(t+1)*8),8);
				memcpy((tiMem+(t+1)*8),(tiMem+(t+2)*8),8);
				memcpy((tiMem+(t+2)*8),bufsw1,8);
			}
		}
	}

    // Get map if possible (so not in sprite mode)
	if (tilemap!=NULL)
	{
		for (t=0;t<mapw*maph;t++) {
			// if bitmap mode, adapt it
			if (bmpmode)
			{
				if (tilemap[t]>=256*2)
					*(maMem+t)=tilemap[t]-256*2;
				else if (tilemap[t]>=256)
					*(maMem+t)=tilemap[t]-256;
				else
					*(maMem+t)=tilemap[t];
			}
			else
				*(maMem+t)=tilemap[t];
		}
    }

	// write files regarding compression type
	lenencode=num_tiles*8;lenencode1=num_tiles*8;lenencode2=mapw*maph;
	lenencodet1=lenencodet2=lenencodet3=num_tiles*8;
	if (ecmmode>1)
	{
		lenencode1=num_tiles;
	}
	if (compress==0) { // no compression
		memcpy(tiMemEncode,tiMem,lenencode);
		if (gramode==1)
		{
			memcpy(coMemEncode,coMem,32);
			lenencode1=32;
		}
		else
			memcpy(coMemEncode,coMem,lenencode1);
		memcpy(maMemEncode,maMem,lenencode2);
	}
	else if (compress==1) { // rle compression
		if (ecmmode>1)
		{
			lenencodet1=rleCompress( tiMem,tiMemEncode,lenencode);
			lenencodet2=rleCompress( tiMem+256*8,tiMemEncode+256*8,lenencode);
			lenencodet3=rleCompress( tiMem+256*8*2,tiMemEncode+256*8*2,lenencode);
		}
		else
			lenencode=rleCompress( tiMem,tiMemEncode,lenencode);
		if (gramode==1)
		{
			memcpy(coMemEncode,coMem,32);
			lenencode1=32;
		}
		else
			lenencode1=rleCompress(coMem,coMemEncode,lenencode1);
        if (savemap)
            lenencode2=rleCompress(maMem,maMemEncode,lenencode2);
        else
            memcpy(maMemEncode,maMem,lenencode2);
	}
	else if (compress==2) { // ple compression
		if (ecmmode>1)
		{
			lenencodet1=pleCompress( tiMem,tiMemEncode,lenencode);
			lenencodet2=pleCompress( tiMem+256*8,tiMemEncode+256*8,lenencode);
			lenencodet3=pleCompress( tiMem+256*8*2,tiMemEncode+256*8*2,lenencode);
		}
		else
			lenencode=pleCompress( tiMem,tiMemEncode,lenencode);
		if (gramode==1)
		{
			memcpy(coMemEncode,coMem,32);
			lenencode1=32;
		}
		else
			lenencode1=pleCompress(coMem,coMemEncode,lenencode1);
        if (savemap)
            lenencode2=pleCompress(maMem,maMemEncode,lenencode2);
        else
            memcpy(maMemEncode,maMem,lenencode2);
	}
	else if (compress==3) { // dan1 compression
		if (ecmmode>1)
		{
			lenencodet1=dan1Compress( tiMem,tiMemEncode,lenencode);
			lenencodet2=dan1Compress( tiMem+256*8,tiMemEncode+256*8,lenencode);
			lenencodet3=dan1Compress( tiMem+256*8*2,tiMemEncode+256*8*2,lenencode);
		}
		else
        {
			lenencode=dan1Compress( tiMem,tiMemEncode,lenencode);
        }
		if (gramode==1)
		{
			memcpy(coMemEncode,coMem,32);
			lenencode1=32;
		}
		else
        {
			lenencode1=dan1Compress(coMem,coMemEncode,lenencode1);
        }
        if (savemap)
        {
            lenencode2=dan1Compress(maMem,maMemEncode,lenencode2);
        }
        else
        {
            memcpy(maMemEncode,maMem,lenencode2);
        }
    }		
	else if (compress==4) { // dan2 compression
		if (ecmmode>1)
		{
			lenencodet1=dan2Compress( tiMem,tiMemEncode,lenencode);
			lenencodet2=dan2Compress( tiMem+256*8,tiMemEncode+256*8,lenencode);
			lenencodet3=dan2Compress( tiMem+256*8*2,tiMemEncode+256*8*2,lenencode);
		}
		else
        {
			lenencode=dan2Compress( tiMem,tiMemEncode,lenencode);
        }
		if (gramode==1)
		{
			memcpy(coMemEncode,coMem,32);
			lenencode1=32;
		}
		else
        {
			lenencode1=dan2Compress(coMem,coMemEncode,lenencode1);
        }
        if (savemap)
        {
            lenencode2=dan2Compress(maMem,maMemEncode,lenencode2);
        }
        else
        {
            memcpy(maMemEncode,maMem,lenencode2);
        }
    }	
	else if (compress==5) { // dan3 compression
		if (ecmmode>1)
		{
			lenencodet1=dan3Compress( tiMem,tiMemEncode,lenencode);
			lenencodet2=dan3Compress( tiMem+256*8,tiMemEncode+256*8,lenencode);
			lenencodet3=dan3Compress( tiMem+256*8*2,tiMemEncode+256*8*2,lenencode);
		}
		else
        {
			lenencode=dan3Compress( tiMem,tiMemEncode,lenencode);
        }
		if (gramode==1)
		{
			memcpy(coMemEncode,coMem,32);
			lenencode1=32;
		}
		else
        {
			lenencode1=dan3Compress(coMem,coMemEncode,lenencode1);
        }
        if (savemap)
        {
            lenencode2=dan3Compress(maMem,maMemEncode,lenencode2);
        }
        else
        {
            memcpy(maMemEncode,maMem,lenencode2);
        }
    }	
	
	// write to files
	fprintf(fpc,"// Generated by gfx2col\n\n");
	
	if (ecmmode>1)
	{
		addcomment(fpc, (((num_tiles*8)-lenencodet1)*100)/(num_tiles*8),lenencodet1,compress);
		fprintf(fpc, "const unsigned char TILP1%s[%d]={\n", filenamef,lenencodet1);
		// write characters & colors
		for (t = 0; t < lenencodet1; t++) {
			if(t) {
				if((t & 31) == 0)
					fprintf(fpc, ",\n");
				else
					fprintf(fpc, ", ");
			}
			fprintf(fpc, "0x%02X", *(tiMemEncode+t));
		}
		fprintf(fpc, "\n};\n\n");
		if (ecmmode>2)
		{
			addcomment(fpc, (((num_tiles*8)-lenencodet2)*100)/(num_tiles*8),lenencodet2,compress);
			fprintf(fpc, "const unsigned char TILP2%s[%d]={\n", filenamef,lenencodet2);
			// write characters & colors
			for (t = 0; t < lenencodet2; t++) {
				if(t) {
					if((t & 31) == 0)
						fprintf(fpc, ",\n");
					else
						fprintf(fpc, ", ");
				}
				fprintf(fpc, "0x%02X", *(tiMemEncode+t+256*8));
			}
			fprintf(fpc, "\n};\n\n");
		}
		if (ecmmode>3)
		{
			addcomment(fpc, ((num_tiles*8-lenencodet3)*100)/(num_tiles*8),lenencodet3,compress);
			fprintf(fpc, "const unsigned char TILP3%s[%d]={\n", filenamef,lenencodet3);
			// write characters & colors
			for (t = 0; t < lenencodet3; t++) {
				if(t) {
					if((t & 31) == 0)
						fprintf(fpc, ",\n");
					else
						fprintf(fpc, ", ");
				}
				fprintf(fpc, "0x%02X", *(tiMemEncode+t+256*8*2));
			}
			fprintf(fpc, "\n};\n\n");
		}
	}
	else
	{
		addcomment(fpc, ((num_tiles*8-lenencode)*100)/(num_tiles*8),lenencode,compress);
		fprintf(fpc, "const unsigned char TIL%s[%d]={\n", filenamef,lenencode);
		// write characters & colors
		for (t = 0; t < lenencode; t++) {
			if(t) {
				if((t & 31) == 0)
					fprintf(fpc, ",\n");
				else
					fprintf(fpc, ", ");
			}
			fprintf(fpc, "0x%02X", *(tiMemEncode+t));
		}
		fprintf(fpc, "\n};\n\n");
	}
	
	// do that only if it is not a sprite
	if (sprmode==0) 
	{
		if (gramode!=1)
		{
			if (ecmmode>1)
			{
				addcomment(fpc, ((num_tiles-lenencode1)*100)/(num_tiles),lenencode1,compress);
			}
			else
				addcomment(fpc, ((num_tiles*8-lenencode1)*100)/(num_tiles*8),lenencode1,compress);
		}
		fprintf(fpc, "const unsigned char COL%s[%d]={\n", filenamef,lenencode1);
		for (t = 0; t < lenencode1; t++) {
			if(t) {
				if((t & 31) == 0)
					fprintf(fpc, ",\n");
				else
					fprintf(fpc, ", ");
			}
			fprintf(fpc, "0x%02X", *(coMemEncode+t));
		}
		fprintf(fpc, "\n};\n\n");
			
		// write map if needed
		if (savemap) {
			addcomment(fpc, ((mapw*maph-lenencode2)*100)/(mapw*maph),lenencode2,compress);
			fprintf(fpc, "const unsigned char MAP%s[%d]={\n", filenamef,lenencode2);
			for (t = 0; t < lenencode2; t++) {
				if(t) {
					if((t & 31) == 0)
						fprintf(fpc, ",\n");
					else
						fprintf(fpc, ", ");
				}
				fprintf(fpc, "0x%02X", *(maMemEncode+t));
			}
			fprintf(fpc, "\n};\n\n");
		}
	}

	// do that only if we need palette
	if (savepal) 
	{
		if (output_palette==64) 
		{
			fprintf(fpc, "const unsigned char PAL%s[%d]={\n", filenamef,(ecmmode==1) ? 16*2 : 64*2);
			if (ecmmode==1)
			{
				y=15;
				for (t = 0; t <  16; t++) 
				{
					if (t) 
					{
						if((t & 15) == 0)
							fprintf(fpc, ",\n");
						else
							fprintf(fpc, ", ");
					}

					val16b=*(palet+t);
					fprintf(fpc, "0x%02X", (val16b & 0xF00)>>8);
					fprintf(fpc, ",0x%02X", (val16b & 0xFF));
				}
			}
			else
			{
				y = (1<<(ecmmode-1))-1;
				for (t = 0; t < 64; t++) 
				{
					if (t) 
					{
						if((t & y) == 0)
							fprintf(fpc, ", // PAL %d\n",(t/(y+1))-1);
						else
							fprintf(fpc, ", ");
					}

					val16b=*(palet+t);
					fprintf(fpc, "0x%02X", (val16b & 0xF00)>>8);
					fprintf(fpc, ",0x%02X", (val16b & 0xFF));
				}
			}
			fprintf(fpc, "  // PAL %d\n};\n\n",(t/(y+1))-1);
		}
	}

	// write hearder file
	fprintf(fph, "#ifndef %s_INC_\n", filenamef);
	fprintf(fph, "#define %s_INC_\n\n", filenamef);
	if (ecmmode>1)
	{
		fprintf(fph, "#define SZTILP1%s %d\n", filenamef,lenencodet1);
		fprintf(fph, "#define SZTILP2%s %d\n", filenamef,lenencodet2);
		fprintf(fph, "#define SZTILP3%s %d\n", filenamef,lenencodet3);

	}
	else
		fprintf(fph, "#define SZTIL%s %d\n", filenamef,lenencode);
	// do that only if it is not a sprite
	if (sprmode==0) 
	{

		fprintf(fph, "#define SZCOL%s %d\n", filenamef,lenencode1);
		if (savemap)
			fprintf(fph, "#define SZMAP%s %d\n", filenamef,lenencode2);
		fprintf(fph,"\n");
	}
	if (ecmmode>1)
	{
		fprintf(fph, "extern const unsigned char TILP1%s[];\n", filenamef);
		fprintf(fph, "extern const unsigned char TILP2%s[];\n", filenamef);
		fprintf(fph, "extern const unsigned char TILP3%s[];\n", filenamef);
	}
	else
		fprintf(fph, "extern const unsigned char TIL%s[];\n", filenamef);
	// do that only if it is not a sprite
	if (sprmode==0) 
	{
		fprintf(fph, "extern const unsigned char COL%s[];\n", filenamef);
		if (savemap)
			fprintf(fph, "extern const unsigned char MAP%s[];\n", filenamef);
	}
	if (savepal)
	{
		if (output_palette==64) 
		{
			fprintf(fph, "extern const unsigned char PAL%s[];\n", filenamef);
		}
	}

	fprintf(fph, "\n\n");
	fprintf(fph, "#endif\n");
		
	fclose(fpc);fclose(fph);

    // free memory
    if (maMemEncode) free(maMemEncode);
    if (maMem) free(maMem);
    if (coMemEncode) free(coMemEncode);
    if (coMem) free(coMem);
    if (tiMemEncode) free(tiMemEncode);
    if (tiMem) free(tiMem);

	return -1;
} //end of Convert2Pic


//---------------------------------------------------------------------------
void PrintOptions(char *str) {
	printf("\n\nUsage : gfx2col [options] bmp/pcx/tga filename ...");
	printf("\n  where filename is a 256 color PNG, BMP, PCX or TGA file");
	printf("\n   and palette is only the 1st 16 colors in bitmap or");
	printf("\n   the 1st 64 colors in bitmap for F18A mode.");
	
	if(str[0]!=0)
		printf("\nThe [%s] parameter is not recognized.",str);

	printf("\n\nOptions are:");
	printf("\n\n--- General options ---");
	printf("\n-c[no|rle|ple|dan1|dan2|dan3]    Compression method [no]");
	printf("\n\n--- Graphic options ---");
	printf("\n-s                               Generate sprite graphics");
	printf("\n-b                               Bitmap mode (no more 256 tiles limit)");
	printf("\n-g[m1|m2]                        TMS9918 Graphic mode (mode 2 or mode 1) [m2]");
	printf("\n-e[0|1|2|3]                      Enhanced Color Mode (F18A only) [0]");
	printf("\n-t                               Enable transparent tiles (color 0)");
	printf("\n\n--- Map options ---");
	printf("\n-m!                              Exclude map from output");
	printf("\n-m                               Convert the whole picture");
	printf("\n-mR!                             No tile reduction (not advised)");
	printf("\n-mn#              	           Generate the whole picture with an offset for tile number");
	printf("\n                   	            where # is the offset in decimal (0 to 2047)");
	printf("\n\n--- Palette options ---");
	printf("\n-p!                              Exclude palette from output");
	printf("\n-po                              Export palette (16 colors (ecm0) or 64 colors(ecm1-3)");
	printf("\n-pR                              Palette rounding");
	printf("\n\n--- File options ---");
	printf("\n-f[bmp|pcx|tga|png]              Convert a bmp or pcx or tga or png file [bmp]");
	printf("\n\n--- Misc options ---");
	printf("\n-q                               Quiet mode");
	printf("\n");
	
	printf("\nExample:");
	printf("\ngfx2col -crle -fpng -m myimage.png");
	printf("\n  will convert a myimage png file to a inc file with 8x8 tiles, rle compressed");
	printf("\n  and a map.");
} //end of PrintOptions()

//---------------------------------------------------------------------------
// M A I N 
int main(int argc, char **arg) {
	unsigned int palette[64];
	unsigned int colorspal[256];//,coltilopt[256];
	unsigned char colornumbers;
	
	int height, width;
	int xsize, ysize,xsize1, ysize1;
	pcx_picture image;

	unsigned char *buffer, *buff=NULL;
	unsigned int *tilemap,*timap=NULL;

	char filebase[256]="";
	char filename[256];

	int i, x,y; 

    int file_type=BMP_FILE;
    int tile_reduction=1;         // 0 = no tile reduction (warning !)
    int savemap=1;                // 1 = save the map
    int savepal=1;                // 1 = save the palette
    
	// Show something to begin :)
	if (quietmode == 0) {
		printf("\n==============================");
		printf("\n---gfx2col v"GFX2COLVERSION" "GFX2COLDATE"---");
		printf("\n------------------------------");
		printf("\n(c) 2018-2020 Alekmaul");
		printf("\n==============================\n");
	}

	//parse the arguments
	for(i=1;i<argc;i++)	
	{
		if(arg[i][0]=='-') 
		{
			if(arg[i][1]=='q') //quiet mode
			{
				quietmode=1;
			}
			else if(arg[i][1]=='t') // transparent tile mode 
			{
				transmode=1;
			}
			else if(arg[i][1]=='s') // sprite mode
			{
				sprmode=1;
				tile_reduction=0;
                savemap=0;          // Fix 200318 , no need for sprite
			}
			else if(arg[i][1]=='b') // bitmap mode
			{
				bmpmode=1;
			}			
			else if(arg[i][1]=='m') //map options
			{
				if( strcmp(&arg[i][1],"m") == 0)
				{
				}
				else if( strcmp(&arg[i][1],"m!") == 0)
				{
					savemap=0;
				}
				else if( strcmp(&arg[i][1],"mp") == 0)
				{
					highpriority=1;
				}
				else if(arg[i][2]=='n') //offset for tiles
				{
					offset_tile = atoi(&arg[i][3]);
				}
				else if( strcmp(&arg[i][1],"mR!") == 0)
				{
					tile_reduction=0;
				}
				else
				{
					PrintOptions(arg[i]);
					return 1;
				}
			}
			else if(arg[i][1]=='g')		// graphic mode
			{
				if( strcmp(&arg[i][1],"gm1") == 0)
				{
					gramode = 1; 
				}
                else //invalid option
                {
                    PrintOptions(arg[i]);
                    return 1;
                }
			}
			else if(arg[i][1]=='p') 	//palette options
			{
				if( strcmp(&arg[i][1],"p!") == 0)
				{
					savepal=0;
				}
				else if(arg[i][2]=='o') 		//palette output (64 colors)
				{
					output_palette=64;
				}
				else if(arg[i][2]=='R') // color rounded
				{
					palette_rnd=1;
				}
                else //invalid option
                {
                    PrintOptions(arg[i]);
                    return 1;
                }
			}
			else if(arg[i][1]=='e') 	//ecm mode
			{
				if(arg[i][2]=='o') 		//palette output (64 colors)
				{
					output_palette=64;
				}
				else if(arg[i][2]=='R') // color rounded
				{
					palette_rnd=1;
				}
				else if ( (arg[i][2]>='0') && (arg[i][2]<='3') )
				{
					ecmmode=1+arg[i][2]-48;
					output_palette=64;
				}
				else
				{
					PrintOptions(arg[i]);
					return 1;
				}
			}
			else if(arg[i][1]=='c')		//compression method
			{
				if( strcmp(&arg[i][1],"crle") == 0)
				{
					compress = 1; 
				}
				else if( strcmp(&arg[i][1],"cple") == 0)
				{
					compress = 2;
				}
				else if( strcmp(&arg[i][1],"cdan1") == 0)
				{
					compress = 3; // DAN1 compression
				}
				else if( strcmp(&arg[i][1],"cdan2") == 0)
				{
					compress = 4; // DAN2 compression
				}
				else if( strcmp(&arg[i][1],"cdan3") == 0)
				{
					compress = 5; // DAN3 compression
				}
                else //invalid option
                {
                    PrintOptions(arg[i]);
                    return 1;
                }
			}
			else if(arg[i][1]=='f') //file type specification
			{
				if( strcmp(&arg[i][1],"fpcx") == 0)
				{
					file_type = 2; // PCX,
				}
				else if( strcmp(&arg[i][1],"ftga") == 0)
				{
					file_type = 3; // TGA
				}
				else if( strcmp(&arg[i][1],"fpng") == 0)
				{
					file_type = 4; // PNG, evething else is bmp
				}
                else //invalid option
                {
                    PrintOptions(arg[i]);
                    return 1;
                }
			}
			else //invalid option
			{
				PrintOptions(arg[i]);
				return 1;
			}
		}
		else
		{
			//its not an option flag, so it must be the filebase
			if(filebase[0]!=0) // if already defined... there's a problem
			{
				PrintOptions(arg[i]);
				return 1;
			}
			else
				strcpy(filebase,arg[i]);
		}
	}

	if( filebase[0] == 0 ) {
		printf("\nERROR: You must specify a base filename.");
		PrintOptions("");
		return 1;
	}

	//Load picture
	if (filebase[strlen(filebase)-4] == '.') {
		filebase[strlen(filebase)-4] = '\0';
	}
	switch (file_type) {
		case 2 : // PCX
			sprintf(filename,"%s.pcx",filebase);
			if (quietmode == 0)
				printf("\nOpening graphics file: [%s]",filename);
			if(!PCX_Load(filename,(pcx_picture_ptr) &image))
				return 1;
			break;
		case 3 : // TGA
			sprintf(filename,"%s.tga",filebase);
			if (quietmode == 0)
				printf("\nOpening graphics file: [%s]",filename);
			if(!TGA_Load(filename,(pcx_picture_ptr) &image))
				return 1;
			break;
		case 4 : // PNG
			sprintf(filename,"%s.png",filebase);
			if (quietmode == 0)
				printf("\nOpening graphics file: [%s]",filename);
			if(!PNG_Load(filename,(pcx_picture_ptr) &image))
				return 1;
			break;
		default : // BMP for everithing else
			sprintf(filename,"%s.bmp",filebase);
			if (quietmode == 0)
				printf("\nOpening graphics file: [%s]",filename);
			if(!BMP_Load(filename,(pcx_picture_ptr) &image))
				return 1;
			break;
	}

	//convert the palette
	if (output_palette==64)
		ConvertPalette(image.palette, palette);
	
	height = image.header.height;
	width = image.header.width;
	xsize = width>>3; ysize = height>>3;
	
	//Print what the user has selected
	if (quietmode == 0) {
		printf("\n****** O P T I O N S ***************");
		if (sprmode)
			printf("\nSprite mode=ON");
		else {
			printf("\nSprite mode=OFF");
			if (transmode)
				printf("\nF18A Tile transparent mode=ON");
			else 
				printf("\nF18A Tile transparent mode=OFF");
			if (highpriority)
				printf("\nF18A Tile highpriority mode=ON");
			else
				printf("\nF18A Tile highpriority mode=OFF");
			if (ecmmode==0) 
			{
				if (bmpmode)
					printf("\nTMS9918 Bitmap mode2=ON");
				else {
					printf("\nTMS9918 Bitmap mode2=OFF");
					if (gramode == 0)
						printf("\nTMS9918 Graphic mode 2");
					else if (gramode == 1)
						printf("\nTMS9918 Graphic mode 1");
				}
			}
			if (tile_reduction)
				printf("\nOptimize tilemap=ON");
			else
				printf("\nOptimize tilemap=OFF");
		}
		if (ecmmode!=0) 
		{
			printf("\nF18A Enhanced Color Mode=%d",ecmmode-1);
		}
			
		if (file_type == 2)
			printf("\nPCX file: %dx%d pixels",width,height);
		else if (file_type == 3)
			printf("\nTGA file: %dx%d pixels",width,height);
		else if (file_type == 4)
			printf("\nPNG file: %dx%d pixels",width,height);
		else
			printf("\nBMP file: %dx%d pixels",width,height);

		if (compress == 0)
			printf("\nNo compression");
		else if (compress == 1)
			printf("\nRLE compression");
		else if (compress == 2)
			printf("\nPLE compression");
		else if (compress == 3)
			printf("\nDAN1 compression");
		else if (compress == 4)
			printf("\nDAN2 compression");
		else if (compress == 5)
			printf("\nDAN3 compression");

		if (output_palette)
			printf("\nPalette output=ON");
		else 
			printf("\nPalette output=OFF");

		printf("\n************************************");
	}
	fflush(stdout);

	if ( (bmpmode==1) && (width != 256) && (height != 192) )
	{
		printf("\nERROR : Image must have 256x192 pixel size in bitmap mode (%d,%d here).\n",width, height);
		return 1;
	}
		
	if (bmpmode) 
	{
		// prepare global map & tiles
		tilemap=(unsigned int *) malloc(32*24*sizeof(int));
		buffer = (unsigned char *) malloc( 768*8*8*sizeof(char) );
		ysize=0;

		// 3 parts for tiles in bitmap mode
        for (i=0;i<3;i++) {
			ysize1=8;xsize1=32;

			// Get tiles
            if (buff) free(buff);
            buff=ArrangeBlocks(image.buffer+i*256*64,256,64,8,&xsize1,&ysize1,8);
			if(buff==NULL)
			{
				printf("\nERROR:Not enough memory to do image operations...\n");
				return 1;
			
			}
			
			// Optimize map with current tile set
            if (timap) free (timap);
            timap=MakeMap(buff, colorspal, &ysize1, xsize1, ysize1, xsize1, ysize1, tile_reduction );
			if(timap==NULL) 
			{
				free(buff);
				printf("\nERROR:Not enough memory to do tile map optimizations..\n");
				return 1;
			}

			// load tiles
			ysize+=ysize1;
			if ( (ysize1>0)) {
				memcpy(buffer+i*256*8*8,buff,256*8*8);
							
				// change map at the end
                for (y=0;y<8;y++)
					for (x=0;x<32;x++)
						tilemap[x+y*32+i*256]=timap[x+y*32]+i*256;
			} // if ( (ysize>0))
		} // for (i=0;i<3;i++) {
		free(image.buffer);
		free(buff);
		free(timap);
	}
	else {
		// now re-arrange into a list of 8x8 blocks for easy conversion
		buffer=ArrangeBlocks( image.buffer, width, height, 8, &xsize, &ysize, 8);
		free(image.buffer);
		if(buffer==NULL)
		{
			printf("\nERROR:Not enough memory to do image operations...\n");
			return 1;
		}
			
		//make the tile map now
		tilemap=MakeMap(buffer, colorspal, &ysize, xsize, ysize, xsize, ysize, tile_reduction );
		if(tilemap==NULL) 
		{
			free(buffer);
			printf("\nERROR:Not enough memory to do tile map optimizations..\n");
			return 1;
		}

		// make color map now for mode 1 and if not F18A enhanced mode 1-3 (will erase colorspal, but don't care)
		if ( (ecmmode<=1) && (gramode==1) )
		{
			if ( MakeCol(buffer, tilemap,&colornumbers, colorspal,  &ysize,width/8, height/8) == 0)
			{
				return 1;
			}
			if (quietmode == 0) 
				printf("\nScreen uses %d colors.",colornumbers);
				
		}
	}

	if (ysize>0) 
	{
		if (quietmode == 0) 
		{
			if (tile_reduction)
				printf("\nReduced screen to %d tiles.",ysize);
			else
				printf("\nComputed screen with %d tiles.",ysize);
		}
		
		if ( (ysize>256) && (bmpmode==0) && (sprmode==0) )  // fix 200318 no control if in sprite mode
		{
			printf("\nERROR : Image must have less than 256 tiles (%d here).\n",ysize);
			return 1;
		}
		
		//convert pictures and save to file
		if(!Convert2Pic(filebase, buffer, tilemap, palette, colorspal, ysize, width/8, height/8,savemap,savepal)) 
		{
			//free up image & tilemap memory
			free(tilemap);
			free(buffer);
			return 1;
		}
	}

	//free up image & tilemap memory
	free(tilemap);
	free(buffer);

	if (quietmode == 0)
		printf("\nDone !\n\n");

	return 0;
}
<file_sep>#ifndef COMPTOOL_H
#define COMPTOOL_H

#include <stdio.h>
#include <stdlib.h>
#include <mem.h>

#define bool unsigned char
#define byte unsigned char
#define false 0
#define true 0xff

extern int pleCompress(byte *src,byte *dst,int n);

extern void addevent(void);
extern void claimevent(void);

#endif<file_sep>/*---------------------------------------------------------------------------------


	f18a test with no specific feature
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "f18atest.h"

//---------------------------------------------------------------------------------
// The NMI routine. Gets called 50 or 60 times per second 
// nothing to update for bitmap example
void nmi (void) {
}

//---------------------------------------------------------------------------------
void main (void) {
	// Check if f18a is available
	vdp_f18ainit();

	// display a message regarding result of test
	if (vdp_f18aok==1) {
		// put screen in mode 1 with no specific f18a stuffs
		vdp_f18asetmode1(0);
		
		// Put default char in VRAM and duplicate to all areas
		//  as we are going to write to line 8, it is in the first area
		vdp_setdefaultchar(FNTNORMAL);
		vdp_duplicatevram();
		vdp_fillvram(0x2000,0xF1,128*8);
		vdp_enablescr();
	
		// Print text as we are not going to do something else
		vdp_putstring(8,5,"F18A SUPPORT OK !");
	}
	else {
		// Put screen in text mode 2
		vdp_setmode2txt();
	
		// Put default char in VRAM and duplicate to all areas
		//  as we are going to write to line 8, it is in the second area
		vdp_setdefaultchar(FNTNORMAL);
		vdp_duplicatevram();
		vdp_fillvram(0x2000,0xf1,128*8); 	// Change color (or we will see nothing)
		vdp_enablescr();
	
		// Print text as we are not going to do something else
		vdp_putstring(8,5,"NO F18A SUPPORT...");
	}

	// Wait for nothing :P
	while(1) {
		// Wait Vblank
		vdp_waitvblank(1);
	}
	// startup module will issue a soft reboot if it comes here 
}
<file_sep>#include "compdan3.h"

//---------------------------------------------------------------------------
#define DAN3RAW_MIN	1
#define DAN3RAW_RANGE (1<<8)
#define DAN3RAW_MAX DAN3RAW_MIN + DAN3RAW_RANGE - 1

#define DAN3BIT_GOLOMG_MAX	7
#define DAN3BIT_OFFSET_MIN	9
#define DAN3BIT_OFFSET_MAX	16
#define DAN3MAX 256*1024
#define DAN3MAX_GAMMA		(1<<(DAN3BIT_GOLOMG_MAX+1)) - 2

#define DAN3BIT_OFFSET00	0
#define DAN3BIT_OFFSET0		1
#define DAN3BIT_OFFSET1		5
#define DAN3BIT_OFFSET2		8
#define DAN3MAX_OFFSET00	(1<<DAN3BIT_OFFSET00)
#define DAN3MAX_OFFSET0		(1<<DAN3BIT_OFFSET0) + DAN3MAX_OFFSET00
#define DAN3MAX_OFFSET1		(1<<DAN3BIT_OFFSET1)
#define DAN3MAX_OFFSET2		(1<<DAN3BIT_OFFSET2) + DAN3MAX_OFFSET1
#define DAN3MAX_OFFSET		(1<<DAN3BIT_OFFSET_MAX) + DAN3MAX_OFFSET2
#define DAN3BIT_OFFSET_NBR	DAN3BIT_OFFSET_MAX - DAN3BIT_OFFSET_MIN + 1

// MATCHES -
struct t_match
{
	int index;
	struct t_match *next;
};
struct t_match dan3matches[65536];

struct t_optimal
{
	int bits[DAN3BIT_OFFSET_NBR]; /* COST */
	int offset[DAN3BIT_OFFSET_NBR];
	int len[DAN3BIT_OFFSET_NBR];
} dan3optimals[DAN3MAX];

int DAN3BIT_OFFSET_NBR_ALLOWED;
int DAN3BIT_OFFSET_MAX_ALLOWED;
int DAN3BIT_OFFSET3;
int DAN3MAX_OFFSET3;
int dan3bit_index;
int dan3index_dest;
int dan3index_src;
int dan3bit_mask;

// - INITIALIZE MATCHES TABLE -
void dan3reset_matches(void)
{
	int i;
	for (i = 0;i < 65536;i++)
	{
		dan3matches[i].next = NULL;
	}
}

// REMOVE MATCHE(S) FROM MEMORY -
void dan3flush_match(struct t_match *match)
{
	struct t_match *node;
	struct t_match *head = match->next;
	while ((node = head) != NULL)
	{
		head = head->next;
		free(node);
	}
	match->next = NULL;
}

// - INSERT A MATCHE IN TABLE -
void dan3insert_match(struct t_match *match, int index)
{
	struct t_match *new_match = (struct t_match *) malloc( sizeof(struct t_match) );
	new_match->index = match->index;
	new_match->next = match->next;
	match->index = index;
	match->next = new_match;
}

void set_BIT_OFFSET3(int i)
{
	DAN3BIT_OFFSET3 = DAN3BIT_OFFSET_MIN + i;
	DAN3MAX_OFFSET3 = (1 << DAN3BIT_OFFSET3) + DAN3MAX_OFFSET2;
}

// WRITE DATA -
void dan3write_byte(byte value, byte *data_dest)
{
	data_dest[dan3index_dest++] = value;
}
void dan3write_bit(int value, byte *data_dest)
{
	if (dan3bit_mask == 0)
	{
		dan3bit_mask  = (unsigned char) 128;
		dan3bit_index = dan3index_dest;
		dan3write_byte((unsigned char) 0, data_dest);
	}
	if (value) data_dest[dan3bit_index] |= dan3bit_mask;
	dan3bit_mask >>= 1 ;
}
void dan3write_bits(int value, int size, byte *data_dest)
{
	int i;
	int mask = 1;
	for (i = 0 ; i < size ; i++)
	{
		mask <<= 1;
	}
	while (mask > 1)
	{
		mask >>= 1;
		dan3write_bit (value & mask,data_dest);
	}
}
void dan3write_golomb_gamma(int value, byte *data_dest)
{
	int i;
	value++;
	for (i = 4; i <= value; i <<= 1)
	{
		dan3write_bit(0,data_dest);
	}
	while ((i >>= 1) > 0)
	{
		dan3write_bit(value & i,data_dest);
	}
}
void dan3write_offset(int value, int option,byte *data_dest)
{
	value--;
	if (option == 1)
	{
		if (value >= DAN3MAX_OFFSET00)
		{
			dan3write_bit(1,data_dest);
			value -= DAN3MAX_OFFSET00;
			dan3write_bits(value, DAN3BIT_OFFSET0,data_dest);
		}
		else
		{
			dan3write_bit(0,data_dest);
			dan3write_bits(value, DAN3BIT_OFFSET00,data_dest);
		}
	}
	else
	{
		if (value >= DAN3MAX_OFFSET2)
		{
			dan3write_bit(1,data_dest);
			dan3write_bit(1,data_dest);
			value -= DAN3MAX_OFFSET2;
			dan3write_bits(value >> DAN3BIT_OFFSET2, DAN3BIT_OFFSET3 - DAN3BIT_OFFSET2,data_dest);
			dan3write_byte((unsigned char) (value & 255),data_dest);; /* BIT_OFFSET2 = 8 */
		}
		else
		{
			if (value >= DAN3MAX_OFFSET1)
			{
				dan3write_bit(0,data_dest);;
				value -= DAN3MAX_OFFSET1;
				dan3write_byte((unsigned char) (value & 255),data_dest); /* BIT_OFFSET2 = 8 */
			}
			else
			{
				dan3write_bit(1,data_dest);
				dan3write_bit(0,data_dest);
				dan3write_bits(value, DAN3BIT_OFFSET1,data_dest);
			}
		}
	}
}
void dan3write_literal(unsigned char c,byte *data_dest)
{
	dan3write_bit(1,data_dest);
	dan3write_byte(c,data_dest);
}
void dan3write_literals_length(int length,byte *data_dest)
{
	dan3write_bit(0,data_dest);
	dan3write_bits(0, DAN3BIT_GOLOMG_MAX,data_dest);
	dan3write_bit(1,data_dest);
	length -= DAN3RAW_MIN;
	dan3write_byte((unsigned char) length,data_dest);
}
void dan3write_doublet(int length, int offset,byte *data_dest)
{
	dan3write_bit(0,data_dest);
	dan3write_golomb_gamma(length,data_dest);
	dan3write_offset(offset, length,data_dest);
}
void dan3write_end(byte *data_dest)
{
	dan3write_bit(0,data_dest);
	dan3write_bits(0, DAN3BIT_GOLOMG_MAX,data_dest);
	dan3write_bit(0,data_dest);
}

void dan3write_lz(byte *data_src, byte *data_dest,int subset)
{
	int i, j;
	int index;
	dan3index_dest = 0;
	dan3bit_mask = 0;
	dan3write_bits(0xFE, subset + 1,data_dest);
	dan3write_byte(data_src[0],data_dest);
	for (i = 1;i < dan3index_src;i++)
	{
		if (dan3optimals[i].len[subset] > 0)
		{
			index = i -  dan3optimals[i].len[subset] + 1;
			if (dan3optimals[i].offset[subset] == 0)
			{
				if (dan3optimals[i].len[subset] == 1)
				{
					dan3write_literal(data_src[index],data_dest);
				}
				else
				{
					dan3write_literals_length(dan3optimals[i].len[subset],data_dest);
					for (j = 0;j < dan3optimals[i].len[subset];j++)
					{
						dan3write_byte(data_src[index + j], data_dest);
					}
				}
			}
			else
			{
				dan3write_doublet(dan3optimals[i].len[subset], dan3optimals[i].offset[subset],data_dest);
			}
		}
	}
	dan3write_end(data_dest);
	//write_destination();
}

// - GOLOMB GAMMA LIMIT TO 254 -
int golomb_gamma_bits(int value)
{
	int bits = 0;
	value++;
	while (value > 1)
	{
		bits += 2;
		value >>= 1;
	}
	return bits;
}

int dan3count_bits(int offset, int len)
{
	int bits = 1 + golomb_gamma_bits(len);
	if (len == 1)
	{
		if (DAN3BIT_OFFSET00 == -1)
		{
			return bits + DAN3BIT_OFFSET0;
		}
		else
		{
			return bits + 1 + (offset > DAN3MAX_OFFSET00 ? DAN3BIT_OFFSET0 : DAN3BIT_OFFSET00);
		}
	}
	return bits + 1 + (offset > DAN3MAX_OFFSET2 ? 1 + DAN3BIT_OFFSET3 : (offset > DAN3MAX_OFFSET1 ? DAN3BIT_OFFSET2 : 1 + DAN3BIT_OFFSET1));
}

void update_optimal(int index, int len, int offset)
{
	int i;
	int cost;
	i = DAN3BIT_OFFSET_NBR_ALLOWED - 1;
	while (i >= 0)
	{
		if (offset == 0)
		{
			if (index > 0)
			{
				if (len == 1)
				{
					dan3optimals[index].bits[i] = dan3optimals[index-1].bits[i] + 1 + 8;
					dan3optimals[index].offset[i] = 0;
					dan3optimals[index].len[i] = 1;
				}
				else
				{
					cost = dan3optimals[index-len].bits[i] + 1 + DAN3BIT_GOLOMG_MAX + 1 + 8 + len * 8;
					if (dan3optimals[index].bits[i] > cost)
					{
						dan3optimals[index].bits[i] = cost;
						dan3optimals[index].offset[i] = 0;
						dan3optimals[index].len[i] = len;
					}
				}
			}
			else
			{
				dan3optimals[index].bits[i] = 8;
				dan3optimals[index].offset[i] = 0;
				dan3optimals[index].len[i] = 1;
			}
		}
		else
		{
			if (offset > DAN3MAX_OFFSET1)
			{
				set_BIT_OFFSET3(i);
				if (offset > DAN3MAX_OFFSET3) break;
			}
			cost = dan3optimals[index-len].bits[i] + dan3count_bits(offset, len);
			if (dan3optimals[index].bits[i] > cost)
			{
				dan3optimals[index].bits[i] = cost;
				dan3optimals[index].offset[i] = offset;
				dan3optimals[index].len[i] = len;
			}
		}
		i--;
	}
}

// - REMOVE USELESS FOUND OPTIMALS -
void dan3cleanup_optimals(int subset)
{
	int j;
	int i = dan3index_src - 1;
	int len;
	while (i > 1)
	{
		len = dan3optimals[i].len[subset];
		for (j = i - 1; j > i - len;j--)
		{
			dan3optimals[j].offset[subset] = 0;
			dan3optimals[j].len[subset] = 0;
		}
		i = i - len;
	}
}

// - LZ ENCODE -
void dan3lzss_slow(byte *data_src,byte *data_dest)
{
	//int temp_bits;
	int best_len;
	int len;
	int i, j, k;
	int offset;
	int match_index, prev_match_index = -1;
	int bits_minimum_temp, bits_minimum;
	struct t_match *match;
	dan3reset_matches();
	update_optimal(0, 1, 0);
	i = 1;
	while (i < dan3index_src)
	{
		// TRY LITERALS 
		update_optimal(i, 1, 0);
		// STRING OF LITERALS 
        if (i >= DAN3RAW_MIN)
        {
            j = DAN3RAW_MAX;
            if (j > i) j = i;
            if (DAN3RAW_MIN == 1)
            {
                for (k = j ; k > DAN3RAW_MIN; k--)
                {
                    update_optimal(i, k, 0);
                }
            }
            else
            {
                // RAW MINIMUM > 1
                for (k = j ; k >= DAN3RAW_MIN; k--)
                {
                    update_optimal(i, k, 0);
                }
            }
        }
		// LZ MATCH OF 1
		j = (DAN3BIT_OFFSET00 == -1 ? (1 << DAN3BIT_OFFSET0) : DAN3MAX_OFFSET0);
		if (j > i) j = i;
		for (k = 1; k <= j; k++)
		{
			if (data_src[i] == data_src[i-k])
			{
				update_optimal(i, 1, k);
			}
		}
		// LZ MATCH OF 2+ 
		match_index = ((int) data_src[i-1]) << 8 | ((int) data_src[i] & 255);
		match = &dan3matches[match_index];
		if (prev_match_index == match_index /*&& bFAST == TRUE*/ && dan3optimals[i-1].offset[0] == 1 && dan3optimals[i-1].len[0] > 2)
		{
			len = dan3optimals[i-1].len[0];
			if (len < DAN3MAX_GAMMA)
				update_optimal(i, len + 1, 1);
		}
		else
		{
			best_len = 1;
			for (;match->next != NULL; match = match->next)
			{
				offset = i - match->index;
				if (offset > DAN3MAX_OFFSET)
				{
					dan3flush_match(match);
					break;
				}
				for (len = 2;len <= DAN3MAX_GAMMA;len++)
				{
					update_optimal(i, len, offset);
					//best_len = len;
					if (i < offset + len || data_src[i-len] != data_src[i-len-offset])
					{
						break;
					}
				}
				//if (bFAST && best_len > 255) break;
                if (best_len > 255) break;
			}
		}
		//prev_match_index = match_index;
		dan3insert_match(&dan3matches[match_index], i);
		i++;
	}
	bits_minimum = dan3optimals[dan3index_src-1].bits[0];
	j = 0;
	for (i = 0;i < DAN3BIT_OFFSET_NBR_ALLOWED;i++)
	{
		bits_minimum_temp = dan3optimals[dan3index_src-1].bits[i];
		if (bits_minimum_temp < bits_minimum)
		{
			bits_minimum = bits_minimum_temp;
			j = i;
		}
	}
	set_BIT_OFFSET3(j);
	dan3cleanup_optimals(j);
	dan3write_lz(data_src,data_dest,j);

	len = (1 + j + bits_minimum + 2 + DAN3BIT_GOLOMG_MAX + 7) / 8;
}

// - SET MAXIMUM BITS ALLOWED TO ENCODE OFFSET
void set_max_bits_allowed(int bits)
{
	if (bits > DAN3BIT_OFFSET_MAX) bits = DAN3BIT_OFFSET_MAX;
	if (bits < DAN3BIT_OFFSET_MIN) bits = DAN3BIT_OFFSET_MIN;
	DAN3BIT_OFFSET_MAX_ALLOWED = bits;
	DAN3BIT_OFFSET_NBR_ALLOWED = DAN3BIT_OFFSET_MAX_ALLOWED - DAN3BIT_OFFSET_MIN + 1;
}

int dan3Compress(byte *src,byte *dst,int n)
{
    size_t count;

	// SET MAX BITS FOR BIG OFFSET VALUES -
    set_max_bits_allowed(DAN3BIT_OFFSET_MAX);

	// Initialize Matches Array
    dan3index_src=n;

	// Apply compression
    dan3lzss_slow(src,dst);

    // compute ratio
    count=dan3index_dest;

    return count;
}
<file_sep>/*---------------------------------------------------------------------------------


	scoring functions demo
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "scoring.h"

score_t scoretst,scoretst1;

//---------------------------------------------------------------------------------
// The NMI routine. Gets called 50 or 60 times per second 
// nothing to update for Input example
void nmi (void) {
}

//---------------------------------------------------------------------------------
void main (void) {
	// Put screen in text mode 2
	vdp_setmode2txt();
	
	// Put default char in VRAM and duplicate to all areas
	//  as we are going to write to line 10, it is in the second area
	vdp_setdefaultchar(FNTNORMAL);
	vdp_duplicatevram();
	vdp_fillvram(0x2000,0xf1,128*8); // Change color (or we will see nothing)
	vdp_enablescr();
	
	// Clear the score
	scoretst.hi=18;scoretst.lo=900;
	sys_scoclear(&scoretst);
	vdp_putstring(2,2,"score hi xxxxx score lo xxxx");
	vdp_putstring(11,2,sys_str(scoretst.hi));vdp_putstring(26,2,sys_str(scoretst.lo));
	
	// Add a value
	sys_scoadd(&scoretst,0x4DB);
	vdp_putstring(2,4,"score hi xxxxx score lo xxxx");
	vdp_putstring(11,4,sys_str(scoretst.hi));vdp_putstring(26,4,sys_str(scoretst.lo));

	// Add more than 10000
	sys_scoadd(&scoretst,0x2710);
	vdp_putstring(2,6,"score hi xxxxx score lo xxxx");
	vdp_putstring(11,6,sys_str(scoretst.hi));vdp_putstring(26,6,sys_str(scoretst.lo));
	vdp_putstring(11,7,sys_scostr(&scoretst,8));

	// Compare two scores
	scoretst.hi=18;scoretst.lo=900;
	scoretst1.hi=17;scoretst1.lo=900;
	if (sys_scocmp(&scoretst,&scoretst1)==0xFF) vdp_putstring(2,12,"1 scores equals");
	else if (sys_scocmp(&scoretst,&scoretst1)==0)  vdp_putstring(2,12,"1 scoretst higher");
	else if (sys_scocmp(&scoretst,&scoretst1)==1)  vdp_putstring(2,12,"1 scoretst lower");
	
	scoretst1.hi=18;scoretst1.lo=901;
	if (sys_scocmp(&scoretst,&scoretst1)==0xFF)  vdp_putstring(2,13,"2 scores equals");
	else if (sys_scocmp(&scoretst,&scoretst1)==0)  vdp_putstring(2,13,"2 scoretst higher");
	else if (sys_scocmp(&scoretst,&scoretst1)==1)  vdp_putstring(2,13,"2 scoretst lower");
	
	scoretst1.hi=19;scoretst1.lo=900;
	if (sys_scocmp(&scoretst,&scoretst)==0xFF)  vdp_putstring(2,14,"3 scores equals");
	else if (sys_scocmp(&scoretst,&scoretst1)==0)  vdp_putstring(2,14,"3 scoretst higher");
	else if (sys_scocmp(&scoretst,&scoretst1)==1)  vdp_putstring(2,14,"3 scoretst lower");

	// Wait for nothing :P
	while(1) {
		vdp_waitvblank(1);
	}
	// startup module will issue a soft reboot if it comes here 
}
<file_sep>cmake_minimum_required (VERSION 3.1)

project(gfx2col C)

set(gfx2col_major_version 1)
set(gfx2col_minor_version 4)
set(gfx2col_path_version 0)
set(gfx2col_version "${gfx2col_major_version}.${gfx2col_minor_version}.${gfx2col_path_version}")

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE "Debug")
endif()

set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}")

set(CMAKE_C_STANDARDS 11)

configure_file(config.h.in config.h)

set(gfx2col_sources
	compdan1.c
	compdan2.c
	compdan3.c
	comprle.c
	comptool.c
    gfx2col.c
    lodepng.c
    lodepic.c
)

set(gfx2col_headers
	compdan1.h
	compdan2.h
	compdan3.h
	comprle.h
    gfx2col.h
    lodepng.h
    lodepic.h
    config.h
)

add_executable(gfx2col ${gfx2col_sources} ${gfx2col_headers})
target_compile_options(gfx2col PRIVATE -Wall -Wshadow -Wextra)
target_include_directories(gfx2col PRIVATE ${CMAKE_BINARY_DIR})

install(TARGETS gfx2col RUNTIME DESTINATION bin)
<file_sep>/*---------------------------------------------------------------------------------


	Simple sound demo
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "ssound.h"

//---------------------------------------------------------------------------------
// sound declaration
const u8 dummysound[]={ 			// no sound, for soundtable, see below
	0x90
};

const u8 dksound[]={ 				// from Donkey Kong sound item 9
	0x81,0x3d,0x00,0x50,0x11,0x01,  //  tone freq 1833,8Hz swept down - vol 15 (max) - length 80
	0x90							// end
};

const u8 btsound[]={ 				// from Burger time sound item 12
	0x00,0x00,0x02,0x05,			// periodic noise - freq 125 Hz - vol 15 (max) - length 5
	0x10							// end
};

const u8 shsound[]={ 				// from spy hunter sound item 13
	0x02,0x26,0x1e,0x1d,0x24,		// white noise - freq 874 Hz - vol 13 swept down - length 30
	0x10							// end
};

const u8 sfsound[]={ 				// from space fury sound item 4
	0x43,0x97,0x00,0x08,0x11,
		0x2d,0x1f,0x11,				// tone freq 740,8Hz swept down - vol 15 (max) swept down - length 8
	0x10							// end
/*
*/
};

//---------------------------------------------------------------------------------
// mandatory soundtable declaration
// For some reason the very first entry MUST be SOUNDAREA1.  SOUNDAREA1 is the lowest priority sound effect.  
// I recommend using SOUNDAREA1-SOUNDAREA3 to be music track. SOUNDAREA4-6 to be sound effects. 
const sound_t snd_table[]={
	{ dummysound,		  				SOUNDAREA1},	// sound entry 1	

	{ dksound,			  				SOUNDAREA4},	// sound entry 2	
	{ btsound,			  				SOUNDAREA5},	// sound entry 3	
	{ shsound,			  				SOUNDAREA6},	// sound entry 4	
	{ sfsound,			  				SOUNDAREA4},	// sound entry 5	
};

//---------------------------------------------------------------------------------
// The NMI routine. Gets called 50 or 60 times per second 
// nothing to update for Input example
void nmi (void) {
}

//---------------------------------------------------------------------------------
void main (void) {
	// Put sound table and mute all channel
	snd_settable(snd_table);
	snd_stopall();

	// Put screen in text mode 2
	vdp_setmode2txt();
	
	// Put default char in VRAM and duplicate to all areas
	//  as we are going to write to line 10, it is in the second area
	vdp_setdefaultchar(FNTNORMAL);
	vdp_duplicatevram();
	vdp_fillvram(0x2000,0xf1,128*8); // Change color (or we will see nothing)
    vdp_putstring(7,6,"PUSH PAD FOR SOUNDS");
	
    // display screen and enable sound
    vdp_enablescr();
    vdp_enablenmi();
	
	// Wait for nothing :P
	while(1) {
		// Update display with current pad 1 values
		if (joypad_1 & PAD_RIGHT) { vdp_putstring(9,10,"DK SND"); snd_startplay(2); }
		if (joypad_1 & PAD_LEFT)  { vdp_putstring(9,10,"BT SND"); snd_startplay(3); }
		if (joypad_1 & PAD_DOWN)  { vdp_putstring(9,10,"SH SND"); snd_startplay(4); }
		if (joypad_1 & PAD_UP)    { vdp_putstring(9,10,"SF SND"); snd_startplay(5); }

		while (joypad_1) vdp_waitvblank(1); // Wait Vblank while joy pressed 
		
		vdp_waitvblank(1); // default wait vblank
	}
	// startup module will issue a soft reboot if it comes here 
}
<file_sep>/*---------------------------------------------------------------------------------


	Graphic mode 1 example with a bitmap 
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "mode1plecompress.h"

#include "gfxs.h"									// to add definition of graphics

//---------------------------------------------------------------------------------
// The NMI routine. Gets called 50 or 60 times per second 
// nothing to update for bitmap example
void nmi (void) {
}

//---------------------------------------------------------------------------------
void main (void) {
	vdp_disablescr();

	// put screen in mode 1 
	vdp_setmode1txt();
	
	vdp_ple2vram (TILourvisiongfx, chrgen); // characters
	vdp_putvram (coltab,COLourvisiongfx,32); // colors (not compressed as it is only 32 bytes)
	vdp_ple2vram (MAPourvisiongfx, chrtab); // map
	
	vdp_enablescr();

	// Wait for nothing :P
	while(1) {
		// Wait Vblank
		vdp_waitvblank(1);
	}
	// startup module will issue a soft reboot if it comes here 
}
<file_sep>/*---------------------------------------------------------------------------------

	Copyright (C) 2018-2019
		Alekmaul 

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:

	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.
	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.
	3.	This notice may not be removed or altered from any source
		distribution.

  Hex checker / BIN creator for colecovision.
  
  Based on :
    hex2bin converts an Intel hex file to binary.
	Copyright (C) 2012,  <NAME>
	checksum extensions Copyright (C) 2004 Rockwell Automation
	All rights reserved.
  
***************************************************************************/

//INCLUDES
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <malloc.h>
#include <string.h>

//DEFINES
#define CVMKCARTVERSION __BUILD_VERSION
#define CVMKCARTDATE __BUILD_DATE

#define MAX_LINE_SIZE 1024				// The data records can contain 255 bytes: this means 512 characters.
#define MEMORY_SIZE 1024*1024			// size in bytes (max = 1Mb)

#define NO_ADDRESS_TYPE_SELECTED 0
#define LINEAR_ADDRESS 1
#define SEGMENTED_ADDRESS 2

int quietmode=0;										// 0 = not quiet, 1 = i can't say anything :P
unsigned int maxlength = 64*1024;		// max rom length size
unsigned int nobanks = 2;						// number of banks
unsigned int padbyte = 0xFF;				// padding byte
unsigned char *memblocks;						// This will hold binary codes translated from hex file 
unsigned int norecord;							// record number for tracing

unsigned char datastring[MAX_LINE_SIZE];  
char dataline[MAX_LINE_SIZE]; 				// line inputted from file 
  
unsigned int nobytes;
unsigned int firstword, address, segment, upperaddr;
unsigned int lowaddr, highaddr, startaddr, lowbank;

  /* This mask is for mapping the target binary inside the
	 binary buffer. If for example, we are generating a binary
	 file with records starting at FFF00000, the bytes will be
	 stored at the beginning of the memory buffer. */
unsigned int maskaddr;

unsigned int physaddr, recordtype;
unsigned int temp;
int temp2;
unsigned int norecord;

// We will assume that when one type of addressing is selected, it will be valid for all the
//  current file. Records for the other type will be ignored. 
unsigned int	seglinselect = NO_ADDRESS_TYPE_SELECTED;

char *p;
  
//-- Read a line from file --------------------------------------------------------
int Getdataline(char* str,FILE *in)
{
	char *result;

	result = fgets(str,MAX_LINE_SIZE,in);
	if ((result == NULL) && !feof (in)) {
		printf("\nERROR: Can't read from file\n");
		return 0;
	}
	
	return 1;
}

//-- Print option of program ------------------------------------------------------
void PrintOptions(char *str) {
	printf("\n\nUsage: cvmkcart [options] romfilename ...");
	printf("\n  where romfilename is the COLECOVISION rom file to generate.");
	
	if(str[0]!=0)
		printf("\nThe [%s] parameter is not recognized.",str);
	
	printf("\n\nOptions are:");
	printf("\n\n--- Rom options ---");
	printf("\n-b[bank]          Number of 16k banks of finale rom (default is 2 for 64k rom, max is 64 for 1Mb rom).");
	printf("\n-p[value]         Padding byte value (default is 255).");
	printf("\n-iihxfilename     Name of HEX ihx filename.");
	printf("\n");
	printf("\n\n--- Misc options ---");
	printf("\n-q                quiet mode");
	printf("\n");
	
} //end of PrintOptions()

/// M A I N ////////////////////////////////////////////////////////////

int main(int argc, char **arg)
{
	FILE *fpi, *fpo;

	char romfile[256];
	char ihxfile[256];

	int i;

	// Show something to begin :)
	if (quietmode == 0) {
		printf("\n=================================");
		printf("\n--- CVMKCART v"CVMKCARTVERSION" "CVMKCARTDATE" ---");
		printf("\n---------------------------------");
		printf("\n(c) 2014-2019 Alekmaul ");
		printf("\n=================================\n");
	}
	
	// Init vars
	romfile[0] = '\0';
	ihxfile[0] = '\0';
	
	//parse the arguments
	for(i=1;i<argc;i++)
	{
		if(arg[i][0]=='-')
		{
			if(arg[i][1]=='q') //quiet mode
			{
				quietmode=1;
			}
			else if(arg[i][1]=='b') // number of banks
			{
				nobanks=atoi(&arg[i][2]);
				if ( (nobanks<2) || (nobanks>64))
				{
					PrintOptions(arg[i]);
					return 1;
				}
				maxlength=(nobanks+3)*16*1024; // 3 because we begin writing at 0xc000
			}
			else if(arg[i][1]=='p') // padding byte
			{
				padbyte=atoi(&arg[i][2]);
				if (padbyte>255)
				{
					PrintOptions(arg[i]);
					return 1;
				}
			}
			else if(arg[i][1]=='i') // ihx filename
			{
				strcpy(ihxfile,&arg[i][2]);
			}
			else //invalid option
			{
				PrintOptions(arg[i]);
				return 1;
			}
		}
		else
		{
			//its not an option flag, so it must be the filebase
			if(romfile[0]!=0) // if already defined... there's a problem
			{
				PrintOptions(arg[i]);
				return 1;
			}
			else {
				strcpy(romfile,arg[i]);
			}
		}
	}

	//make sure options are valid
	if( romfile[0] == 0 )
	{
		printf("\nERROR: You must specify a rom filename.");
		PrintOptions("");
		return 1;
	}
	if (strlen(ihxfile) == 0)
	{
		printf("\nERROR: You must specify an ihx file.");
		PrintOptions("");
		return 1;
	}
	
	// open the file
	fpi = fopen(ihxfile,"r");
	if (fpi==NULL)
	{
		printf("\nERROR: Can't open ihx file [%s]",ihxfile);
		return 0;
	}
	
	// open the file
	fpo = fopen(romfile,"wb");
	if (fpo==NULL)
	{
		printf("\nERROR: Can't create rom file [%s]",romfile);
		return 0;
	}
	
	// allocate a buffer 
	if ((memblocks = malloc (maxlength+0x8000)) == NULL)
    {
		printf("\nERROR: Can't allocate memory for output.\n");
		exit(1);
	}

	if (quietmode == 0) {
		printf("\n****** O P T I O N S ***************");
		printf("\nReading file     %s ...",ihxfile);
		printf("\nWriting rom file %s...",romfile);
		printf("\nRom size         %dk",(maxlength-0x4000)/1024);
		printf("\nNumber of banks  %d",nobanks);
		printf("\nPadding byte     %02x\n",padbyte);
	}
	
	// begining of reading file  
	startaddr = 0;
	maxlength+=0x8000; // rom 0..8000 if coleco bios and ram
  
	// fill unused bytes with FF or the value specified by the p option (or 255 for default value)
	memset (memblocks,padbyte,maxlength);
	
	// To begin, assume the lowest address is at the end of the memory.
	// While reading each records, subsequent addresses will lower this number.
	// At the end of the input file, this value will be the lowest address.
	// A similar assumption is made for highest address. It starts at the
	// beginning of memory. While reading each records, subsequent addresses will raise this number.
	// At the end of the input file, this value will be the highest address. 
	lowaddr = maxlength - 1 - 0x8000;
	highaddr = 0;
	segment = 0;
	upperaddr = 0;
	norecord = 0;
	lowbank=0;
	
    /* Max length must be in powers of 2: 1,2,4,8,16,32, etc. */
	maskaddr = maxlength;// -1;
	if (quietmode == 0) {
		printf("\nMaximum address set to %06x\n",maskaddr);
	}
	
	// Read the file & process the lines. 
	do // repeat until EOF(fpi) 
	{

		//Read a line from input file.
		Getdataline(dataline,fpi);
		norecord++;

		//Remove carriage return/line feed at the end of line.
		i = strlen(dataline);

		if (--i != 0) {
			if (dataline[i] == '\n') dataline[i] = '\0';

			// Scan the first two bytes and nb of bytes.
			// The two bytes are read in firstword since its use depend on the
			// record type: if it's an extended address record or a data record.
			sscanf (dataline, ":%2x%4x%2x%s",&nobytes,&firstword,&recordtype,datastring);
			p = (char *) datastring;

			// If we're reading the last record, ignore it. 
			switch (recordtype) {
				// Data record
				case 0:
					if (nobytes == 0) {
						printf("\nWARNING: 0 byte length Data record ignored");
						break;
					}
					address = firstword;
					
					// check bank number to update if new bank
					if (address==0xc000) {
						lowbank++;
						if (quietmode == 0) {
							printf("\nBank %d detected ...",lowbank);
						}
					}

					// add bank number if in bank
					if (address>=0xc000)
						address+=(lowbank-1)*0x4000;

					if (seglinselect == SEGMENTED_ADDRESS)
						physaddr = (segment << 4) + address;
					else
						// LINEAR_ADDRESS or NO_ADDRESS_TYPE_SELECTED
						//upperaddr = 0 as specified in the Intel spec. until an extended address record is read.
						physaddr = ((upperaddr << 16) + address) % maskaddr; // change & to %

					// Check that the physical address stays in the buffer's range. 
					if ((physaddr + nobytes) <= maxlength) {
						// Set the lowest address as base pointer. 
						if (physaddr < lowaddr)
							lowaddr = physaddr;

						// Same for the top address.
						temp = physaddr + nobytes -1;
						if (temp > highaddr)
							highaddr = temp;

						// Read the Data bytes. 
						// Bytes are written in the Memory block even if checksum is wrong.
						i = nobytes;

						do
						{
							sscanf (p, "%2x",&temp2);
							p += 2;

							// Overlapping record will erase the pad bytes 
							if (memblocks[physaddr] != padbyte) 
								printf("\nWARNING: Overlapped record (%d) detected %06x=%02x",norecord-1, physaddr,memblocks[physaddr]);
							memblocks[physaddr++] = temp2;
						} while (--i != 0);

						// Read the Checksum value. 
						sscanf (p, "%2x",&temp2);
					}
					else
					{
						if (seglinselect == SEGMENTED_ADDRESS)
							printf("\nWARNING: Data record (%d) skipped at %6X:%6X",norecord-1, segment,address);
						else
							printf("\nWARNING: Data record (%d) skipped at %6X",norecord-1, physaddr);
					}
					break;

				// End of file record
				case 1:
					// Simply ignore checksum errors in this line. 
					break;

				// Extended segment address record 
				case 2:
					// firstword contains the offset. It's supposed to be 0000 so we ignore it. 
					// First extended segment address record ? 
					if (seglinselect == NO_ADDRESS_TYPE_SELECTED)
						seglinselect = SEGMENTED_ADDRESS;

					// Then ignore subsequent extended linear address records 
					if (seglinselect == SEGMENTED_ADDRESS)
					{
						sscanf (p, "%4x%2x",&segment,&temp2);

						// Update the current address.
						physaddr = (segment << 4) % maskaddr;
					}
					break;

				// Start segment address record 
				case 3:
					// Nothing to be done since it's for specifying the starting address for execution of the binary code 
					break;

				// Extended linear address record 
				case 4:
					// firstword contains the offset. It's supposed to be 0000 so we ignore it. 
					// First extended linear address record ? 
					if (seglinselect == NO_ADDRESS_TYPE_SELECTED)
						seglinselect = LINEAR_ADDRESS;

					// Then ignore subsequent extended segment address records 
					if (seglinselect == LINEAR_ADDRESS)
					{
						sscanf (p, "%4x%2x",&upperaddr,&temp2);

						// Update the current address. 
						physaddr = (upperaddr << 16) % maskaddr;
					}
					break;

				// Start linear address record 
				case 5:
					// Nothing to be done since it's for specifying the starting address for execution of the binary code 
					break;
				default:
					printf("\nWARNING: Unknown record type");
					break;
            }
        }
	} while (!feof (fpi));
    
	// maxlength is set; the memory buffer is already filled with pattern before
	// reading the hex file. The padding bytes will then be added to the binary file.
	highaddr = startaddr + maxlength-1;
	startaddr=0xc000;
	lowaddr = startaddr;

	// change 0x8000 to last bank
	// and manage start adress to 0x8000
	memcpy(&memblocks[highaddr-0x4000+1],&memblocks[0x8000],0x4000);
	
	if (quietmode == 0) {
		printf("\n\nLowest address  = %08X",lowaddr);
		printf("\nHighest address = %08X",highaddr);
		printf("\nPad Byte        = %X",  padbyte);
		printf("\nRom size wrote  = %08X (%dk)",highaddr - lowaddr +1,(highaddr - lowaddr +1)/1024);
		printf("\nBanks detected  = %X\n", lowbank);
	}
	
	// write binary file 
	fwrite (&memblocks[lowaddr], 1, highaddr - lowaddr +1, fpo);
	free (memblocks);
    
	// close the files
	fclose(fpi);
	fclose(fpo);
	
	if (quietmode == 0)
		printf("\nDone!\n");

	// display map file
	if (quietmode == 0) {
		// open the map file
		strcpy(romfile,ihxfile);
		i = strlen(romfile);
		romfile[i-3]='m';romfile[i-2]='a';romfile[i-1]='p';
		fpi = fopen(romfile,"r");
		if (fpi==NULL)
		{
			printf("\nERROR: Can't open map file [%s]",romfile);
			return 0;
		}
		printf("\nArea                                    Addr        Size        Decimal Bytes (Attributes)");
		printf("\n--------------------------------        ----        ----        ------- ----- ------------\n");
		do {
			//Read a line from input file.
			Getdataline(dataline,fpi);
			
			// if line begin with _, print it (I know it is bad ...)
			if (dataline[0]=='_') {
				printf(dataline);
			}
		} while (!feof (fpi));
		fclose(fpi);
		printf("\n");
	}
	
	return 0;
}
<file_sep>ifeq ($(strip $(PVCOLLIB_HOME)),)
$(error "Please create an environment variable PVCOLLIB_HOME with path to its folder and restart application. (you can do it on windows with <setx PVCOLLIB_HOME "/c/snesdev">)")
endif

export TOPDIR	:=	$(CURDIR)

# create version number which will be used everywhere
export PVCOLLIB_MAJOR	:= 1
export PVCOLLIB_MINOR	:= 6
export PVCOLLIB_PATCH	:= 0

# Directory with docs config and output (via doxygen)
export PVCDOCSDIR = $(TOPDIR)/docs

.PHONY: release clean all docs

all: include/coleco/libversion.h pvcollibversion release docs

#-------------------------------------------------------------------------------
release: lib
	make -C source all

#-------------------------------------------------------------------------------
lib:
	mkdir lib

#-------------------------------------------------------------------------------
examples:
	cd ../coleco-examples && \
	make && \
	make install

#-------------------------------------------------------------------------------
clean:
	make -C source clean
	rm -rf $(PVCDOCSDIR)/html
	rm -f pvcollib_version.txt

#---------------------------------------------------------------------------------
doxygenInstalled := $(shell command -v doxygen 2> /dev/null)
docs:
ifndef doxygenInstalled
	@echo "doxygen is not installed, documentation will be not generated.";
else
	@rm -rf $(PVCDOCSDIR)/html; \
	PVCDOCSDIR="$(PVCDOCSDIR)" PVCVERSION="$(PVCOLLIB_MAJOR).$(PVCOLLIB_MINOR).$(PVCOLLIB_PATCH)" doxygen "$(PVCDOCSDIR)/pvcollib.dox"
	@if [ "$(DOCS_PDF_ON)" = "YES" ]; then\
		$(MAKE) -C $(PVCDOCSDIR)/latex;\
		cp $(PVCDOCSDIR)/latex/refman.pdf $(PVCDOCSDIR)/PVCOLLIB_manual.pdf;\
	fi
	@if [ -f 'warn.log' ]; then \
			@cat warn.log; \
	fi	
	@rm -rf $(PVCDOCSDIR)/latex
endif

# Turn on Latex -> PDF conversion to run run at end of regular docs build
# (which includes latex output but deletes it at the end).
#
# The conversion process requires a Latex install.
# For Windows there are various Latex packages to choose from.
# For Linux this appears to be the minimum:
#   sudo apt install texlive-latex-base
#   sudo apt install texlive-latex-recommended
#   sudo apt install texlive-latex-extra
#
docspdf: DOCS_PDF_ON=YES
docspdf: docs

#---------------------------------------------------------------------------------
include/coleco/libversion.h : Makefile
	@echo "#ifndef __PVCOLLIBVERSION_H__" > $@
	@echo "#define __PVCOLLIBVERSION_H__" >> $@
	@echo >> $@
	@echo "#define _PVCOLLIB_MAJOR_	$(PVCOLLIB_MAJOR)" >> $@
	@echo "#define _PVCOLLIB_MINOR_	$(PVCOLLIB_MINOR)" >> $@
	@echo "#define _PVCOLLIB_PATCH_	$(PVCOLLIB_PATCH)" >> $@
	@echo >> $@
	@echo '#define _PVCOLLIB_STRING "PVCOLLIB Release '$(PVCOLLIB_MAJOR).$(PVCOLLIB_MINOR).$(PVCOLLIB_PATCH)'"' >> $@
	@echo >> $@
	@echo "#endif // __PVCOLLIBVERSION_H__" >> $@

# to ease installation for users, the version is no more in folder name (which require to update PVCOLLIB_HOME) but in specific file
pvcollibversion:
	@echo $(PVCOLLIB_MAJOR).$(PVCOLLIB_MINOR).$(PVCOLLIB_PATCH) > pvcollib_version.txt<file_sep>ifeq ($(strip $(PVCOLLIB_HOME)),)
$(error "Please create an environment variable PVCOLLIB_HOME with path to its folder and restart application. (you can do it on windows with <setx PVCOLLIB_HOME "/c/colecodev">)")
endif

include ${PVCOLLIB_HOME}/devkitcol/col_rules

#---------------------------------------------------------------------------------
# ROMNAME is used in col_rules file
ROMNAME		:=	simplesprite

.PHONY: bitmaps all
 
 #---------------------------------------------------------------------------------
all: bitmaps $(ROMNAME).rom
	
clean: cleanRom cleanGfx

#---------------------------------------------------------------------------------
pacsprite.inc: pacsprite.png
	@echo convert sprite ... $(notdir $@)
	$(GFXCONV) -fpng -s $<
	
bitmaps: pacsprite.inc
<file_sep>#ifndef __SDCC_STDALIGN_H
#define __SDCC_STDALIGN_H 1

#ifndef __alignas_is_defined
#define __alignas_is_defined 1

#define alignas _Alignas

#endif


#ifndef __alignof_is_defined
#define __alignof_is_defined 1

#define alignof _Alignof

#endif

#endif

<file_sep>/*---------------------------------------------------------------------------------

	Generic f18a video functions

	Copyright (C) 2018-2019
		Alekmaul

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:

	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.
	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.
	3.	This notice may not be removed or altered from any source
		distribution.

---------------------------------------------------------------------------------*/
/**
 * \file f18a.h
 * \brief contains the basic definitions for controlling the f18a video device.
 *
 * This unit provides generic features related to f18a device.<br>
 *<br>
 * Here is the list of features:<br>
 * - enable and disable f18a<br>
 * - update palette<br>
*/

#ifndef COL_F18A_INCLUDE
#define COL_F18A_INCLUDE

#include <coleco/coltypes.h>

#define sprtab_f18a  		0x2800 //f18a colour only requires 1/3 the colour data so til 0x2800
#define sprtab_f18a_2  		0x3000
#define sprtab_f18a_3	 	0x3800
#define mapvram 			0x1b00  

#define F18A_ECMS_0P		(0<<0)
#define F18A_ECMS_1B		(1<<0)
#define F18A_ECMS_2B		(2<<0)
#define F18A_ECMS_3B		(3<<0)
#define F18A_ECMT_0P		(0<<4)
#define F18A_ECMT_1B		(1<<4)
#define F18A_ECMT_2B		(2<<4)
#define F18A_ECMT_3B		(3<<4)
#define F18A_ECM_R30		(1<<6)
#define F18A_ECM_TM2		(1<<7)
#define F18A_ECM_YRE		(1<<3)

/**
 *  \brief vdp_f18aok is set if f18a module is present<br>
 *	when calling vdp_f18ainit function<br>
 */
extern volatile u8 vdp_f18aok;

/**
 * \fn void vdp_f18ainit(void)
 * \brief Activate f18a device<br>
 * Activate f18a and init vdp_f18aok variable with 1 if it is ok<br>
*/
void vdp_f18ainit(void);

/**
 * \fn void vdp_f18asetpalette(void *data,unsigned char count)
 * \brief Send a palette RGB 12bits color entries to f18a device<br>
 *
 * \param data address of data to use
 * \param count number of data <b>in words (each entry is two bytes)</b>
*/
void vdp_f18asetpalette(void *data,unsigned char count);

/**
 * \fn void vdp_f18asetpaletteentry(void *data,u8 entry,unsigned char count)
 * \brief Send a palette RGB 12bits color entries to f18a device<br>
 *
 * \param data address of data to use
 * \param offset 1st entry in the palette (0..64)
 * \param count number of data <b>in words (each entry is two bytes)</b>
*/
void vdp_f18asetpaletteentry(void *data,unsigned offset,unsigned char count);

/**
 * \fn vdp_f18asetmode1(u8 flags)
 * \brief Activate mode 1 in bitmap mode for f18a ONLY<br>
 *
 * \param flags	ecm mode definition<br>
 * F18A_ECMS_0P	or F18A_ECMS_1..3B for sprite color mode<br>
 * F18A_ECMT_0P	or F18A_ECMT_1..3B for tile color mode<br>
 * F18A_ECM_R30	for 30 lines mode <br>
 * F18A_ECM_TM2	to activate tile map 2 <br>
 * F18A_ECM_YRE	to activate Y real coordinates <br>
*/
void vdp_f18asetmode1(u8 flags);

/**
 * \fn vdp_f18asetscrollx(u8 bgnum, u8 x)
 * \brief Sets the horizontal scroll offset to the specified location
 *
 * \param bgnum	background number (1 or 2 for TL1 and TL2)
 * \param x	the horizontal scroll offset <br>
 *     (5 bits of scroll | 3 bits for planes : HTO0	HTO1	HTO2	HTO3	HTO4	HPO0	HPO1	HPO2)
*/
void vdp_f18asetscrollx(u8 bgnum, u8 x);

/**
 * \fn vdp_f18asetscrolly(u8 bgnum, u8 y)
 * \brief Sets the vertical scroll offset to the specified location
 *
 * \param bgnum	background number (1 or 2 for TL1 and TL2)
 * \param y	the vertical scroll offset <br>
 *     (5 bits of scroll | 3 bits for planes : VTO0	VTO1	VTO2	VTO3	VTO4	VPO0	VPO1	VPO2)
*/
void vdp_f18asetscrolly(u8 bgnum, u8 y);

#endif
<file_sep>/*---------------------------------------------------------------------------------


	simple sprite demo
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "simplesprite.h"

#include "gfxs.h"									// to add definition of graphics

//---------------------------------------------------------------------------------
// The NMI routine. Gets called 50 or 60 times per second 
// nothing to update for bitmap example
void nmi (void) {
	// update sprite display during nmi, if you enable sprites
	if (spr_enable)
		spr_update();
}

//---------------------------------------------------------------------------------
void main (void) {
	u8 xp,yp,idpac;
	
	// Put screen in text mode 2
	vdp_disablescr();
	
	vdp_setmode2txt();
	
	// Put default char in VRAM and duplicate to all areas
	//  as we are going to write to line 10, it is in the second area
	vdp_setdefaultchar(FNTNORMAL);
	vdp_duplicatevram();
	vdp_fillvram(0x2000,0xf1,128*8); 	// Change color (or we will see nothing)

	// Put sprite character
	vdp_putvram (sprtab,TILpacspritegfx,SZTILpacspritegfx); // sprite characters

	// Enable screen and nmi to allow display and sprite management
    vdp_enablescr();
	vdp_enablenmi();
    
	// Put sprite in middle of screen with color light yellow, 0 because we have only one pattern (index 0)
	xp=8*16;yp=8*12;
	idpac=spr_getentry();
	spr_set(idpac,xp,yp,11,0);
	
	// enable sprite display
	spr_enable = 1;
	
	// Wait for nothing :P
	while(1) {
		if (joypad_1 & PAD_RIGHT) { 
			if (xp<(256-16)) { xp++; spr_setx(idpac,xp); } 
		}
		if (joypad_1 & PAD_LEFT)  { 
			if (xp>0) { xp--; spr_setx(idpac,xp); } 
		}
		if (joypad_1 & PAD_DOWN)  { 
			if (yp<(192-16)) {  yp++; spr_sety(idpac,yp); } 
		}
		if (joypad_1 & PAD_UP)    { 
			if (yp>0) { yp--; spr_sety(idpac,yp); } 
		}

		// Wait Vblank
		vdp_waitvblank(1);
	}
	// startup module will issue a soft reboot if it comes here 
}
<file_sep>ifeq ($(strip $(PVCOLLIB_HOME)),)
$(error "Please create an environment variable PVCOLLIB_HOME with path to its folder and restart application. (you can do it on windows with <setx PVCOLLIB_HOME "/c/colecodev">)")
endif

include ${PVCOLLIB_HOME}/devkitcol/col_rules

#---------------------------------------------------------------------------------
# ROMNAME is used in col_rules file
ROMNAME		:=	ssound

.PHONY: all
 
#---------------------------------------------------------------------------------
all: $(ROMNAME).rom
	
clean: cleanRom cleanGfx

<file_sep>#ifndef COMPDAN3_H
#define COMPDAN3_H

#include <stdio.h>
#include <stdlib.h>
#include <mem.h>

#define bool unsigned char
#define byte unsigned char
#define false 0
#define true 0xff

extern int dan3Compress(byte *src,byte *dst,int n);

#endif<file_sep>#ifndef _COSMOC_MAIN_
#define _COSMOC_MAIN_

#include <coleco.h>

extern void vdp_putvramex (unsigned offset,void *ptr,unsigned count,u8 and_mask,u8 xor_mask);
extern u8 check_collision (sprite_t *sprite1,sprite_t *sprite2,
                      unsigned sprite1_size_hor,unsigned sprite1_size_vert,
                      unsigned sprite2_size_hor,unsigned sprite2_size_vert);

extern const sound_t snd_table[];

/* various RLE-encoded tables (in tables.c) */
extern const u8 title_screen[];
extern const u8 intro_screen[];
extern const u8 stone_characters[];
extern const u8 sprite_patterns[];

#endif<file_sep>
# bin2txt binary to text converter for Colecovision PVcollib development

## Usage
```
bin2txt [options] filename ...  
```
where filename is a binary file

## Options  
### General options 
- `-c[no|rle|ple|dan]` Compression method [no]  
  
### Convert options  
- `-cc` Output in c style format
- `-ca` Output in assembly style format
  
### Misc options 
- `-q` Quiet mode  
  
## Example 
```
bin2txt -cc myimage.bin
```
 This will will convert a myimage bin file to a h file.

## History  
V1.0.0 : initial release  
<file_sep>/*---------------------------------------------------------------------------------


	f18a test with a bitmap 
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "f18abitmap1.h"

#include "gfxs.h"									// to add definition of graphics

//---------------------------------------------------------------------------------
// The NMI routine. Gets called 50 or 60 times per second 
// nothing to update for bitmap example
void nmi (void) {
}

//---------------------------------------------------------------------------------
void main (void) {
	// Check if f18a is available
	vdp_f18ainit();

	// display a message regarding result of test
	if (vdp_f18aok==1) {
		// put screen in mode 1 with no specific f18a stuffs
		vdp_f18asetmode1(0x30);
		
		vdp_ple2vram (TILourvisiongfx, chrgen); // characters
		vdp_ple2vram (MAPourvisiongfx, chrtab); // map
		vdp_ple2vram (COLourvisiongfx, coltab); // colours

		vdp_f18asetpalette(PALourvisiongfx,64);
		
		vdp_enablescr();
	}
	else {
		// Put screen in text mode 2
		vdp_setmode2txt();
	
		// Put default char in VRAM and duplicate to all areas
		//  as we are going to write to line 8, it is in the second area
		vdp_setdefaultchar(FNTNORMAL);
		vdp_duplicatevram();
		vdp_fillvram(0x2000,0xf1,128*8); 	// Change color (or we will see nothing)
		vdp_enablescr();
	
		// Print text as we are not going to do something else
		vdp_putstring(8,5,"NO F18A SUPPORT...");
	}

	// Wait for nothing :P
	while(1) {
		// Wait Vblank
		vdp_waitvblank(1);
	}
	// startup module will issue a soft reboot if it comes here 
}
<file_sep>/********************************************/
/*                                          */
/*   GRAPHICS TABLES  -  WIN ICVGM v3.00    */
/*                                          */
/*        WARNING : RLE COMPRESSION         */
/*                                          */
/********************************************/

#include <coleco.h>

const u8 NAMERLE[] = {
  0x01, 0x24, 0x23, 0x9B, 0x20, 0x03, 0x25, 0x26, 0x24, 0x23, 0x9B, 0x20, 0x03, 0x25, 0x26,
  0x24, 0x23, 0x86, 0x20, 0x00, 0x98, 0x93, 0x20, 0x03, 0x25, 0x26, 0x24, 0x23, 0x87, 0x20, 0x0B,
  0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x87, 0x20, 0x03, 0x25,
  0x26, 0x24, 0x23, 0x87, 0x20, 0x0B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
  0x96, 0x97, 0x87, 0x20, 0x03, 0x25, 0x26, 0x24, 0x23, 0x93, 0x20, 0x00, 0x98, 0x86, 0x20, 0x03,
  0x25, 0x26, 0x24, 0x23, 0x8C, 0x20, 0x01, 0xD6, 0xD7, 0x8C, 0x20, 0x03, 0x25, 0x26, 0x24, 0x23,
  0x9B, 0x20, 0x03, 0x25, 0x26, 0x24, 0x23, 0x92, 0x20, 0x00, 0xC8, 0x87, 0x20, 0x03, 0x25, 0x26,
  0x24, 0x23, 0x86, 0x20, 0x05, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x84, 0x20, 0x01, 0xC9, 0xCA,
  0x87, 0x20, 0x03, 0x25, 0x26, 0x24, 0x23, 0x86, 0x20, 0x04, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0x82,
  0x20, 0x04, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0x87, 0x20, 0x03, 0x25, 0x26, 0x24, 0x23, 0x87, 0x20,
  0x03, 0xA4, 0xA5, 0xA6, 0xA7, 0x82, 0x20, 0x03, 0xD0, 0xD1, 0xD2, 0xD3, 0x88, 0x20, 0x03, 0x25,
  0x26, 0x24, 0x23, 0x86, 0x20, 0x06, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0x82, 0x20, 0x01,
  0xD4, 0xD5, 0x88, 0x20, 0x03, 0x25, 0x26, 0x24, 0x23, 0x86, 0x20, 0x09, 0xAF, 0xB0, 0xB1, 0xB2,
  0xB3, 0xB4, 0xB5, 0xB6, 0xC7, 0xC7, 0x8A, 0x20, 0x03, 0x25, 0x26, 0x24, 0x23, 0x87, 0x20, 0x09,
  0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0x20, 0xC7, 0xC7, 0x89, 0x20, 0x03, 0x25, 0x26, 0x24,
  0x23, 0x87, 0x20, 0x08, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0x20, 0xC7, 0x8A, 0x20, 0x03,
  0x25, 0x26, 0x24, 0x23, 0x8A, 0x20, 0x05, 0xC5, 0xC6, 0xC4, 0x20, 0xC7, 0xC7, 0x8A, 0x20, 0x03,
  0x25, 0x26, 0x24, 0x23, 0x9B, 0x20, 0x03, 0x25, 0x26, 0x24, 0x23, 0x9B, 0x20, 0x03, 0x25, 0x26,
  0x24, 0x23, 0x9B, 0x20, 0x03, 0x25, 0x26, 0x24, 0x23, 0x89, 0x20, 0x07, 0xD8, 0xD9, 0xDA, 0xDB,
  0xDC, 0xDD, 0xDE, 0xDF, 0x89, 0x20, 0x03, 0x25, 0x26, 0x24, 0x23, 0x9B, 0x20, 0x03, 0x25, 0x26,
  0x24, 0x23, 0x9B, 0x20, 0x03, 0x25, 0x26, 0x24, 0x23, 0x9B, 0x20, 0x01, 0x25, 0x26, 0xFF};

const u8 PATTERNRLE[] = {
  0x0A, 0xC3, 0x24, 0xA5, 0x66, 0x3C, 0x5A, 0xDB, 0xE7, 0x00, 0xC3, 0x42, 0x83, 0x00, 0x1C,
  0x18, 0x00, 0x24, 0x7E, 0xE7, 0xC3, 0xE7, 0x7E, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x3C, 0x18, 0x00,
  0x00, 0xE0, 0x90, 0x48, 0x28, 0x1C, 0x3A, 0x7A, 0x7C, 0x00, 0x60, 0x30, 0x10, 0x82, 0x00, 0x1C,
  0x03, 0x08, 0x18, 0x3F, 0x79, 0xF0, 0xF9, 0x7F, 0x3E, 0x06, 0x06, 0xC0, 0x86, 0x0F, 0x06, 0x00,
  0x00, 0x07, 0x09, 0x12, 0x14, 0x38, 0x5C, 0x5E, 0x3E, 0x00, 0x06, 0x0C, 0x08, 0x82, 0x00, 0x0E,
  0xC0, 0x10, 0x18, 0xFC, 0x9E, 0x0F, 0x9F, 0xFE, 0x7C, 0x60, 0x60, 0x03, 0x61, 0xF0, 0x60, 0xB9,
  0x00, 0x44, 0x99, 0x66, 0xDD, 0x77, 0xDD, 0x77, 0x99, 0xBB, 0x99, 0x66, 0xDD, 0x77, 0xDD, 0x77,
  0xEE, 0xBB, 0x99, 0x66, 0xDD, 0x77, 0xDD, 0xBB, 0xEE, 0x33, 0x99, 0x66, 0xDD, 0x77, 0xEE, 0xBB,
  0xCC, 0x33, 0x99, 0x66, 0xDD, 0xBB, 0xEE, 0x33, 0xCC, 0x22, 0x99, 0x66, 0xEE, 0xBB, 0xCC, 0x33,
  0x88, 0x22, 0x99, 0xBB, 0xEE, 0x33, 0xCC, 0x22, 0x88, 0x00, 0xEE, 0xBB, 0xCC, 0x33, 0x88, 0x22,
  0x00, 0x00, 0xEE, 0x33, 0xCC, 0x22, 0x88, 0x82, 0x00, 0x03, 0xCC, 0x33, 0x88, 0x22, 0x83, 0x00,
  0x02, 0xCC, 0x22, 0x88, 0x84, 0x00, 0x01, 0x88, 0x22, 0x85, 0x00, 0x00, 0x88, 0x90, 0x00, 0x01,
  0x0C, 0x1E, 0x82, 0x3E, 0x37, 0x1C, 0x46, 0xAD, 0xDB, 0x76, 0x44, 0x12, 0x00, 0x00, 0xF3, 0xCC,
  0x30, 0xCC, 0xF3, 0xCC, 0x30, 0xCC, 0xF3, 0xCC, 0x30, 0xCC, 0xF3, 0xCC, 0x30, 0xCC, 0xCF, 0x33,
  0x0C, 0x33, 0xCF, 0x33, 0x0C, 0x33, 0xCF, 0x33, 0x0C, 0x33, 0xCF, 0x33, 0x0C, 0x33, 0x18, 0xDB,
  0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x7E, 0x3C, 0x18, 0x82, 0x00, 0x03,
  0x18, 0x3C, 0x3C, 0x18, 0x84, 0x00, 0x81, 0x18, 0x8A, 0x00, 0x21, 0x30, 0x18, 0x88, 0xFE, 0x7F,
  0x18, 0x38, 0x70, 0x00, 0xE0, 0x30, 0xFE, 0x7F, 0x30, 0xE0, 0x00, 0x0C, 0x18, 0x11, 0x7F, 0xFE,
  0x18, 0x1C, 0x0E, 0x00, 0x07, 0x0C, 0x7F, 0xFE, 0x0C, 0x07, 0x00, 0xE7, 0x66, 0x85, 0x00, 0x01,
  0x18, 0x3C, 0x85, 0x00, 0x81, 0x66, 0x00, 0x24, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
  0xF2, 0x00, 0x00, 0x1C, 0x82, 0x3F, 0x01, 0x7B, 0x70, 0x83, 0x00, 0x03, 0x80, 0x83, 0x3F, 0x7F,
  0x85, 0x00, 0x01, 0x1E, 0x3F, 0x83, 0x00, 0x81, 0x38, 0x01, 0xF8, 0xFD, 0x85, 0x00, 0x01, 0xF0,
  0xFD, 0x85, 0x00, 0x01, 0xD8, 0xF8, 0x82, 0x00, 0x04, 0x1F, 0x3F, 0x3F, 0x39, 0x39, 0x82, 0x00,
  0x04, 0x80, 0xC0, 0xC0, 0xC6, 0xCE, 0x84, 0x00, 0x02, 0x01, 0x33, 0x73, 0x84, 0x00, 0x02, 0x80,
  0xF1, 0xFD, 0x84, 0x00, 0x02, 0xC0, 0xF8, 0xFF, 0x84, 0x00, 0x0B, 0x0C, 0x1C, 0x9C, 0x7E, 0x7F,
  0x7F, 0xF0, 0xF0, 0xFE, 0xFE, 0x1E, 0xFF, 0x82, 0xE3, 0x1D, 0xF7, 0x7F, 0x7F, 0x1C, 0xFE, 0xE0,
  0xFF, 0x7F, 0xA3, 0xFF, 0x7F, 0x3E, 0x7F, 0x73, 0x73, 0xF3, 0xE3, 0xE1, 0xE1, 0x00, 0xFF, 0x9F,
  0xFF, 0xF7, 0xCF, 0xFF, 0xFD, 0x78, 0xF8, 0xE0, 0x84, 0xC0, 0x38, 0x00, 0x3F, 0x3F, 0x1F, 0x1C,
  0x1D, 0x1F, 0x1F, 0x0F, 0xCE, 0xEE, 0xFE, 0x7E, 0xFF, 0xEF, 0xE7, 0x83, 0x73, 0x73, 0x7B, 0x7F,
  0x7F, 0xF7, 0xF2, 0xE0, 0xFD, 0x9D, 0x9D, 0x9F, 0x1F, 0x3B, 0x39, 0x18, 0xFF, 0xCF, 0xCF, 0xCE,
  0x8E, 0x9C, 0x1C, 0x0C, 0xDC, 0xDC, 0xFC, 0xFC, 0x7C, 0x38, 0xF8, 0xF0, 0x10, 0x18, 0x3F, 0xFE,
  0x7C, 0x3E, 0x32, 0x20, 0x84, 0x00, 0x0D, 0x01, 0x03, 0x07, 0x00, 0x00, 0x03, 0x3F, 0xF0, 0xC0,
  0x80, 0x0F, 0x00, 0x00, 0xFF, 0x82, 0x00, 0x0D, 0x7E, 0xFF, 0x00, 0x00, 0x80, 0xFE, 0x03, 0x01,
  0x03, 0xFE, 0x00, 0x00, 0x1F, 0xFF, 0x82, 0x7F, 0x04, 0xC0, 0x00, 0x00, 0xC0, 0xFE, 0x82, 0xFF,
  0x20, 0x7E, 0x07, 0x0E, 0x0E, 0x0F, 0x0F, 0x07, 0x07, 0x03, 0x3F, 0xF8, 0xE0, 0xC0, 0x83, 0x87,
  0x8F, 0xCD, 0x00, 0x00, 0x7D, 0xFF, 0xC7, 0xBF, 0xF3, 0xC1, 0x00, 0xF8, 0xE0, 0x80, 0xC0, 0xE0,
  0xF0, 0xFB, 0x85, 0x00, 0x03, 0xE0, 0xF8, 0xEB, 0x7B, 0x82, 0x3F, 0x82, 0x1F, 0x08, 0x86, 0x07,
  0x33, 0x38, 0x18, 0x80, 0xC3, 0xFF, 0xFF, 0x82, 0x7F, 0x0B, 0xFF, 0xF1, 0xE0, 0xC0, 0xFC, 0xF2,
  0xFC, 0xFF, 0xFC, 0xF0, 0xE0, 0xE0, 0x82, 0x00, 0x06, 0x01, 0x03, 0x07, 0x06, 0x0D, 0x0F, 0x3F,
  0x82, 0xFF, 0x00, 0x7F, 0x83, 0xFF, 0x09, 0xF7, 0xBF, 0xFB, 0xDF, 0xFF, 0xFF, 0xC2, 0xC5, 0xE3,
  0xFF, 0x82, 0xFE, 0x10, 0xFC, 0xE0, 0xE0, 0xE7, 0x0F, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00, 0xC0,
  0xF0, 0xFC, 0xFE, 0x7F, 0xFF, 0x86, 0x00, 0x04, 0x9E, 0x0B, 0x03, 0x06, 0x04, 0x83, 0x00, 0x3B,
  0xFF, 0xBF, 0x7C, 0xF0, 0xC3, 0x87, 0x0F, 0x0F, 0xF0, 0x0F, 0x3F, 0xFC, 0xFB, 0xF7, 0x87, 0x7B,
  0x03, 0xFF, 0xFF, 0x3F, 0xDF, 0xEF, 0x8F, 0x73, 0x85, 0xC3, 0xC7, 0xEF, 0xFE, 0xFD, 0xFD, 0xFE,
  0xBF, 0x9F, 0xBF, 0x7F, 0xFF, 0xBF, 0x7F, 0xEF, 0xE1, 0xC0, 0xE4, 0xE1, 0xE8, 0xE5, 0xC1, 0x97,
  0x00, 0x80, 0x80, 0xC0, 0xC0, 0x80, 0x80, 0x00, 0x1E, 0x1E, 0x3E, 0x3E, 0x82, 0x3F, 0x05, 0x1F,
  0xFC, 0xFD, 0xFB, 0xE7, 0x1F, 0x82, 0xFF, 0x12, 0xED, 0xDD, 0xFA, 0xF6, 0xFE, 0xFD, 0xFB, 0xF3,
  0xFE, 0x87, 0x03, 0x81, 0xC0, 0xE1, 0xFF, 0xFF, 0xDF, 0x3C, 0xC2, 0x83, 0xFF, 0x08, 0xDF, 0x7C,
  0x00, 0xF0, 0xFC, 0xFF, 0xFF, 0xEF, 0xEF, 0x84, 0x00, 0x05, 0xC0, 0xF0, 0xFF, 0x1F, 0x0F, 0x03,
  0x84, 0x00, 0x81, 0xFF, 0x01, 0xFE, 0xF0, 0x83, 0x00, 0x01, 0xE1, 0x80, 0x85, 0x00, 0x01, 0xFF,
  0xFE, 0x84, 0xFF, 0x15, 0x7F, 0x8F, 0x0F, 0xE7, 0xF8, 0xFE, 0xFF, 0xDF, 0xDF, 0xE7, 0xC7, 0x83,
  0x03, 0x01, 0x81, 0xE1, 0xFF, 0xBF, 0x77, 0xF8, 0xF8, 0xB8, 0x82, 0xC0, 0x02, 0x7F, 0x3F, 0x1F,
  0x84, 0x00, 0x03, 0xCF, 0x8F, 0x07, 0x07, 0x83, 0x03, 0x81, 0x00, 0x00, 0x3F, 0x82, 0x00, 0x19,
  0xFC, 0x00, 0x01, 0x02, 0x07, 0x0F, 0x1F, 0x3E, 0x7E, 0xFC, 0x01, 0x02, 0x07, 0x0D, 0x1B, 0x36,
  0x2B, 0x55, 0xFC, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x84, 0x00, 0x02, 0x01, 0xFF, 0x7E,
  0x82, 0x00, 0x21, 0x03, 0x1A, 0xBB, 0xC7, 0xD5, 0x00, 0x00, 0x01, 0x83, 0xC6, 0xFD, 0xFE, 0xFD,
  0x6B, 0xD7, 0xAB, 0x57, 0xAA, 0x56, 0xAC, 0x54, 0x84, 0x88, 0x08, 0x10, 0x10, 0x20, 0x04, 0x08,
  0x1F, 0x03, 0x00, 0x00, 0x01, 0x82, 0x00, 0x1A, 0xAA, 0xD5, 0x3A, 0x07, 0xC1, 0x30, 0x00, 0x0C,
  0xFE, 0x5F, 0xFF, 0x5F, 0xFF, 0x2F, 0x1F, 0x3D, 0xE8, 0xB0, 0xC0, 0xFC, 0xFC, 0x7C, 0xBC, 0xD8,
  0x1D, 0x0E, 0x02, 0x84, 0x00, 0x12, 0xD0, 0xE0, 0x08, 0x8E, 0xE6, 0x63, 0x30, 0x00, 0x44, 0xAA,
  0x2A, 0x4A, 0x8A, 0x8A, 0xE4, 0x00, 0x4E, 0xA2, 0xA2, 0x82, 0xA4, 0x1A, 0x44, 0x00, 0x73, 0xDB,
  0xC3, 0x73, 0x1B, 0xDB, 0x73, 0x00, 0xCF, 0x6C, 0x6C, 0x6F, 0xCC, 0x0C, 0x0F, 0x00, 0xBE, 0x30,
  0x30, 0x3C, 0x30, 0x30, 0xBE, 0x00, 0xF0, 0x84, 0xD8, 0x0B, 0xF0, 0x00, 0x70, 0xD8, 0x18, 0x30,
  0x60, 0x00, 0x60, 0x00, 0x06, 0x0E, 0x83, 0x06, 0x00, 0x0F, 0x83, 0x00, 0x00, 0x1C, 0x83, 0x00,
  0x06, 0x38, 0x6C, 0x0C, 0x18, 0x0C, 0x6C, 0x38, 0xFE, 0x00, 0xFE, 0x00, 0x82, 0x00, 0xFF};

const u8 COLORRLE[] = {
  0xDF, 0x41, 0x83, 0xEF, 0x83, 0xE7, 0x83, 0x23, 0x83, 0x2C, 0x83, 0xAB, 0x81, 0xA9, 0x01,
  0xA8, 0xA6, 0x83, 0x86, 0x81, 0x89, 0x81, 0x8B, 0x83, 0x23, 0x83, 0x2C, 0x83, 0x23, 0x83, 0x2C,
  0x83, 0x23, 0x83, 0x2C, 0x83, 0x23, 0x82, 0x2C, 0x00, 0xC1, 0x83, 0x23, 0x81, 0x2C, 0x81, 0xC1,
  0x83, 0x23, 0x00, 0x2C, 0x82, 0xC1, 0x83, 0x23, 0x83, 0xC1, 0x82, 0x23, 0x00, 0x21, 0x83, 0xC1,
  0x81, 0x23, 0x81, 0x21, 0x83, 0xC1, 0x02, 0x23, 0x21, 0x21, 0x84, 0xC1, 0x81, 0x21, 0x85, 0xC1,
  0x00, 0x21, 0xA6, 0xC1, 0x87, 0x41, 0x81, 0xF1, 0x00, 0xA1, 0x82, 0xF1, 0x04, 0xE1, 0xA1, 0x61,
  0x69, 0x6A, 0x84, 0x61, 0x87, 0x2A, 0x87, 0x42, 0x87, 0x2A, 0x87, 0x42, 0xFE, 0x41, 0xFE, 0x41,
  0xFE, 0x41, 0xFE, 0x41, 0xFE, 0x41, 0xCC, 0x41, 0xFE, 0xF1, 0xC0, 0xF1, 0x87, 0xB1, 0x8B, 0xE1,
  0x83, 0xED, 0x82, 0xE1, 0x83, 0xED, 0x84, 0xE1, 0x82, 0xED, 0xA6, 0xE1, 0x81, 0xEF, 0x97, 0xE1,
  0x04, 0x5F, 0x1F, 0x5F, 0x1F, 0x5F, 0x87, 0xEF, 0x82, 0xED, 0x97, 0xE1, 0x87, 0xE8, 0x82, 0xED,
  0x00, 0xE1, 0x82, 0xEF, 0x83, 0xE1, 0x84, 0xEF, 0x85, 0xE1, 0x00, 0xEF, 0xA8, 0xE1, 0x83, 0xEF,
  0x8B, 0xE1, 0x87, 0xEF, 0xA0, 0xE1, 0x86, 0xEF, 0xDF, 0xE1, 0x87, 0x71, 0xA2, 0xE1, 0x02, 0xF1,
  0xA1, 0xB1, 0x83, 0xE1, 0x82, 0xF1, 0xBC, 0xE1, 0x81, 0x91, 0x02, 0x81, 0x61, 0x61, 0xD0, 0xF1,
  0xFE, 0x41, 0xFC, 0x41, 0x83, 0x41, 0xFF};
<file_sep>#include <coleco.h>

/* Sound#1 : "beep" */
static const u8 egg_snd[] = {
    0x43,0x00,0x72,5,0x11,0x90,0xF3,0x11,
    0x50};

static const u8 jump_snd[] = {
    0x83,0x90,0x11,0x07,0x13,0xe1,0x18,0x11,
    0x90};

static const u8 fire_snd[] = {
    /* white noise - freq 3495 Hz - vol 9 (max) swept down - length 31 */
    0x02,0x64,0x1f,0x1e,0x54,
    0x10};

static const u8 inv_snd[] = {
    0xc3,0x56,0xe3,0x40,0x11,0xfa,0xc0,0x44,
    0xc3,0x56,0xe3,0x30,0x11,0xf5,0xc0,0x33,
    0xc3,0x56,0xe3,0x20,0x11,0xea,0xc0,0x22,
    0xc2,0x97,0x20,0x4c,0x1e,0x5b,
    0xd0};

static const u8 bird_snd[] = {
    0x43,0xa2,0xe0,0x10,0x11,0xfa,0x90,0x11,
    0x43,0x70,0xe0,0x08,0x11,0xfa,0xa0,0x12,
    0x50};
    
extern const u8 music_ch1[];
extern const u8 music_ch2[];
    
const sound_t snd_table[] = {
    {egg_snd,SOUNDAREA1},
    {jump_snd,SOUNDAREA2},
    {fire_snd,SOUNDAREA3},
    {inv_snd,SOUNDAREA4},
    {bird_snd,SOUNDAREA5},
    {music_ch1,SOUNDAREA1},
   `{music_ch2,SOUNDAREA2}};
<file_sep>cmake_minimum_required (VERSION 3.1)

project(cvmkcart C)

set(cvmkcart_major_version 1)
set(cvmkcart_minor_version 0)
set(cvmkcart_path_version 0)
set(cvmkcart_version "${cvmkcart_major_version}.${cvmkcart_minor_version}.${cvmkcart_path_version}")

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE "Debug")
endif()

set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}")

set(CMAKE_C_STANDARDS 11)

configure_file(config.h.in config.h)

set(cvmkcart_sources
    cvmkcart.c
)

set(cvmkcart_headers
    cvmkcart.h
    config.h
)

add_executable(cvmkcart ${cvmkcart_sources} ${cvmkcart_headers})
target_compile_options(cvmkcart PRIVATE -Wall -Wshadow -Wextra)
target_include_directories(cvmkcart PRIVATE ${CMAKE_BINARY_DIR})

install(TARGETS cvmkcart RUNTIME DESTINATION bin)
<file_sep>/*---------------------------------------------------------------------------------


	small game from coder <NAME> : Diamond Dash
		made by her during 2004 MiniGame Competition 
		https://web.archive.org/web/20050204071935/http://www.ffd2.com/minigame/
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "diamond.h"

#include "dash.h"											// main file for game
#include "snds.h"											// to add definition of sounds

const u8 game_title[] = {40,41,42,43,44,45,46,47,0};		// Char array for "DIAMOND DASH!!"

//---------------------------------------------------------------------------------
// The NMI routine. Gets called 50 or 60 times per second 
// nothing to update for game example
void nmi (void) {
}

//---------------------------------------------------------------------------------
void main (void) {
	// Put sound table and mute all channel
	snd_settable(snd_table);
	snd_stopall();
	
	// Put screen in text mode 2 and sprite in 8x8 pixels size
	vdp_disablescr();
	
	vdp_setmode2txt();
	spr_mode8x8();
	
	// Initialise graphics and sounds 
	init_graphics();
	
	// Set a "stop point" to let the Video Chip knows that there is only 1 sprite to show
	sprites[1].y=208;
	
	// Show a new mountain & Show "DIAMOND DASH!!" in center screen 
	new_mountain(); 
	show_score();
	vdp_putstring(12,11,game_title);
	vdp_enablescr();
	
	// Wait until player press fire
	vdp_enablenmi(); sys_pause(); vdp_disablenmi();

	// Play game
	game();
	// END
	// startup module will issue a soft reboot if it comes here 
}
<file_sep>#ifndef _SIMPLESPR_MAIN_
#define _SIMPLESPR_MAIN_

#include <coleco.h>

#endif
<file_sep>/*---------------------------------------------------------------------------------

	Generic score functions.

	Copyright (C) 2018-2019
		Alekmaul

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:

	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.
	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.
	3.	This notice may not be removed or altered from any source
		distribution.


---------------------------------------------------------------------------------*/
/**
 * \file score.h
 * \brief coleco generic score support.
 *
 * This unit provides methods to manage scores.<br>
 *<br>
 * Here is the list of supported features:<br>
 * - scores with more than 65536 values<br>
 * - reset, compare, add scores<br>
 * - convert a score to a string for display purpose<br>
*/

#ifndef COL_SCORE_H
#define COL_SCORE_H

#include <coleco/coltypes.h>

/**
 * \struct score_t
 * \brief score value 
 * Can manage score with more than 65536 values (max of an unsigned)
 */
typedef struct { 
 unsigned lo;			/*!< low value of the score */
 unsigned hi;			/*!< high value of the score */
} score_t;

/**
 * \fn void sys_scoclear(score_t *sco)
 * \brief Init a score variable with value 0
 *
 * \param sco score variable to reset
*/
void sys_scoclear(score_t *sco);

/**
 * \fn void sys_scoadd(score_t *sco, unsigned value)
 * \brief Add a unsigned value to a score variable
 *
 * \param sco score variable 
 * \param value value to add to score
*/
void sys_scoadd(score_t *sco, unsigned value); 

/**
 * \fn u16 sys_scocmp(score_t *sco1,score_t *sco2)
 * \brief Compare two scores and return 1 if 1st one is lower than 2nd one
 *
 * \param sco1 score variable 
 * \param sco2 score variable 
 * \return 1 if sco1 is lower than sco2, 0 if not, 0xFF if equals
*/
u16 sys_scocmp(score_t *sco1,score_t *sco2);

/**
 * \fn void sys_scocpy(score_t *sco1,score_t *sco2)
 * \brief Copy a score sco1 into another score sco2
 * 
 * \param sco1 score variable 
 * \param sco2 score variable 
*/
void sys_scocpy(score_t *sco1,score_t *sco2);

/**
 * \fn char *sys_scostr(score_t *sco, unsigned length)
 * \brief Convert a score variable to a string of specific length
 *
 * \param sco score variable 
 * \param length number of digits for displkay (max 9)
 * \return char * string value of score
*/
char *sys_scostr(score_t *sco, unsigned length);

#endif
<file_sep>/*---------------------------------------------------------------------------------

	Copyright (C) 2018-2019

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:


	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.

	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.

	3.	This notice may not be removed or altered from any source
		distribution.

---------------------------------------------------------------------------------*/
/*! \file coleco.h
\brief the master include file for colecovision applications.
*/

/*!
 \mainpage PVcollib Documentation


 \section intro Introduction
 Welcome to the PVcollib reference documentation.

 \section console_mngt Generic console feature
 - \ref console.h "Console management"

 \section sound_sn76489 sound engine API
 - \ref sound.h "General sound"

 \section video_tms9918 2D engine API
 - \ref video.h "General video"

 \section video_f18a F18A video device API
 - \ref f18a.h "F18A specific video"
 
 \section pad_mngt Generic pad & spinner API
 - \ref pad.h "General pad & spinner"

 \section sprite_mngt Generic sprites API
 - \ref sprite.h "General sprites"

 \section score_mngt Generic score API
 - \ref score.h "General scores"

 \section SGM Generic API
 - \ref sgm.h "General SGM"

 \section external_links Useful links
 - <a href="http://atariage.com/forums/forum/55-colecovision-programming/">AtariAge ColecoVision development forum.</a>
 - <a href="https://atariage.com/forums/topic/280138-f18a-mk2/">AtariAge F18A development topic.</a>
 
 \section special_thanks Special Thanks
 - <NAME> (aka newcoleco) for cvlib source code, which are parts of PVcollib.
 - <a href="https://sourceforge.net/projects/sdcc/files/"><NAME></a> - SDCC Release Manager. 
 - AtariAge member <a href="http://eriscreations.com/">digress</a> for his help about F18A programming on Coleco.
 - AtariAge member <a href="http://codehackcreate.com/archives/592">matthew180</a> for his help on discord about F18A device, thanks for making it real matthew ;) !.
*/


//adding the example page.
/*!
 <!-- EXAMPLES -->
    <!-- hello world -->
		\example helloworld/helloworld.c

    <!-- diamond game -->
		\example games/diamond/diamond.c

    <!-- graphic management -->
		\example graphics/backgrounds/dancompress/grafdancomp.c
		\example graphics/backgrounds/notcompress/grafnocomp.c
		\example graphics/backgrounds/plecompress/grafplecomp.c
		\example graphics/backgrounds/rlecompress/grafrlecomp.c
		\example graphics/sprites/simplesprite/simplesprite.c
		\example graphics/sprites/animatedsprite/animatedsprite.c
	
	<!-- f18a gaphic management -->
		\example graphics/f18a/f18abitmap1/f18abitmap1.c
		\example graphics/f18a/f18aecm3/f18aecm3.c
		\example graphics/f18a/f18atest/f18atest.c
	
    <!-- pad management -->
		\example input/input.c

    <!-- random numbers -->
		\example random/randvalue.c

    <!-- megacart management -->
		\example megacart/megacart.c
		
    <!-- region detection -->
		\example palntsc/palntsc.c

    <!-- score management -->
		\example scoring/scoring.c

	<!-- sgm system management -->
		\example sgm/sgmtest/sgmtest.c

    <!-- sound management -->
		\example audio/music/music.c
		\example audio/simplesound/ssound.c
*/

#ifndef COL_INCLUDE
#define COL_INCLUDE

#include <coleco/coltypes.h>

#include "coleco/console.h"
#include "coleco/pad.h"
#include "coleco/score.h"
#include "coleco/sound.h"
#include "coleco/sprite.h"
#include "coleco/video.h"
#include "coleco/f18a.h"
#include "coleco/sgm.h"

#endif // COL_INCLUDE
<file_sep>#ifndef _GRAFNOCMP_MAIN_
#define _GRAFNOCMP_MAIN_

#include <coleco.h>

extern void init_graphics(void);
extern void new_mountain(void);
extern void game(void);
extern void show_score(void);

#endif
<file_sep>#ifndef _MEGACART_GFXS1_
#define _MEGACART_GFXS1_

#include <coleco.h>

#include "image1gfx.h"		// generetad by gfx2col

#endif
<file_sep># A C library for the ColecoVision #
![PVcollib](https://www.portabledev.com/wp-content/uploads/2019/11/pvcollib_logo.png)

PVcollib V1.5.1 (09, 20, 2020)  

PVcollib is an open and free library to develop programs for ColecoVision in C language.

It contains sdcc compiler / linker and a library (sources included) which offer facilities to use backgrounds / sprites / pads / music & sound on ColecoVision system.   
Sdcc compiler from <NAME> - SDCC Release Manager  (https://sourceforge.net/projects/sdcc/files/).  
C Library is based on works from Amy Purple (aka newcoleco), a great Colecovision coder and music composer (<no website currently>).  
A great thanks to Amy Purple continuing to help me to improve the library, thanks to her !
F18A support from matthew180 (http://codehackcreate.com/archives/592) with the help of digress (http://eriscreations.com) on Colecovision.  
NMI cautions in ctrcol.s from Tursi (http://www.harmlesslion.com/cgi-bin/showprog.cgi?ColecoVision), thanks to him !

It also contains examples to help how to use functions with the library. You can find the Doxygen documentation of the library in the ['docs'](pvcollib/docs/html/files.html) directory.  

GitHub page: https://github.com/alekmaul/pvcollib    
Wiki page: https://github.com/alekmaul/pvcollib/wiki  
Doc page: https://www.portabledev.com/pvcollib/doc

You can find tutorials about how install and use PVCollib on this page: https://github.com/alekmaul/pvcollib/wiki/Introduction

We now have a Discord :D, just join us with this link : https://discord.gg/8kAHJgj  

PVcollib and affiliated tools are distributed under the MIT license (see pvcollib_license.txt file)  

PVcollib is completly free and you can support it through the Paypal button:    
[![Paypal](https://www.paypalobjects.com/fr_FR/FR/i/btn/x-click-but04.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=Y5USKF23DQVLC)  

Thanks and happy coding =) !

<file_sep>/*---------------------------------------------------------------------------------


	megacart demo with 3 banks
	images from Amy Purple post (newcoleco) here:
		https://atariage.com/forums/topic/268244-data-compression-benchmark-dan-pletter-zx7-exomizer-pucrunch-megalz/
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "megacart.h"

#include "gfxsb1.h"									// to add definition of graphics
#include "gfxsb2.h"									// to add definition of graphics
#include "gfxsb3.h"									// to add definition of graphics

// Switch of the banks
#define SWITCH_IN_BANK1		{ dummy=(*(volatile unsigned char*) 0xFFF8); } // b1 with 16k
#define SWITCH_IN_BANK2		{ dummy=(*(volatile unsigned char*) 0xFFF9); } // b2 with 16k
#define SWITCH_IN_BANK3		{ dummy=(*(volatile unsigned char*) 0xFFFA); } // b3 with 16k
#define SWITCH_IN_BANK4		{ dummy=(*(volatile unsigned char*) 0xFFFB); } // b4 with 16k
#define SWITCH_IN_BANK5		{ dummy=(*(volatile unsigned char*) 0xFFFC); } // b5 with 16k
#define SWITCH_IN_BANK6		{ dummy=(*(volatile unsigned char*) 0xFFFD); } // b6 with 16k
#define SWITCH_IN_BANK7		{ dummy=(*(volatile unsigned char*) 0xFFFE); } // b7 with 16k
#define SWITCH_IN_BANK8		{ dummy=(*(volatile unsigned char*) 0xFFFF); } // b8 with 16k

// var for bank switching
unsigned char dummy;

//---------------------------------------------------------------------------------
// The NMI routine. Gets called 50 or 60 times per second 
// nothing to update for bitmap example
void nmi (void) {
}

//---------------------------------------------------------------------------------
void initvramIMG1(void) {
	// Disable Interrupt 
	vdp_waitvblank(1);
	vdp_disablescr();
	
	SWITCH_IN_BANK1;
	
	// Put image in vram  
	vdp_dan12vram (TILimage1gfx, chrgen); // characters
	vdp_dan12vram (COLimage1gfx, coltab); // colors
	vdp_dan12vram (MAPimage1gfx, chrtab); // map

	// enable interrupt
	vdp_enablescr(); 
    vdp_enablenmi();
}

//---------------------------------------------------------------------------------
void initvramIMG2(void) {
	// Disable Interrupt 
	vdp_waitvblank(1);
	vdp_disablescr();
	
	SWITCH_IN_BANK2;
	
	// Put image in vram  
	vdp_dan12vram (TILimage2gfx, chrgen); // characters
	vdp_dan12vram (COLimage2gfx, coltab); // colors
	vdp_dan12vram (MAPimage2gfx, chrtab); // map

	// enable interrupt
	vdp_enablescr(); 
    vdp_enablenmi();
}

//---------------------------------------------------------------------------------
void initvramIMG3(void) {
	// Disable Interrupt 
	vdp_waitvblank(1);
	vdp_disablescr();
	
	SWITCH_IN_BANK3;
	
	// Put image in vram  
	vdp_dan12vram (TILimage3gfx, chrgen); // characters
	vdp_dan12vram (COLimage3gfx, coltab); // colors
	vdp_dan12vram (MAPimage3gfx, chrtab); // map

	// enable interrupt
	vdp_enablescr(); 
    vdp_enablenmi();
}

//---------------------------------------------------------------------------------
void main (void) {
	// Put screen in bitmapmode 2
	vdp_disablescr();
	
	vdp_setmode2bmp();
	
    // Enable screen 
	vdp_enablescr();
	
	// Put 1st image
	initvramIMG1();
	
	// Wait for nothing :P
	while(1) {
		// change image regarding joypad
	    if ( (joypad_1 & PAD_RIGHT) ) initvramIMG1();
		if ( (joypad_1 & PAD_LEFT) ) initvramIMG2();
		if ( (joypad_1 & PAD_FIRE1) ) initvramIMG3();

		// Wait Vblank
		while (joypad_1) { vdp_waitvblank(1); }
		vdp_waitvblank(1);
	}
	// startup module will issue a soft reboot if it comes here 
}
<file_sep>#ifndef _BUNNY_MAIN_
#define _BUNNY_MAIN_

#include <coleco.h>

#define NONE 0x00
#define ICE 0x01
#define GRASS 0x02
#define SAND 0x04
#define AIR 0x08

extern const sound_t snd_table[];

extern u8 read_next_code(u8 *item, u8 code);
extern void invincible(u8 i);
extern void player_sprite (u8 i);
extern void player_color (void);

/* Data from "graphics.c" to initialise graphics */
extern const u8 NAMERLE[];
extern const u8 PATTERNRLE[];
extern const u8 COLORRLE[];

extern const u8* levels[];

#endif
<file_sep>/****************************************************************************/
/**                                                                        **/
/**                                 cch.c                                  **/
/**                                                                        **/
/** ColecoVision Cosmo Challenge game main module                          **/
/**                                                                        **/
/** Copyright (C) <NAME> 1997                                     **/
/**     You are not allowed to distribute this software commercially       **/
/**     Please, notify me, if you make any changes to this file            **/
/****************************************************************************/
#include "cosmoc.h"

/* when his health bar reaches 0, one dies */
static u8 player1_health,player2_health;
/* incremented every interrupt */
static u8 nmi_count;
/* if 1, the title and intro screens have been displayed */
static u8 game_running;
/* 0=one player, 1=two players */
static u8 game_mode;

/* scrolling stones buffer */
static u8 stone_vram[96*2];
/* next stone type to put in buffer */
static u8 stonea,stoneb;

/* scroll stone stuff one character */
static void scroll_stones (void)
{
 register u8 a;
 /* scroll old buffer */
 sys_memcpyb (stone_vram,stone_vram+1,95);
 sys_memcpyb (stone_vram+97,stone_vram+96,95);
 /* check new stones */
 if (!stonea)
 {
  a=sys_random();
  if (a<16) stonea=((a&3)<<2)+128+16+32;
 }
 if (!stoneb)
 {
  a=sys_random();
  if (a<16) stoneb=((a&3)<<2)+3+32;
 }
 /* put new stones in buffer */
 if (stonea)
 {
  stone_vram[31]=stonea-32;
  stone_vram[31+32]=stonea;
  stone_vram[31+64]=stonea+32;
  stonea++;
  if ((stonea&3)==0) stonea=0;
 }
 else
  stone_vram[31]=stone_vram[31+32]=stone_vram[31+64]=96;
 if (stoneb)
 {
  stone_vram[96]=stoneb-32;
  stone_vram[128]=stoneb;
  stone_vram[160]=stoneb+32;
  stoneb--;
  if ((stoneb&3)==3) stoneb=0;
 }
 else
  stone_vram[96]=stone_vram[128]=stone_vram[160]=96;
}

/* The NMI routine. Gets called 50 or 60 times per second */
void nmi (void)
{
 static u8 stone_count;
 register u8 i;
 nmi_count++;
 /* if intro screen is being displayed, return immediately */
 if (!game_running) return;
 /* Update sprites */
 vdp_putvram(sprgen+8*4,sprites,(32-8)*4);
 /*
 update_sprites (32-8,sprgen+8*4);
 */
 
 /* update stone display */
 switch (stone_count)
 {
  case 6:
   /* scroll 2 pixels */
   vdp_putvramex (chrtab+256,stone_vram,96,0xff,128);
   vdp_putvramex (chrtab+384,stone_vram+96,96,0xff,128);
   break;
  case 4:
   /* scroll 4 pixels */
   vdp_putvramex (chrtab+256,stone_vram,96,0xff,16);
   vdp_putvramex (chrtab+384,stone_vram+96,96,0xff,16);
   break;
  case 2:
   /* scroll 6 pixels */
   vdp_putvramex (chrtab+256,stone_vram,96,0xff,128|16);
   vdp_putvramex (chrtab+384,stone_vram+96,96,0xff,128|16);
   break;
  case 1:
   /* update buffer, will be uploaded next call */
   scroll_stones ();
   break;
  case 0:
   /* upload stone stuff to vram */
   vdp_putvram (chrtab+256,stone_vram,96);
   vdp_putvram (chrtab+384,stone_vram+96,96);
   stone_count=8;
   break;
 }
 stone_count--;
 /* update stars */
 if ((nmi_count&1)==0)
 {
  i=((nmi_count>>1)&7)+16;
  sprites[i].y=sys_random();
  sprites[i].x=sys_random();
  sprites[i].pattern=28+(sys_random()&4);
  sprites[i].colour=sys_random()&15;
 }
}

const sprite_t sprites_init[]=
{
 /* ship A */
 { 166,60,4,15 },
 { 166,60,8,4 },
 { 166,60,12,8 },
 /* ship B */
 { 8,180,16,15 },
 { 8,180,20,4 },
 { 8,180,24,8 },
 /* 5 bullets each */
 { 207,0,0,11 },
 { 207,0,0,11 },
 { 207,0,0,11 },
 { 207,0,0,11 },
 { 207,0,0,11 },
 { 207,0,0,11 },
 { 207,0,0,11 },
 { 207,0,0,11 },
 { 207,0,0,11 },
 { 207,0,0,11 },
 /* 8 stars */
 { 207,0,28,14 },
 { 207,0,28,14 },
 { 207,0,28,14 },
 { 207,0,28,14 },
 { 207,0,28,14 },
 { 207,0,28,14 },
 { 207,0,28,14 },
 { 207,0,28,14 }
};

/* to prevent sprites being displayed on the status bar */
const sprite_t default_sprgen[]=
{
 { -9,0,0,0 },
 { -9,0,0,0 },
 { -9,0,0,0 },
 { -9,0,0,0 },
 { 183,0,0,0 },
 { 183,0,0,0 },
 { 183,0,0,0 },
 { 183,0,0,0 } // Overflow Warning Making no sense!
};

void show_player1_health_bar (u8 n)
{
 register u8 i;
 if (n && player1_health)
 {
  vdp_fillvram (chrtab+736,1,player1_health);
  i=32-player1_health;
  if (i)
   vdp_fillvram (chrtab+736+player1_health,2,i);
 }
 else
  vdp_fillvram (chrtab+736,2,32);
}

void show_player2_health_bar (u8 n)
{
 register u8 i;
 if (n && player2_health)
 {
  vdp_fillvram (chrtab,1,player2_health);
  i=32-player2_health;
  if (i)
   vdp_fillvram (chrtab+player2_health,2,i);
 }
 else
  vdp_fillvram (chrtab,2,32);
}

void player1_is_hit (int spritenr)
{
 sprites[spritenr].y=207;
 if (player1_health)
 {
     player1_health--;
     if (player1_health==4) {
         /* play sound low health */
         snd_startplay(1);
     }
     snd_startplay(3);
     /* play shound hit */
  show_player1_health_bar(1);
 }
}

void player2_is_hit (int spritenr)
{
 sprites[spritenr].y=207;
 if (player2_health)
 {
     player2_health--;
     if (player2_health==4) {
         /* play sound low health */
         snd_startplay(1);
     }
     snd_startplay(3);
     /* play shound hit */
  show_player2_health_bar(1);
 }
}

void stone_is_hit (int spritenr)
{
  sprites[spritenr].y=207;
  snd_startplay(4);
}

u8 check_stone (u8 spritenr)
{
 register unsigned n;
 n=(sprites[spritenr].y)>>3;
 n-=8;
 if (n&0xf8) return 0;
 if (n==3 || n==7) return 0;
 if (n&4) --n;
 n<<=5;
 n+=(sprites[spritenr].x>>3);
 return stone_vram[n]!=96;
}

void _fill_vram (unsigned offset,u8 value,unsigned count)
{
 vdp_disablenmi();
 vdp_fillvram (offset,value,count);
 vdp_enablenmi();
}

static void vdp_showpicture(void *picture)
{
	vdp_disablescr();
	vdp_disablenmi();
	vdp_rle2vram(vdp_rle2vram(picture,coltab),chrgen);
	vdp_enablescr();
	vdp_enablenmi();
}

static void title (void)
{
 /* initialise name table */
 vdp_setmode2bmp();
 /* show title screen */
 vdp_showpicture(title_screen);
 sys_pause();
 /* show intro screen */
 vdp_showpicture(intro_screen);
 sys_pause();
}

static const u8 red_font[8]= { 0x61,0x61,0x81,0x81,0x81,0x91,0x91,0x91 };
static const u8 yellow_font[8]= { 0xa1,0xa1,0xb1,0xb1,0xb1,0xf1,0xf1,0xf1 };

void init_vdp (void)
{
 u8 i;
 vdp_setmode2bmp();
 /* Disable Interrupt */
 vdp_disablenmi();
 /* special color for the middle section */   
 vdp_setreg(3,0xbf); 
 /* Upload first 8 sprites */
 vdp_putvram (sprgen,default_sprgen,sizeof(default_sprgen));
 /* Fill colour table */
 vdp_putvram_repeat (coltab,yellow_font,8,0); // 0 = 256
 vdp_putvram_repeat (coltab+'0'*8,red_font,8,10);
 /* Clear Characters Pattern Table */
 vdp_fillvram (chrgen,0x00,0x0800);
 /* Upload ASCII character patterns */
 vdp_setdefaultchar(FNTBOLD_ITALIC); // (29,128-29,chrgen+29*8,BOLD_ITALIC);
 /* Health indicator */
 vdp_fillvram (chrgen+9,0x55,6);
 vdp_fillvram (coltab+8,0x90,16);
 /* Duplicate Charset to the other 2 screen section */
 vdp_duplicatevram();
 /* Upload stones character definitions */
 vdp_rle2vram (vdp_rle2vram(stone_characters,coltab+256*8),chrgen+256*8);
 /* Upload sprite patterns */
 vdp_rle2vram (sprite_patterns,sprtab);
 /* clear screen display */
 vdp_fillvram (chrtab,32,768);
 /* Fill part 2 of name table */
 vdp_fillvram (chrtab+256,96,256);
 /* Scroll in stones */
 for (i=32;i!=0;--i) scroll_stones ();
 /* Blue screen border */
 vdp_setreg(7,0xf4);
 /* turn display on */
 vdp_enablescr();
 /* enable NMI */
 vdp_enablenmi();
}

void choice (void)
{

 _fill_vram (chrtab+0,1,32);
 _fill_vram (chrtab+736,1,32);
 _fill_vram (chrtab+18*32,0,64);
 
 vdp_putstring(8,18,"1 - One player ");
 vdp_putstring(8,19,"2 - Two players");
 /* wait until all keys released */
 while (keypad_1!=0xff || keypad_2!=0xff);
 /* get choice */
 game_mode=255;
 while (game_mode==255)
 {
  if (keypad_1==1 || keypad_2==1) game_mode=0;
  if (keypad_1==2 || keypad_2==2) game_mode=1;
 }
 
 _fill_vram (chrtab+18*32,0,64);
 
}

void main (void)
{
  u8 i;
  u8 old_joypad_1,old_joypad_2;
  snd_settable(snd_table);
  title ();
  init_vdp ();
  /* set game_running flag, enables scrolling stones and blinking stars */
  game_running=1;
  /* clear NMI counter */
  nmi_count=255;
options:
  choice ();
play_again:
  player1_health=player2_health=32;
  show_player1_health_bar(1);
  show_player2_health_bar(1);
  sys_memcpyb (sprites,sprites_init,sizeof(sprites_init));
  old_joypad_1 = 8;
  old_joypad_2 = (sys_randbyte(0,1) == 0) ? 2 : 8;
  vdp_putstring(11,18,"Get ready");
  snd_startplay(9);
  snd_startplay(10);
  snd_startplay(11);
  vdp_waitvblank(150);
  
  _fill_vram (chrtab+18*32,0,64);
  
  old_joypad_1=0;
  old_joypad_2=0;
  while (1)
  {
   /* Wait for a VBLANK */
   vdp_waitvblank(1);
   if ((nmi_count&31)==0)
   {
    if (player1_health<5 || player2_health<5)
    {
     if (player1_health<5) show_player1_health_bar(nmi_count&32);
     if (player2_health<5) show_player2_health_bar(nmi_count&32);
    }
   }
   /* Let computer play */
   if (!game_mode)
   {
    /* direction, slightly random */
    joypad_2=old_joypad_2&0x0f;
    i=sys_random();
     if (i<24)
     {
         if (sprites[0].x<sprites[3].x)
         {
             joypad_2 = 8;
         }
         else
         {
             joypad_2 = 2;
         }
     }
    /* fire ? */
    if ((nmi_count&7)==0) joypad_2|=0x10;
   }
   /* Parse joysticks */
   if (joypad_1&2)
   {
    if (sprites[0].x<241)
     sprites[1].x=sprites[2].x=(++sprites[0].x);
   }
   if (joypad_1&8)
   {
    if (sprites[0].x)
     sprites[1].x=sprites[2].x=(--sprites[0].x);
   }
   if (joypad_2&2)
   {
    if (sprites[3].x<241)
     sprites[4].x=sprites[5].x=(++sprites[3].x);
   }
   if (joypad_2&8)
   {
    if (sprites[3].x)
     sprites[4].x=sprites[5].x=(--sprites[3].x);
   }
   if ((joypad_1^old_joypad_1)&joypad_1&0xf0)
   {
    for (i=6;i<11;++i) if (sprites[i].y==207) break;
    if (i<11)
    {
     sprites[i].y=sprites[0].y;
     sprites[i].x=sprites[0].x+7;
     snd_startplay(2);
    }
   }
   if ((joypad_2^old_joypad_2)&joypad_2&0xf0)
   {
    for (i=11;i<16;++i) if (sprites[i].y==207) break;
    if (i<16)
    {
     sprites[i].y=sprites[3].y+14;
     sprites[i].x=sprites[3].x+7;
     snd_startplay(2);
    }
   }
   old_joypad_1=joypad_1;
   old_joypad_2=joypad_2;
   if (player1_health && player2_health)
   {
    for (i=6;i<11;++i)
    {
     if (sprites[i].y!=207)
     {
      if (check_stone(i)) {
         stone_is_hit (i);
      }
      if (check_collision(sprites+i,sprites+3,0x303,0x303,0x1000,0x0e00)) {
         player2_is_hit (i);
      }
	  sprites[i].y-=4;
      if (sprites[i].y>192) sprites[i].y=207; // the warning makes no sense
     }
    }
    for (i=11;i<16;++i)
    {
     if (sprites[i].y!=207)
     {
      if (check_stone(i))
       stone_is_hit (i);
      if (check_collision(sprites+i,sprites+0,0x303,0x303,0x1000,0x0e02))
       player1_is_hit (i);
	   sprites[i].y+=4;
      if (sprites[i].y>192) sprites[i].y=207; // the warning makes no sense
     }
    }
   }
   else break;
  }
  i = 0;
  if (player1_health) {
      i = 3;
  }
  snd_startplay(5);
  snd_startplay(6);
  snd_startplay(7);
  snd_startplay(8);
  sprites[i].y=sprites[i+1].y=sprites[i+2].y=207;
  spr_clear(); // PROBLEM!!! it's supposed to be clear_sprites (start=6,count=10);
  vdp_putstring(9,18,"1 - Play again");
  vdp_putstring(9,19,"2 - Options   ");
  vdp_putstring(9,20,"3 - Intro     ");
  while ((keypad_1==0 || keypad_1>3) &&
         (keypad_2==0 || keypad_2>3));
  if (keypad_1==0 || keypad_1>3) i=keypad_2;
  else i=keypad_1;
  
  _fill_vram (chrtab+18*32,0,3*32);
  
  if (i==1) goto play_again;
  if (i==2) goto options;
  /* startup module will issue a soft reboot */
}
<file_sep>#ifndef _INPUT_MAIN_
#define _INPUT_MAIN_

#include <coleco.h>

#endif
<file_sep>/*-------------------------------------------------------------------------
   ds80c390.h - Register Declarations for the DALLAS DS80C390 Processor
                 far from complete, e.g. no CAN

   Copyright (C) 2000, <NAME> <johan.knol AT iduna.nl>

   This library is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License 
   along with this library; see the file COPYING. If not, write to the
   Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
   MA 02110-1301, USA.

   As a special exception, if you link this library with other files,
   some of which are compiled with SDCC, to produce an executable,
   this library does not by itself cause the resulting executable to
   be covered by the GNU General Public License. This exception does
   not however invalidate any other reasons why the executable file
   might be covered by the GNU General Public License.
-------------------------------------------------------------------------*/

#ifndef DS80C390_H
#define DS80C390_H

__sfr __at 0x80 P4; 		/* ce3..ce0, a19..a16 */
__sfr __at 0x81 SP; 		/* stack pointer */
__sfr __at 0x82 DPL; 		/* data pointer 0 lsb */
__sfr __at 0x83 DPH; 		/* data pointer 0 msb */
__sfr __at 0x84 DPL1; 		/* data pointer 1 lsb */
__sfr __at 0x85 DPH1; 		/* data pointer 1 msb */
__sfr __at 0x86 DPS; 		/* data pointer select */
__sfr __at 0x87 PCON; 		/* power control */
__sfr __at 0x88 TCON; 		/* timer/counter control */
  __sbit __at 0x88 IT0;
  __sbit __at 0x89 IE0;
  __sbit __at 0x8a IT1;
  __sbit __at 0x8b IE1;
  __sbit __at 0x8c TR0;
  __sbit __at 0x8d TF0;
  __sbit __at 0x8e TR1;
  __sbit __at 0x8f TF1;
__sfr __at 0x89 TMOD; 		/* timer mode control */
__sfr __at 0x8a TL0; 		/* timer 0 lsb */
__sfr __at 0x8b TL1; 		/* timer 1 msb */
__sfr __at 0x8c TH0; 		/* timer 0 msb */
__sfr __at 0x8d TH1; 		/* timer 1 msb */
__sfr __at 0x8e CKCON; 		/* clock control */
__sfr __at 0x90 P1;
  __sbit __at 0x90 T2;
  __sbit __at 0x91 T2EX;
  __sbit __at 0x92 RXD1;
  __sbit __at 0x93 TXD1;
  __sbit __at 0x94 INT2;
  __sbit __at 0x95 INT3;
  __sbit __at 0x96 INT4;
  __sbit __at 0x97 INT5;
__sfr __at 0x91 EXIF; 		/* external interrupt flag */
__sfr __at 0x92 P4CNT;
__sfr __at 0x93 DPX; 		/* extended datapointer 0 */
__sfr __at 0x95 DPX1; 		/* extended datapointer 1 */
__sfr __at 0x98 SCON0; 		/* serial 0 control */
  __sbit __at 0x98 RI_0;
  __sbit __at 0x99 TI_0;
  __sbit __at 0x9a RB8_0;
  __sbit __at 0x9b TB8_0;
  __sbit __at 0x9c REN_0;
  __sbit __at 0x9d SM2_0;
  __sbit __at 0x9e SM1_0;
  __sbit __at 0x9f SM0_0;
  __sbit __at 0x9f FE_0;	/* depending on SMOD0 */
__sfr __at 0x99 SBUF0;		/* serial 0 data buffer */
__sfr __at 0x9b ESP; 		/* extended stack pointer */
__sfr __at 0x9c AP; 		/* address page */
__sfr __at 0x9d ACON; 		/* address control */
__sfr __at 0xa0 P2; 		/* never mind the sbits */
__sfr __at 0xa1 P5;
__sfr __at 0xa2 P5CNT;
__sfr __at 0xa8 IE; 		/* interrupt enable */
  __sbit __at 0xa8 EX0;
  __sbit __at 0xa9 ET0;
  __sbit __at 0xaa EX1;
  __sbit __at 0xab ET1;
  __sbit __at 0xac ES0;
  __sbit __at 0xad ET2;
  __sbit __at 0xae ES1;
  __sbit __at 0xaf EA;
__sfr __at 0xb0 P3;
  __sbit __at 0xb0 RXD0;
  __sbit __at 0xb1 TXD0;
  __sbit __at 0xb2 INT0;
  __sbit __at 0xb3 INT1;
  __sbit __at 0xb4 T0;
  __sbit __at 0xb5 T1;
  __sbit __at 0xb6 WR;
  __sbit __at 0xb7 RD;
__sfr __at 0xb8 IP; 		/* interupt priority */
  __sbit __at 0xb8 PX0; 	/* external 0 */
  __sbit __at 0xb9 PT0; 	/* timer 0 */
  __sbit __at 0xba PX1; 	/* external 1 */
  __sbit __at 0xbb PT1; 	/* timer 1 */
  __sbit __at 0xbc PS0; 	/* serial port 0 */
  __sbit __at 0xbd PT2; 	/* timer 2 */
  __sbit __at 0xbe PS1; 	/* serial port 1 */
__sfr __at 0xc0 SCON1; 		/* serial 1 control */
  __sbit __at 0xc0 RI_1;
  __sbit __at 0xc1 TI_1;
  __sbit __at 0xc2 RB8_1;
  __sbit __at 0xc3 TB8_1;
  __sbit __at 0xc4 REN_1;
  __sbit __at 0xc5 SM2_1;
  __sbit __at 0xc6 SM1_1;
  __sbit __at 0xc7 SM0_1;
  __sbit __at 0xc7 FE_1;	/* depending on SMOD0 */
__sfr __at 0xc1 SBUF1; 		/* serial 1 data buffer */
__sfr __at 0xc4 PMR; 		/* power managment */
__sfr __at 0xc6 MCON; 		/* memory control register */
__sfr __at 0xc7 TA; 		/* timed access register */
__sfr __at 0xc8 T2CON; 		/* timer 2 control */
  __sbit __at 0xc8 CP_RL;	/* capture/reload */
  __sbit __at 0xc9 C_T; 	/* count/timer */
  __sbit __at 0xca TR2; 	/* stop/run */
  __sbit __at 0xcb EXEN2;
  __sbit __at 0xcc TCLK;
  __sbit __at 0xcd RCLK;
  __sbit __at 0xce EXF2;
  __sbit __at 0xcf TF2; 	/* overflow flag */
__sfr __at 0xc9 T2MOD; 		/* timer 2 mode */
__sfr __at 0xca RCAP2L; 	/* timer 2 capture/reload */
__sfr __at 0xca RTL2; 		/* depends on CP_RL */
__sfr __at 0xcb RCAP2H;
__sfr __at 0xcb RTH2;
__sfr __at 0xcc TL2; 		/* timer 2 lsb */
__sfr __at 0xcd TH2; 		/* timer 2 msb */
__sfr __at 0xd0 PSW; 		/* program status word (byte actually) */
  __sbit __at 0xd0 P; 		/* parity */
  __sbit __at 0xd1 F1; 		/* user flag 1 */
  __sbit __at 0xd2 OV; 		/* overflow flag */
  __sbit __at 0xd3 RS0; 	/* register select l */
  __sbit __at 0xd4 RS1; 	/* register select h */
  __sbit __at 0xd5 F0; 		/* user flag 0 */
  __sbit __at 0xd6 AC; 		/* auxiliary carry flag */
  __sbit __at 0xd7 CY; 		/* carry flag */
__sfr __at 0xd1 MCNT0; 		/* arithmetic accellerator */
__sfr __at 0xd2 MCNT1;
__sfr __at 0xd3 MA;
__sfr __at 0xd4 MB;
__sfr __at 0xd5 MC;
__sfr __at 0xd8 WDCON; 		/* watch dog */
  __sbit __at 0xd8 RWT;
  __sbit __at 0xd9 EWT;
  __sbit __at 0xda WDRF;
  __sbit __at 0xdb WDIF;
  __sbit __at 0xdc PFI;
  __sbit __at 0xdd EPFI;
  __sbit __at 0xde POR;
  __sbit __at 0xdf SMOD_1;
__sfr __at 0xe0 ACC; 		/* accumulator */
__sfr __at 0xe8 EIE; 		/* extended interrupt enable */
  __sbit __at 0xe8 EX2;
  __sbit __at 0xe9 EX3;
  __sbit __at 0xea EX4;
  __sbit __at 0xeb EX5;
  __sbit __at 0xec EWDI;
  __sbit __at 0xed C1IE;
  __sbit __at 0xee C0IE;
  __sbit __at 0xef CANBIE;
__sfr __at 0xea MXAX; 		/* extended address register */
__sfr __at 0xf0 B; 			/* aux accumulator */
__sfr __at 0xf8 EIP; 		/* extended interrupt priority */
  __sbit __at 0xf8 PX2;
  __sbit __at 0xf9 PX3;
  __sbit __at 0xfa PX4;
  __sbit __at 0xfb PX5;
  __sbit __at 0xfc PWDI;
  __sbit __at 0xfd C1IP;
  __sbit __at 0xfe C0IP;
  __sbit __at 0xff CANBIP;

/*  WORD/DWORD Registers  */

__sfr16 __at (0x8C8A) TMR0;  /* TIMER 0 COUNTER   				*/
__sfr16 __at (0x8D8B) TMR1;  /* TIMER 1 COUNTER                 */
__sfr16 __at (0xCDCC) TMR2;  /* TIMER 2 COUNTER                 */
__sfr16 __at (0xCBCA) RCAP2; /* TIMER 2 CAPTURE REGISTER WORD	*/

#endif /* DS80C390_H */
<file_sep>Here, You will find  detailed instruction for installing PVcollib  
To use PVcollib, you will need:  
  * Last version from [Download section](https://github.com/alekmaul/pvcollib/wiki/Download)
  * An editor like Programmer's Notepad or Eclipse (if your PC is strong enough ;-))  

Additional sections below will cover others OS installation like Linux and Mac OS X.  

Good luck!  

## Installing PVcollib

### Step 1: Installing the toolchain

The first thing you need to do to get you started is downloading the latest versions of PVcollib and the tools that come with it. This is the core to all/most homebrew programs on the Colecovision, as it provides the C compiler and linker and various tools.  

Put it wherever you like – it doesn’t affect the compilation (you will only need to define it in your PATH), as long as you don’t extract it in a directory that contains spaces (eg, ‘**C:/colecodev/**’ would be fine).  

#### Msys

You can use msys to have a Unix like environment, but it is not mandatory.  

Download **msys** to use Unix like environment and extract it in your coleco directory. (eg, **C:\colecodev\** would be fine). You will have a subdirectory name **msys** with all msys distribution in it.  

[msys 1.0.17](http://www.portabledev.com/download/11/)

Msys needs to be added to Windows Path because lots of msys binary files are needed when we are going to compile.  

To add the **msys\bin** directory to your PATH environment variable (eg,  you will add  **c:\colecodev\msys\bin** in our example).  
I'm French with a Windows 7 computer, so the name will not reflect your exact configuration. The goal is to have the Windows Path text box to add the msys/bin directory. Do a Right Click on "Ordinateur" icon, choose "Paramètres système avancés" and then, click on "Variables d'environnement" button.  

![Path](http://www.portabledev.com/wp-content/uploads/2018/02/pn_tools_04.jpg)

Choose the Path entry to add **c:\colecodev\msys\bin** at the end of the line.  

![Path2](https://www.portabledev.com/wp-content/uploads/2019/11/pn_tools06.png)

#### Emulators  

Download emulators to test your homebrews and put them in the emulators directory (see unzipped devkitcol, you will have the directory **C:/colecodev/emulators**).  

[bluemsx](http://www.bluemsx.com/)

[bluemsx Fullpack from Emu-France](http://www.emu-france.com/?wpfb_dl=2557)

[EmulTwo](https://github.com/alekmaul/pvcollib/tree/master/emulators/emultwo)

[ColEM](http://fms.komkon.org/ColEm/)

At the end, you must have something like that :  
```
  c:\colecodev
  .........\coleco-examples
  .........\devkitcol
  .................\bin
  .................\include
  .................\lib
  .................\tools
  .................col_rules
  .........\emulators
  .........\include
  .........\lib
  .........\bin
```

### Step 2: Installing for windows

If you're using a Windows environment, you will need to compile again the library.  
Go to your SDK folder and type   
<pre>
C:\colecodev>build_pvcollib.bat
</pre>
When the library is compiled you should obtain the following files
<pre>
C:\colecodev>dir lib
Répertoire de C:\colecodev\lib
collib.lib
crtcol.rel
</pre>

##### Let's start compiling with Programmer's Notepad

We will use the hello world example to test how our PVcollib library is installed. The helloworld directory is shipped with PVcollib examples.  
<file_sep>#include <coleco.h>

static const u8 snd_dummy[] = {
	0xFF
	};

static const u8 snd_lowhealth[] = {
    0x02, 0x02, 0x03, 0x00, 0x00,
    0x02, 0x01, 0x05, 0x00, 0x00,
    0x27,
    0x18,
	};
    
static const u8 snd_shoot[] = {
    0x43, 0x97, 0x20, 0x08, 0x11, 0x2d, 0x18, 0x11,
    0x50
	};

static const u8 snd_block[] = {
    0x83, 0xaa, 0x42, 0x04, 0x11, 0x80, 0x33, 0x12,
    0x90
	};

static const u8 snd_hit[] = {
    0x02, 0x65, 0x03, 0x00, 0x00,
    0x10
	};

static const u8 snd_victory1[] = {
    0x40, 0x00, 0xf0, 0x32,
    0x41, 0x97, 0x50, 0x0a, 0x11, 0xfb,
    0x41, 0x97, 0x50, 0x08, 0x11, 0xfb,
    0x41, 0x97, 0x50, 0x06, 0x11, 0xfb,
    0x41, 0x97, 0x50, 0x04, 0x11, 0xfb,
    0x41, 0x97, 0x50, 0x02, 0x11, 0xfb,
    0x41, 0x97, 0x50, 0x23, 0x21, 0xfc,
    0x42, 0xbe, 0x30, 0x1f, 0x7f, 0x21,
    0x42, 0xbe, 0x40, 0x1f, 0x6f, 0x21,
    0x42, 0xbe, 0x50, 0x10, 0x5f, 0x11,
    0x50
    };
static const u8 snd_victory2[] = {
    0x80, 0x00, 0xf0, 0x32,
    0x81, 0xb4, 0x30, 0x0a, 0x11, 0xfb,
    0x81, 0xb4, 0x30, 0x08, 0x11, 0xfb,
    0x81, 0xb4, 0x30, 0x06, 0x11, 0xfb,
    0x81, 0xb4, 0x30, 0x04, 0x11, 0xfb,
    0x81, 0xb4, 0x30, 0x02, 0x11, 0xfb,
    0x81, 0xb4, 0x30, 0x2d, 0x21, 0xfc,
    0x90
    };
static const u8 snd_victory3[] = {
    0xc0, 0xcb, 0xf0, 0x32,
    0xc1, 0xd6, 0x50, 0x0a, 0x11, 0xfb,
    0xc1, 0xd6, 0x50, 0x08, 0x11, 0xfb,
    0xc1, 0xd6, 0x50, 0x06, 0x11, 0xfb,
    0xc1, 0xd6, 0x50, 0x04, 0x11, 0xfb,
    0xc1, 0xd6, 0x50, 0x02, 0x11, 0xfb,
    0xc1, 0xd6, 0x50, 0x2d, 0x21, 0xfc,
    0xfe, 0xfe, 0xe8,
    0xc0, 0xcb, 0xf0, 0xa5,
    0xd0
    };
static const u8 snd_victory4[] = {
    0x02, 0x07, 0x32, 0x17, 0x5f,
    0x02, 0xf5, 0xbd, 0x00, 0x00,
    0x02, 0x07, 0xa5, 0x1f, 0xaf,
    0x10
    };

static const u8 snd_start1[] = {
    0x42, 0x57, 0x33, 0x08, 0x19, 0x14,
    0x68,
    0x42, 0x81, 0x32, 0x08, 0x49, 0x15,
    0x42, 0x3b, 0x32, 0x08, 0x49, 0x15,
    0x42, 0xe0, 0x31, 0x30, 0x0e, 0xff,
    0x42, 0xe0, 0x71, 0x10, 0x18, 0x14,
    0x50
    };
    
static const u8 snd_start2[] = {
    0x82, 0xd6, 0x30, 0x08, 0x19, 0x14,
    0xa8,
    0x82, 0xa0, 0x30, 0x08, 0x49, 0x15,
    0x82, 0x8f, 0x30, 0x08, 0x49, 0x15,
    0x82, 0x78, 0x30, 0x30, 0x0d, 0xff,
    0x82, 0x78, 0x70, 0x10, 0x18, 0x14,
    0x90
    };
    
static const u8 snd_start3[] = {
    0xc2, 0x8f, 0x30, 0x08, 0x19, 0x14,
    0xe8,
    0xc2, 0x6b, 0x30, 0x08, 0x49, 0x15,
    0xc2, 0x5f, 0x30, 0x08, 0x49, 0x15,
    0xc2, 0x50, 0x30, 0x30, 0x0d, 0xff,
    0xc2, 0x50, 0x70, 0x10, 0x18, 0x14,
    0xd0
    };

const sound_t snd_table[] = {
	{snd_lowhealth,SOUNDAREA1},
	{snd_shoot,SOUNDAREA2},
	{snd_hit,SOUNDAREA3},
	{snd_block,SOUNDAREA4},
	{snd_victory1,SOUNDAREA1},
	{snd_victory2,SOUNDAREA2},
	{snd_victory3,SOUNDAREA3},
	{snd_victory4,SOUNDAREA4},
	{snd_start1,SOUNDAREA1},
	{snd_start2,SOUNDAREA2},
	{snd_start3,SOUNDAREA3}
	};
<file_sep>#ifndef _MEGACART_GFXS3_
#define _MEGACART_GFXS3_

#include <coleco.h>

#include "image3gfx.h"		// generetad by gfx2col

#endif
<file_sep>/*---------------------------------------------------------------------------------


	Pad demo
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "input.h"

//---------------------------------------------------------------------------------
// The NMI routine. Gets called 50 or 60 times per second 
// nothing to update for Input example
void nmi (void) {
}

//---------------------------------------------------------------------------------
void main (void) {
	// Put screen in text mode 2
	vdp_setmode2txt();
	
	// Put default char in VRAM and duplicate to all areas
	//  as we are going to write to line 10, it is in the second area
	vdp_setdefaultchar(FNTNORMAL);
	vdp_duplicatevram();
	vdp_fillvram(0x2000,0xf1,128*8); // Change color (or we will see nothing)
	vdp_enablescr();
	
	// Wait for nothing :P
	while(1) {
		// Update display with current pad 1 values
		if (joypad_1 & PAD_RIGHT) vdp_putstring(9,10,"RIGHT PRESSED"); 
		if (joypad_1 & PAD_LEFT)  vdp_putstring(9,10,"LEFT PRESSED "); 
		if (joypad_1 & PAD_DOWN)  vdp_putstring(9,10,"DOWN PRESSED "); 
		if (joypad_1 & PAD_UP)    vdp_putstring(9,10,"UP PRESSED   "); 
		if (joypad_1 & PAD_FIRE1) vdp_putstring(9,10,"FIRE1 PRESSED"); 
		if (joypad_1 & PAD_FIRE2) vdp_putstring(9,10,"FIRE2 PRESSED"); 
		if (joypad_1 & PAD_FIRE3) vdp_putstring(9,10,"FIRE3 PRESSED"); 
		if (joypad_1 & PAD_FIRE4) vdp_putstring(9,10,"FIRE4 PRESSED"); 

		// Update display with current keyboard pad 1 values
		if (keypad_1 == PAD_KEY0)     vdp_putstring(9,12,"KEY 0 PRESSED"); 
		if (keypad_1 == PAD_KEY1)     vdp_putstring(9,12,"KEY 1 PRESSED"); 
		if (keypad_1 == PAD_KEY2)     vdp_putstring(9,12,"KEY 2 PRESSED"); 
		if (keypad_1 == PAD_KEY3)     vdp_putstring(9,12,"KEY 3 PRESSED"); 
		if (keypad_1 == PAD_KEY4)     vdp_putstring(9,12,"KEY 4 PRESSED"); 
		if (keypad_1 == PAD_KEY5)     vdp_putstring(9,12,"KEY 5 PRESSED"); 
		if (keypad_1 == PAD_KEY6)     vdp_putstring(9,12,"KEY 6 PRESSED"); 
		if (keypad_1 == PAD_KEY7)     vdp_putstring(9,12,"KEY 7 PRESSED"); 
		if (keypad_1 == PAD_KEY8)     vdp_putstring(9,12,"KEY 8 PRESSED"); 
		if (keypad_1 == PAD_KEY9)     vdp_putstring(9,12,"KEY 9 PRESSED"); 
		if (keypad_1 == PAD_KEYSTAR)  vdp_putstring(9,12,"STAR PRESSED "); 
		if (keypad_1 == PAD_KEYSHARP) vdp_putstring(9,12,"SHARP PRESSED"); 

		// Wait Vblank
		vdp_waitvblank(1);
	}
	// startup module will issue a soft reboot if it comes here 
}
<file_sep>#include "compdan2.h"

#include "compdan1.h"

//---------------------------------------------------------------------------
#define DAN2BIT_OFFSET4_MIN 10
#define DAN2BIT_OFFSET4_MAX 16
int DAN2MAX_OFFSET4;
int DAN2BIT_OFFSET4;

// CALCULATE BITS COST -
int dan2count_bits(int offset, int len)
{
	int bits = 1 + elias_gamma_bits(len);
	if (len == 1) return bits + 1 + (offset > MAX_OFFSET1 ? BIT_OFFSET2 : BIT_OFFSET1);
	if (len == 2) return bits + 1 + (offset > MAX_OFFSET2 ? BIT_OFFSET3 : 1 + (offset > MAX_OFFSET1 ? BIT_OFFSET2 : BIT_OFFSET1));
	return bits + 1 + (offset > MAX_OFFSET3 ? DAN2BIT_OFFSET4 : 1 + (offset > MAX_OFFSET2 ? BIT_OFFSET3 : 1 + (offset > MAX_OFFSET1 ? BIT_OFFSET2 : BIT_OFFSET1)));
}

void update_maxoffset4(int bits)
{
	// Update OFFSET4 BIT and MAX values
	DAN2BIT_OFFSET4 = bits;
	DAN2MAX_OFFSET4 = MAX_OFFSET3 + (1<<DAN2BIT_OFFSET4);
}

// - LZSS COMPRESSION -
void dan2lzss(byte *data_src)
{
	int i, j, k;
	int temp_bits;
	struct t_match *match;
	int len, best_len;
	int offset;
	int match_index;
	optimals[0].bits = 8; // FIRST ALWAYS LITERAL 
	optimals[0].offset = 0;
	optimals[0].len = 1;
	for (i = 1;i < index_src;i++)
	{
        // TRY LITERALS 
        optimals[i].bits = optimals[i-1].bits + 1 + 8;
        optimals[i].offset = 0;
        optimals[i].len = 1;
        // LZ MATCH OF ONE : LEN = 1 
        j = MAX_OFFSET2;
        if (j > i) j = i;
			/* temp_bits = optimals[i-1].bits + 1+1+1+2; */
			for (k = 1; k <= j; k++)
			{
				/* if (k==5) temp_bits += 3; */
				if (data_src[i] == data_src[i-k])
				{
					temp_bits = optimals[i-1].bits + dan2count_bits(k, 1);
					if (temp_bits < optimals[i].bits)
					{
						optimals[i].bits = temp_bits;
						optimals[i].len = 1;
						optimals[i].offset = k;
                        break;
					}
				}
			}
			// LZ MATCH OF TWO OR MORE : LEN = 2, 3 , 4 ... 
			match_index = ((int) data_src[i-1]) << 8 | ((int) data_src[i] & 0x000000ff);
			match = &matches[match_index];
			best_len = 1;
			for (/* match = &matches[match_index] */; match->next != NULL && best_len < MAX_LEN; match = match->next)
			{
				offset = i - match->index;
				if (offset > DAN2MAX_OFFSET4)
				{
					flush_match(match);
					break;
				}
				for (len = 2;len <= MAX_LEN;len++)
				{
					if (len > best_len)
					{
						if (!(len == 2 && offset > MAX_OFFSET3))
						{
							best_len = len;
							temp_bits = optimals[i-len].bits + dan2count_bits(offset, len);
							if (optimals[i].bits > temp_bits)
							{
								optimals[i].bits = temp_bits;
								optimals[i].offset = offset;
								optimals[i].len = len;
							}
						}
					}
					if (i < offset + len || data_src[i-len] != data_src[i-len-offset])
					{
                        break;
					}
				}
			}
			insert_match(&matches[match_index], i);
		}
	len = (optimals[index_src-1].bits + 17 + 7) / 8;
	cleanup_optimals();
}

int dan2Compress(byte *src,byte *dst,int n)
{
    size_t count;
	int maxbits = DAN2BIT_OFFSET4_MIN+1;

	// Initialize Matches Array
    index_src=n;
	reset_matches();

	// SET MAX BITS FOR BIG OFFSET VALUES -
	update_maxoffset4(maxbits);

	// Apply compression
	dan2lzss(src);
	free_matches();

    // flush destination
    index_dest=0;
    rle_ntimes = 0;
    bRLEDATA = 0;
    bit_mask = 0;
    write_lz(src, dst);

    // compute ratio
	//index_dest = optimals[n-1].bits += 1 + 16 + 1 + 7;
	//index_dest /= 8;
    count=index_dest;

    return count;
}
<file_sep>VERSION = "1.4.0"

#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
CC=gcc
CFLAGS=-g -O2 -Wall -D__BUILD_DATE="\"`date +'%Y%m%d'`\"" -D__BUILD_VERSION="\"$(VERSION)\""

SOURCES=gfx2col.c lodepng.c lodepic.c comptool.c comprle.c compdan1.c  compdan2.c  compdan3.c
OBJS=gfx2col.o  lodepng.o lodepic.o comptool.o comprle.o compdan1.o  compdan2.o  compdan3.o
EXE=gfx2col
DEFINES =
LIBS =

ifeq ($(OS),Windows_NT)
        EXT=.exe
else
        EXT=
endif

#---------------------------------------------------------------------------------
all: $(EXE)$(EXT)

#---------------------------------------------------------------------------------
$(EXE)$(EXT) : $(OBJS)
	@echo make exe $(notdir $<)
	$(CC) $(CFLAGS) $(OBJS) -o $@

gfx2col.o : gfx2col.c
	@echo make obj $(notdir $<)
	$(CC) $(CFLAGS) -c $<

lodepng.o : lodepng.c
	@echo make obj $(notdir $<)
	$(CC) $(CFLAGS) -c $<

lodepic.o : lodepic.c
	@echo make obj $(notdir $<)
	$(CC) $(CFLAGS) -c $<

comptool.o : comptool.c
	@echo make obj $(notdir $<)
	$(CC) $(CFLAGS) -c $<
	
#---------------------------------------------------------------------------------
clean:
	rm -f $(OBJS) $(EXE)$(EXT) *.tds

install:
	mkdir -p ../../devkitcol/tools && cp $(EXE)$(EXT) ../../devkitcol/tools/$(EXE)$(EXT)
<file_sep>/*---------------------------------------------------------------------------------


	simple pal/ntsc dectection demo
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "palntsc.h"

//---------------------------------------------------------------------------------
// The NMI routine. Gets called 50 or 60 times per second 
// nothing to update for Input example
void nmi (void) {
}

//---------------------------------------------------------------------------------
void main (void) {
	// Put screen in text mode 2
	vdp_setmode2txt();
	
	// Put default char in VRAM and duplicate to all areas
	//  as we are going to write to line 10, it is in the second area
	vdp_setdefaultchar(FNTNORMAL);
	vdp_duplicatevram();
	vdp_fillvram(0x2000,0xf1,128*8); // Change color (or we will see nothing)
	vdp_enablescr();
	
	// Wait for nothing :P
	while(1) {
		// Update display with current value
		if (vid_freq==60)
			vdp_putstring(10,10,"NTSC CONSOLE");
		else if (vid_freq==50)
			vdp_putstring(10,10,"PAL CONSOLE");
		else {
			vdp_putstring(10,10,"UNKNOW");
		}
		
		// Wait Vblank
		vdp_waitvblank(1);
	}
	// startup module will issue a soft reboot if it comes here 
}
<file_sep>Devkitcol 1.11
 
 Programming Compiler and Tools for Colecovision

INTRODUCTION
----------------------
Devkitcol is a set of tools built to compile C sources files and graphics files 
to produce homebrews for Colecovision.
Users are encouraged to download the source code of PVcollib and submit bug fixes
and patches as well as new features for inclusion in the Devkitcol & PVcollib distribution.

SPECIAL THANKS
----------------------
  <NAME> for sdcc - SDCC Release Manager  https://sourceforge.net/projects/sdcc/files/
  <NAME> (aka newcoleco) for cvlib :  <no website>
  matthew180 for F18A support (http://codehackcreate.com/archives/592)
  digress (http://eriscreations.com) for F18A support on Colecovision.    
               
CHANGE LOG
----------------------
VERSION 1.40 (October, 2020)
- Add dan2 & dan3 compression to gfx2col (dan3 currently does not work)

VERSION 1.30 (January, 2020)
- Add lots of feature in gfx2col for f18a

VERSION 1.20 (December, 2019)
- Add graphic mode 1 in gfx2col

VERSION 1.11 (November, 2019)
- Fix bitmap mode issues in gfx2col
- Remove O2 compiler option
- Add cvmkart alias in col_rules

VERSION 1.10 (November, 2019)
- Added doxygen, gfx2col
- Added cvmkcart

VERSION 1.00 (November, 2018)
- Initial release 

If you have questions, please email Alekmaul at <EMAIL>.

EOF<file_sep>#ifndef _RANDOM_MAIN_
#define _RANDOM_MAIN_

#include <coleco.h>


#endif
<file_sep># do not forget that to build pvcollib, you have to install compiler and tools first !

#---------------------------------------------------------------------------------
all:
	cd tools && \
	make && \
	make install && \
	cd ../pvcollib && \
	make && \
	cd ../coleco-examples && \
	make && \
	make install && \
	echo && \
	echo Build finished successfully ! && \
	echo

clean:
	cd tools ; \
	make clean ; \
	cd ../pvcollib ; \
	make clean ; \
	cd ../devkitcol ; \
	rm -f ./tools/* ; \
	cd ../coleco-examples ; \
	make clean ; \
	rm -rf release

# requirements to launch the "release" rule
doxygenInstalled := $(shell command -v doxygen 2> /dev/null)
operatingSystem=
ifeq ($(OS),Windows_NT)
operatingSystem=windows
else
# only for linux platforms, we use the os-release file
ifneq (,$(wildcard /etc/os-release))
include /etc/os-release
# convert to lower case the result
operatingSystem=linux_$(shell echo $(NAME) | tr A-Z a-z)
else
ifeq ($(shell uname -s),Darwin)
operatingSystem=darwin
else
$(error "Unable to detect your operating system, please update the code in global pvcollib Makefile to continue")
endif
endif
endif

#---------------------------------------------------------------------------------	
# to create the release version for github containing binaries and all coleco-examples :
release: all
ifndef doxygenInstalled
	$(error "doxygen is not installed but is mandatory to create the release version.")
endif
ifeq ($(operatingSystem),)
	$(error "Unable to detect your operating system to create the release version.")
endif
	rm -rf release && mkdir -p release/pvcollib && \
	cp -r devkitcol release/pvcollib/devkitcol && \
	mkdir release/pvcollib/pvcollib && cp -r pvcollib/include release/pvcollib/pvcollib/include && \
	cp -r pvcollib/lib release/pvcollib/pvcollib/lib && \
	mkdir release/pvcollib/pvcollib/docs && cp -r pvcollib/docs/html release/pvcollib/pvcollib/docs/html && \
	cp pvcollib/pvcollib_Logo.png release/pvcollib/pvcollib/pvcollib_Logo.png && \
	cp pvcollib/pvcollib_license.txt release/pvcollib/pvcollib/pvcollib_license.txt && \
    cp pvcollib/pvcollib_version.txt release/pvcollib/pvcollib/pvcollib_version.txt && \
	cp -r coleco-examples release/pvcollib/coleco-examples && \
	cd release && zip -r -m pvcollib_32b_$(operatingSystem).zip pvcollib && \
	echo && echo Release created successfully ! && echo

.PHONY: all
<file_sep>#include "compdan1.h"

//---------------------------------------------------------------------------
struct t_match matches[65536];
t_optimal optimals[MAXINFILE];

int index_src,index_dest;
int bit_index;
int rle_ntimes;
int bRLEDATA;
byte bit_mask;

// REMOVE USELESS FOUND OPTIMALS -
void cleanup_optimals(void)
{
	int j;
	int i = index_src - 1;
	int len;
	while (i > 1)
	{
		len = optimals[i].len;
		for (j = i - 1; j > i - len;j--)
		{
			optimals[j].offset = 0;
			optimals[j].len = 0;
		}
		i = i - len;
	}
}

// REMOVE MATCHE(S) FROM MEMORY -
void flush_match(struct t_match *match)
{
	struct t_match *node;
	struct t_match *head = match->next;
	while ((node = head) != NULL)
	{
		head = head->next;
		free(node);
	}
	match->next = NULL;
}

// FREE MATCHE(S) FROM TABLE -
void free_matches(void)
{
	int i;
	for (i = 0;i < 65536;i++)
	{
		flush_match(&matches[i]);
	}
}

// INITIALIZE MATCHES TABLE -
void reset_matches(void)
{
	int i;
	for (i = 0;i < 65536;i++)
	{
		matches[i].next = NULL;
	}
}

// INSERT A MATCHE IN TABLE -
void insert_match(struct t_match *match, int index)
{
	struct t_match *new_match = (struct t_match *) malloc( sizeof(struct t_match) );
	new_match->index = match->index;
	new_match->next = match->next;
	match->index = index;
	match->next = new_match;
}

// ELIAS GAMMA -
int elias_gamma_bits(int value)
{
	int bits = 1;
	while (value > 1)
	{
		bits += 2;
		value >>= 1;
	}
	return bits;
}

// CALCULATE BITS COST -
int count_bits(int offset, int len)
{
	int bits = 1 + elias_gamma_bits(len);
	if (len == 1) return bits + 1 + (offset > MAX_OFFSET1 ? BIT_OFFSET2 : BIT_OFFSET1);
	if (len == 2) return bits + 1 + (offset > MAX_OFFSET2 ? BIT_OFFSET3 : 1 + (offset > MAX_OFFSET1 ? BIT_OFFSET2 : BIT_OFFSET1));
	return bits + 1 + (offset > MAX_OFFSET3 ? BIT_OFFSET4 : 1 + (offset > MAX_OFFSET2 ? BIT_OFFSET3 : 1 + (offset > MAX_OFFSET1 ? BIT_OFFSET2 : BIT_OFFSET1)));
}

// LZSS COMPRESSION -
void dan1lzss(byte *data_src)
{
	int i, j, k;
	int temp_bits;
	struct t_match *match;
	int len, best_len;//, old_best_len;
	int offset;
	int match_index;
	optimals[0].bits = 8; // FIRST ALWAYS LITERAL
	optimals[0].offset = 0;
	optimals[0].len = 1;
	for (i = 1;i < index_src;i++)
	{
		// TRY LITERALS
		optimals[i].bits = optimals[i-1].bits + 1 + 8;
		optimals[i].offset = 0;
		optimals[i].len = 1;

		// LZ MATCH OF ONE
		j = MAX_OFFSET2;
		if (j > i) j = i;
		for (k = 1; k <= j; k++)
		{
			if (data_src[i] == data_src[i-k])
			{
				temp_bits = optimals[i-1].bits + count_bits(k, 1);
				if (temp_bits < optimals[i].bits)
				{
					optimals[i].bits = temp_bits;
					optimals[i].len = 1;
					optimals[i].offset = k;
					break;
				}
			}
		}
		// LZ MATCH OF TWO OR MORE
		match_index = (((int) data_src[i-1]) << 8) | ((int) data_src[i] & 0x000000ff);
		match = &matches[match_index];
		best_len = 1;
		for (/* match = &matches[match_index] */; (match->next != NULL) && (best_len < MAX_LEN); match = match->next)
		{
			offset = i - match->index;
			if (offset > MAX_OFFSET)
			{
				flush_match(match);
				break;
			}
			for (len = 2;len <= MAX_LEN;len++)
			{
				if (len > best_len)
				{
					if (!((len == 2) && (offset > MAX_OFFSET3) ))
					{
						best_len = len;
						temp_bits = optimals[i-len].bits + count_bits(offset, len);
						if (optimals[i].bits > temp_bits)
						{
							optimals[i].bits = temp_bits;
							optimals[i].offset = offset;
							optimals[i].len = len;
						}
					}
				}
				if ((i < offset + len) || (data_src[i-len] != data_src[i-len-offset]) )
				{
					break;
				}
			}
			// SKIP SOME TESTS
			if ( (len > 6) && (len == best_len - 1) && (match->index == match->next->index + 1) )
			{
				j = 1;
				while (match->next != NULL)
				{
					match = match->next;
					if (i - match->index > MAX_OFFSET)
					{
						flush_match(match);
						break;
					}
					j++;
					if (j == len)
					{
						break;
					}
				}
				if (match->next == NULL) break;
			}
		}
		insert_match(&matches[match_index], i);
	}
	len = (optimals[index_src-1].bits + 18 + 7) / 8;
	cleanup_optimals();
}

// WRITE DATA -
void write_byte(byte value, byte *data_dest)
{
	data_dest[index_dest++] = value;
}

void write_bit(int value, byte *data_dest)
{
	if (bit_mask == 0)
	{
		bit_mask  = (unsigned char) 128;
		bit_index = index_dest;
		write_byte((unsigned char) 0,data_dest);
	}
	if (value) data_dest[bit_index] |= bit_mask;
	bit_mask >>= 1 ;
}

void write_bits(int value, int size, byte *data_dest)
{
	int i;
	int mask = 1;
	for (i = 0 ; i < size ; i++)
	{
		mask <<= 1;
	}
	while (mask > 1)
	{
		mask >>= 1;
		write_bit (value & mask,data_dest);
	}
}

void write_literals_length(int length, byte *data_dest)
{
	write_bit(0,data_dest);
	write_bits(0, 16,data_dest);
	write_bit(1,data_dest);
	length -= 27;
	write_byte((unsigned char) length,data_dest);
}

void write_literal(byte c, byte *data_dest)
{
	write_bit(1,data_dest);
	write_byte(c,data_dest);
}

void write_elias_gamma(int value, byte *data_dest)
{
	int i;
	for (i = 2; i <= value; i <<= 1)
	{
		write_bit(0,data_dest);
	}
	while ((i >>= 1) > 0)
	{
		write_bit(value & i,data_dest);
	}
}

void write_offset(int value, int option, byte *data_dest)
{
	value--;
	if (value >= MAX_OFFSET3)
	{
		write_bit(1,data_dest);
		value -= (MAX_OFFSET3);
		write_bits((value >> 8), BIT_OFFSET4 - 8,data_dest);
		write_byte((unsigned char) (value & 0x000000ff),data_dest);
	}
	else if (value >= MAX_OFFSET2)
	{
		if (option > 2) write_bit(0,data_dest);
		write_bit(1,data_dest);
		value -= (MAX_OFFSET2);
		write_byte((unsigned char) (value & 0x000000ff),data_dest);
	}
	else if (value >= MAX_OFFSET1)
	{
		if (option > 2) write_bit(0,data_dest);
		if (option > 1) write_bit(0,data_dest);
		write_bit(1,data_dest);
		value -= MAX_OFFSET1;
		write_bits(value, BIT_OFFSET2,data_dest);
	}
	else
	{
		if (option > 2) write_bit(0,data_dest);
		if (option > 1) write_bit(0,data_dest);
		write_bit(0,data_dest);
		write_bits(value, BIT_OFFSET1,data_dest);
	}
}

void write_doublet(int length, int offset, byte *data_dest)
{
	write_bit(0,data_dest);
	write_elias_gamma(length,data_dest);
	write_offset(offset, length,data_dest);
}

void write_end(byte *data_dest)
{
	write_bit(0,data_dest);
	write_bits(0, 16,data_dest);
	write_bit(0,data_dest);
}

void write_lz(byte *data_src, byte *data_dest)
{
	int i, j;
	int index;

	// FIRST IS LITERAL
	write_byte(data_src[0],data_dest);
	for (i = 1;i < index_src;i++)
	{
		if (optimals[i].len > 0)
		{
			index = i -  optimals[i].len + 1;
			if (optimals[i].offset == 0)
			{
				if (optimals[i].len == 1)
				{
					write_literal(data_src[index],data_dest);
				}
				else
				{
					write_literals_length(optimals[i].len,data_dest);
					for (j = 0;j < optimals[i].len;j++)
					{
						write_byte(data_src[index + j],data_dest);
					}
					rle_ntimes++;
					bRLEDATA = 1;
				}
			}
			else
			{
				write_doublet(optimals[i].len, optimals[i].offset,data_dest);
			}
		}
	}
	write_end(data_dest);
}

int dan1Compress(byte *src,byte *dst,int n)
{
    size_t count;

	// Initialize Matches Array
    index_src=n;
	reset_matches();

	// Apply compression
	dan1lzss(src);
	free_matches();

    // flush destination
    index_dest=0;
    rle_ntimes = 0;
    bRLEDATA = 0;
    bit_mask = 0;
    write_lz(src, dst);

    // compute ratio
	//index_dest = optimals[n-1].bits += 1 + 16 + 1 + 7;
	//index_dest /= 8;
    count=index_dest;

    return count;
}<file_sep>// this file contains sounds
//  converted from asm to C

#include "snds.h"

const u8 sound1[]={
    0x40,0x25,0x62,1,
    0x40,0x74,0x51,1,
    0x40,0x86,0x00,2,
    0x50,
};

const u8 sound2[]={
    0x80,0xdb,0x01,1,
    0x80,0x7b,0x02,1,
    0x80,0xf0,0x21,1,
    0x80,0x2c,0x22,1,
    0x80,0x4c,0x32,1,
    0x80,0x98,0x52,1,
    0x80,0xfe,0x81,1,
    0x80,0x7f,0xa1,1,
    0x90,
};

const u8 sound3[]={
    0xc0,0xcc,0x50,1,
    0xc0,0xdc,0x00,1,
    0xc0,0x3f,0x01,1,
    0xc0,0xac,0x01,1,
    0xc0,0x13,0x02,1,
    0xc0,0x82,0x02,1,
    0xc0,0xde,0x02,1,
    0xc0,0x33,0x03,1,
    0xc0,0x91,0x03,1,
    0xed,
    0xc0,0xbb,0xa0,1,
    0xc0,0xb8,0x90,1,
    0xc0,0x3d,0x91,1,
    0xc0,0xb4,0x91,1,
    0xc0,0x54,0x92,1,
    0xc0,0xbe,0x92,1,
    0xc0,0x44,0xa3,1,
    0xc0,0xb1,0xa3,1 ,
    0xd0,
};

const u8 sound4[]={
    0x02,0x14,64,0x12,0x42,
    0x10,
};

const u8 sound5[]={
    0x40,0x1d,0x51,6,
    0x40,0xd5,0x50,6,
    0x40,0xa9,0x50,6,
    0x40,0xd5,0x50,6,
    0x40,0xa9,0x50,6,
    0x40,0x8e,0x50,6,
    0x40,0xa9,0x50,6,
    0x40,0x8e,0x50,6,
    0x40,0x6a,0x50,24,
    0x50,
};

const u8 sound6[]={
    0x80,0x3a,0x52,6,
    0x80,0xab,0x51,6,
    0x80,0x53,0x51,6,
    0x80,0x1d,0x51,6,
    0x80,0xd5,0x50,6,
    0x80,0xa9,0x50,6,
    0x80,0xd5,0x50,6,
    0x80,0xa9,0x50,6,
    0x80,0x8e,0x50,24,
    0x90,
};

//---------------------------------------------------------------------------------
// mandatory soundtable declaration
// For some reason the very first entry MUST be SOUNDAREA1.  SOUNDAREA1 is the lowest priority sound effect.  
// I recommend using SOUNDAREA1-SOUNDAREA3 to be music track. SOUNDAREA4-6 to be sound effects. 
const sound_t snd_table[]={
	{ sound1,			  				SOUNDAREA1},	// sound entry 1	
	{ sound2,			  				SOUNDAREA2},	// sound entry 2	
	{ sound3,			  				SOUNDAREA3},	// sound entry 3	
	{ sound4,			  				SOUNDAREA4},	// sound entry 4	
	{ sound5,			  				SOUNDAREA5},	// sound entry 5	
	{ sound6,			  				SOUNDAREA6},	// sound entry 6
};
<file_sep>#ifndef _MEGACART_GFXS2_
#define _MEGACART_GFXS2_

#include <coleco.h>

#include "image2gfx.h"		// generetad by gfx2col

#endif
<file_sep>/*---------------------------------------------------------------------------------


	small grame from coder <NAME> : Diamond Dash
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "dash.h"

#include "gfxs.h"											// to add definition of graphics
#include "snds.h"											// to add definition of sounds

const signed char holes1_dx[]={-1,0,1,-2,-1,0,1,2,-2,-1,0,1,0};	// holes type #1
const signed char holes1_dy[]={-2,-2,-2,-1,-1,-1,-1,-1,0,0,0,0,1};

const signed char holes2_dx[]={-2,-1,0,-2,-1,0,1,-2,-1,0,1,0,1};	// holes type #2
const signed char holes2_dy[]={-2,-2,-2,-1,-1,-1,-1,0,0,0,0,1,1};

const char *const holes_dx[]={holes1_dx,holes2_dx};			// holes type table
const char *const holes_dy[]={holes1_dy,holes2_dy};
const char holes_size = 13;									// holes size


const u8 game_over[] = {33,34,35,36,37,38,0};				// Char array for "GAME OVER"


int dynamite; 												// Number of dynamite 
unsigned diamant;											// Score 
unsigned timer;												// Timer

const unsigned int diamant_score[] = {1,3,5};				// Diamonds value
u8 nombre_diamants;											// Number of diamonds needed to finish the level 

const u8 minimum_diamants[]={85,75,60,45,35};

typedef struct {											// Classic coordinate structure
	char x;
	char y;
	signed char dx;
	signed char dy;
} coorxy;

coorxy player; 												// Player : coordinate
coorxy one_dynamite;										// Dynamite : coordinate
u8 dynamite_countdown;										// Dynamite : countdown before explosion

//---------------------------------------------------------------------------------
// Initialise characters graphics in VideoRAM 
void init_graphics(void) {
	// Load characters pattern and color
	vdp_rle2vram(PATTERNRLE,0x0000);
	vdp_duplicatevram();
	vdp_rle2vram(COLORRLE,0x2000);
	
	// Set sprites pattern as characters pattern
	vdp_setreg(6,0);
}

//---------------------------------------------------------------------------------
// Show score, timer and number of dynamites
void show_score(void) {
	vdp_putstring(6,23,sys_str(diamant));
	vdp_putstring(14,23,sys_str(timer));
	vdp_putstring(23,23,sys_str(dynamite));
}

//---------------------------------------------------------------------------------
// Add diamonds function
void add_diamond(u8 nombre, u8 diamond_type) {
	char x,y,k;
	signed char dx,dy;
loop2:
	x = sys_randbyte(1,30);
	y = sys_randbyte(4,21);
	if (vdp_getchar(x,y)!=1) goto loop2;
	
	for (dx=-1;dx<2;dx++) {
		for (dy=-1;dy<2;dy++) {
			k = vdp_getchar(x+dx,y+dy);
			if (k==2) goto loop2;
		}
	}
	vdp_putchar(x,y,2+diamond_type);
	nombre--;
	if (nombre!=0) goto loop2;
}

//---------------------------------------------------------------------------------
// Add holes function
void add_holes(u8 nombre) {
	char x,y,k,type;
	char dx,dy,size;

loop3:
	x = sys_randbyte(3,28);
	y = sys_randbyte(8,21);
	type = sys_random()&1;
	size=holes_size;
	while(size--!=0) {
		dx=(holes_dx[type])[size];
		dy=(holes_dy[type])[size];
		k = vdp_getchar(x+dx,y+dy);
		if (k!=1) goto loop3;
	}
	size=holes_size;
	while(size--!=0) {
		dx=(holes_dx[type])[size];
		dy=(holes_dy[type])[size];
		vdp_putchar(x+dx,y+dy,2);
	}
	nombre--;
	// add dynamite pack in the last two holes
	if (nombre==2) vdp_putchar(x,y,7);
	if (nombre<2) vdp_putchar(x,y,31);
	// loop
	if (nombre!=0) goto loop3;
}

//---------------------------------------------------------------------------------
// Draw a new mountain 
void new_mountain(void) {
	// Blank screen
	vdp_disablevdp();										
	vdp_rle2vram(NAMERLE,0x1800);							// Load default mountain screen
	
	// Initialise player's coordinate and sprite pattern
	player.x = 22;	
	player.y = 2;
	player.dx = 0;
	player.dy = 0;
	spr_setpat(0,64);
	spr_setcol(0,15);
	
	add_holes(6);											// Add 6 holes
	add_diamond(51,1);										// Add 51 green diamonds	
	add_diamond(23,2);										// Add 23 red diamonds
	add_diamond(11,3); 										// Add 11 white diamonds 
	
	// Show screen 
	vdp_enablevdp();
}

//---------------------------------------------------------------------------------
// Show sprite 
void show_sprite(void) {
	// wait 3 vertical retrace to slowdown the execution 
	vdp_enablenmi();
	vdp_waitvblank(3);
	vdp_disablenmi();
	// Put sprites table directly in VideoRAM 
	vdp_putvram(sprgen,sprites,8);
}

//---------------------------------------------------------------------------------
// Update player on screen
void show_player(u8 n) {
	u8 x,y;
	u8 j;
	
	// convert player's x and y position for normal sprite's position
	x = player.x<<3;
	y = (player.y<<3)-1;
	
	// Switch player's sprite pattern
	sprites[0].pattern ^=1;
	
	// If it's during game 
	if (n==0) {
		// Then animate sprites player movement
		for (j=0;j<2;j++) {
			if (sprites[0].x<x) sprites[0].x +=4;
			if (sprites[0].x>x) sprites[0].x -=4;
			if (sprites[0].y<y) sprites[0].y +=4;
			if (sprites[0].y>y) sprites[0].y -=4;
			show_sprite();
		}
	}
	else {
		// Otherwise, simply set sprites table with player's coordinate
		sprites[0].x=x;
		sprites[0].y=y;
		show_sprite();
	}
}

char move_player(void) {
	u8 j,k;
	char x,y;
	
	// Animate player
	show_player(0);
	
	// Put a "cavern" character on player
	vdp_putchar(player.x, player.y,2);
	
	// Get joystick in port#1 
	j = joypad_1;
	
	// Reset player's direction x and y 
	player.dx = 0;
	player.dy = 0;
	
	// Set new player's direction x and y 
	if (j & PAD_UP) player.dy=-1;
	if (j & PAD_DOWN) player.dy=1;
	if (j & PAD_LEFT) player.dx=-1;
	if (j & PAD_RIGHT) player.dx=1;
	
	// If player doesn't move then set 2nd player's sprite pattern, otherwise, set 1st player's sprite pattern 
	if ((player.dx==0) && (player.dy==0)) sprites[0].pattern |= 2; else sprites[0].pattern &= 0xfd; 
	
	// If player press fire 
	if ( (j & PAD_FIRE1) && (dynamite_countdown==0)) {
		// Set new countdown and dynamite coordinate 
		dynamite_countdown=10;
		one_dynamite.x=player.x;
		one_dynamite.y=player.y;
		// Decrease number of player's dynamite 
		dynamite--;
		// If player had no dynamite then return "stop game" flag 
		if (dynamite<0) return 0;
		
		// Play sound#4 : "schhhhhh" 
		snd_startplay(4);
	}
	
	// Check if there is something in front of the player 
	x = player.x + player.dx;
	y = player.y + player.dy;
	k = vdp_getchar(x,y);
	if ((k>1 && k<7)|| k==31) {
		// Update player's coordinate 
		player.x = x; player.y=y;
		// If it's a diamond, increase score and play sound #1 : "beep" 
		if (k>2 && k<6) {
			diamant += diamant_score[k-3]; snd_startplay(1);
			if (--nombre_diamants==0) {
				vdp_putchar(23,2,6); snd_startplay(5); snd_startplay(6);
			} 
		}
		// If it's a dynamite pack, increase number of player's dynamite by 3 and play sound #2 
		if (k==31) {
			dynamite += 3; snd_startplay(2);
		}
		// If it's the exit, return "stop game" flag 
		if (k==6) {
			return 0;
		}
	}
	// Return "continue game" flag 
	return -1;
}

// Do a square hole 
void square_hole(u8 x, u8 y, u8 size) {
	u8 i,j,k;
	char dx=0,dy=0;
	char n = size >> 1;

	// Play sound #2 : "bonk" 
	snd_startplay(2);

	// Add rocks in mountain 
	vdp_enablenmi();
	for (k=0;k<5;k++) {
		while (vdp_getchar(dx,dy)!=2) {  
			dx = sys_randbyte(0,31);
			dy = sys_randbyte(2,22);
		}
		vdp_disablenmi();
		vdp_putchar(dx,dy,1);
		vdp_enablenmi();
	}
	vdp_disablenmi();

	dx = 0;
	// Erase whatever it was directly in the center of this futur hole 
	vdp_putchar(x,y,2);
	// Do square hole 
	x -= n;
	y -= n;
	for (i=0;i<size;i++) {
		for (j=0;j<size;j++) {
			k = vdp_getchar(x,y);
			// If detect a barrel of powder, keep note of its coordinate 
			if (k==7) {dx=x; dy=y;}
			if (k==1) vdp_putchar(x,y,2);
			y++;
		}
		x++;
		y-=size;
	}
	/* If a barrel of powder was detected, do a big square hole */
	if (dx!=0) square_hole(dx, dy, 7);
}

// Update dynamite countdown and effect 
void update_dynamite(void) {
	// If a dynamite is on screen 
	if (dynamite_countdown!=0) {
		// Decrease countdown counter 
		dynamite_countdown--;

		// Update dynamite animation on screen 
		if (dynamite_countdown&1) {
			vdp_putchar(one_dynamite.x,one_dynamite.y,29);
		}
		else {
			vdp_putchar(one_dynamite.x,one_dynamite.y,30);
		}
		// If dynamite countdown = 0, then do a small square hole 
		if (dynamite_countdown==0) {
			square_hole(one_dynamite.x,one_dynamite.y,3);
		}
	}
}

// Game engine 
void game(void) {
	u8 mountains_limit = 5;
	dynamite=0; diamant=0;
	
	while(1) {
		dynamite = 20;
		new_mountain();
		
		// Decrease number of mountain to do 
		mountains_limit--;
		
		// Set number of diamonds needed to exit level 
		nombre_diamants = minimum_diamants[mountains_limit];
		timer=2000;
		show_player(1);

		// Game loop
		while(move_player()) {
			if (timer!=0) timer--;
			show_score();
			update_dynamite();
		}

		// Animate player for the last time 
		show_player(0);

		// "Game Over" when player had no more dynamite 
		if (dynamite<0)	{
			snd_startplay(3); 
			vdp_putstring(13,11,game_over);
			vdp_enablenmi();
			sys_pause();
			vdp_disablenmi();
		}
		else {
			// If there still a timer bonus 
			while (timer>9) {
				// Update timer and score 
				timer-=10;
				diamant++;
				// Play sound#1 : "beep" 
				snd_startplay(1);
				// Update score and timer on screen 
				show_score();
				// Wait a short time to slowdown the execution and to let the "beep" sound playing a bit 
				vdp_enablenmi();
				vdp_waitvblank(2);
				vdp_disablenmi();
			} 

			// If there still a timer bonus 
			while (dynamite--!=0) {
				// Update score
				diamant+=5;
				// Play sound#1 : "bonk" 
				snd_startplay(2);
				// Update score and timer on screen 
				show_score();
				// Wait a short time to slowdown the execution and to let the "beep" sound playing a bit 
				vdp_enablenmi();
				vdp_waitvblank(12);
				vdp_disablenmi();
			}

			// Play winner music 
			snd_startplay(5);
			snd_startplay(6); 

			// Wait until music ends 
			vdp_enablenmi();
			vdp_waitvblank(75);
			vdp_disablenmi(); 

			// Go to next mountain : if it's the last mountain, redo the last one 
			if (mountains_limit==0) mountains_limit++;
		}
	}
}
<file_sep>#ifndef _DIAMOND_SNDS_
#define _DIAMOND_SNDS_

#include <coleco.h>

extern const sound_t snd_table[];

#endif<file_sep>#ifndef __PVCOLLIBVERSION_H__
#define __PVCOLLIBVERSION_H__

#define _PVCOLLIB_MAJOR_	1
#define _PVCOLLIB_MINOR_	6
#define _PVCOLLIB_PATCH_	0

#define _PVCOLLIB_STRING "PVCOLLIB Release 1.6.0"

#endif // __PVCOLLIBVERSION_H__
<file_sep>#ifndef _SIMPLESPR_GFXS_
#define _SIMPLESPR_GFXS_

#include <coleco.h>

#include "pacspritegfx.h"		// generetad by gfx2col

#endif
<file_sep>#include "comprle.h"

//---------------------------------------------------------------------------
int rleCompress(byte *src,byte *dst,int n)
{
	byte *p,*q,*run,*dataend; 
	int count,maxrun;

	dataend = src + n;
	for( run = src,q = dst ; n > 0 ; run = p, n -= count ){
        maxrun = n < 127 ? n : 127;
		if(run <= (dataend-3) && run[1] == run[0] && run[2] == run[0])
        {
			for( p = run+3 ; p < (run+maxrun) && *p == run[0] ; )
				++p;
			count = p-run;
			*q++ = 127+count; /* flag byte */
			*q++ = run[0];
		}
        else
        {
			for( p = run ; p < (run+maxrun) ; )
				if(p <= (dataend-3) && p[1] == p[0] && p[2] == p[0])
					break; // 3 bytes repeated end verbatim run
				else
					++p;
			count = p-run;
			*q++ = count-1; /* flag byte */
			memcpy(q,run,count);
			q += count;
		}
	}

    // end marker
    *q++=0xff;
	return q-dst;
}
<file_sep>#ifndef _MUSICSFX_MAIN_
#define _MUSICSFX_MAIN_

#include <coleco.h>

#endif
<file_sep>ifeq ($(strip $(PVCOLLIB_HOME)),)
$(error "Please create an environment variable PVCOLLIB_HOME with path to its folder and restart application. (you can do it on windows with <setx PVCOLLIB_HOME "/c/colecodev">)")
endif

include ${PVCOLLIB_HOME}/devkitcol/col_rules

#---------------------------------------------------------------------------------
# ROMNAME is used in col_rules file
ROMNAME		:=	megacart

#---------------------------------------------------------------------------------
# each file must be export with correct bank sorting
export OFILES	:= megacart.rel \
	gfxsb1.rel gfxsb2.rel gfxsb3.rel
 
export INCLUDE	:=	$(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
					$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
					-I$(CURDIR)/$(BUILD)

#---------------------------------------------------------------------------------
# BANKs - all defined the same way, we just need to declare them
BANKS = -Wl-b_bank1=0xc000 -Wl-b_bank2=0xc000 -Wl-b_bank3=0xc000 
LDFLAGS += $(BANKS)

#---------------------------------------------------------------------------------
# For  64K Megacart start on $fffc upto SLOT_4 $ffff 
# For 128K Megacart start on $fff8 upto SLOT_7 $ffff
# for 256K one I start on $fff0 upto SLOT_15 at $ffff

.PHONY: bitmaps all
 
#---------------------------------------------------------------------------------
all: bitmaps $(ROMNAME).rom
	@echo Linking Megarom ...
	@cp $(ROMNAME).map crtcol.map 
	$(LDMEGA) -icrtcol.ihx -b6 $(ROMNAME).rom

clean: cleanRom cleanGfx

#---------------------------------------------------------------------------------
image1gfx.inc: image1.png
	@echo convert graphic 1 ... $(notdir $@)
	$(GFXCONV) -cdan1 -fpng -b -m $<

image2gfx.inc: image2.png
	@echo convert graphic 2 ... $(notdir $@)
	$(GFXCONV) -cdan1 -fpng -b -m $<

image3gfx.inc: image3.png
	@echo convert graphic 3 ... $(notdir $@)
	$(GFXCONV) -cdan1 -fpng -b -m $<
	
bitmaps: image1gfx.inc image2gfx.inc image3gfx.inc

#---------------------------------------------------------------------------------
gfxsb1.rel: gfxsb1.c 
	$(CC) $(CFLAGS) -c -mz80 --vc --no-std-crt0 --constseg bank1 gfxsb1.c

gfxsb2.rel: gfxsb2.c 
	$(CC) $(CFLAGS) -c -mz80 --vc --no-std-crt0 --constseg bank2 gfxsb2.c

gfxsb3.rel: gfxsb3.c 
	$(CC) $(CFLAGS) -c -mz80 --vc --no-std-crt0 --constseg bank3 gfxsb3.c

<file_sep>/*---------------------------------------------------------------------------------


	sgm test with no specific feature
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "sgmtest.h"

//---------------------------------------------------------------------------------
// The NMI routine. Gets called 50 or 60 times per second 
// nothing to update for bitmap example
void nmi (void) {
}

//---------------------------------------------------------------------------------
void main (void) {
	// Check if sgm is available
	sys_sgminit();

	// Put screen in text mode 2
	vdp_setmode2txt();
	
	// Put default char in VRAM and duplicate to all areas
	//  as we are going to write to line 8, it is in the second area
	vdp_setdefaultchar(FNTNORMAL);
	vdp_duplicatevram();
	vdp_fillvram(0x2000,0xf1,128*8); 	// Change color (or we will see nothing)
	vdp_enablescr();
	
    // Check now if we were ok with SGM initialization
    if (sys_sgmok==1) {
        // Print text as we are not going to do something else
		vdp_putstring(4,5,"YEAH SGM SUPPORT IS OK !");
    }
    else {
        // Print text as we are not going to do something else
		vdp_putstring(8,5,"NO SGM SUPPORT...");
	}

	// Wait for nothing :P
	while(1) {
		// Wait Vblank
		vdp_waitvblank(1);
	}
	// startup module will issue a soft reboot if it comes here 
}
<file_sep>SUBDIRS := gfx2col cvmkcart bin2txt

all: $(SUBDIRS)

$(SUBDIRS):
	make -C $@

clean:
	for f in $(SUBDIRS); do \
	 cd $$f ; \
	 make clean ; \
	 cd .. ; \
	done

install:
	for f in $(SUBDIRS); do \
	 cd $$f ; \
	 make install ; \
	 cd .. ; \
	done

.PHONY: all $(SUBDIRS)
<file_sep>#ifndef _GRAFPLECMP_MAIN_
#define _GRAFPLECMP_MAIN_

#include <coleco.h>

#endif
<file_sep>/*-------------------------------------------------------------------------
   time.h

   Copyright (C) 2001, <NAME> <johan.knol AT iduna.nl>

   This library is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License 
   along with this library; see the file COPYING. If not, write to the
   Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
   MA 02110-1301, USA.

   As a special exception, if you link this library with other files,
   some of which are compiled with SDCC, to produce an executable,
   this library does not by itself cause the resulting executable to
   be covered by the GNU General Public License. This exception does
   not however invalidate any other reasons why the executable file
   might be covered by the GNU General Public License.
-------------------------------------------------------------------------*/

#ifndef TINIBIOS_H

#define TINIBIOS_H

#include <ds80c390.h>
#include <time.h>

void Serial0Init (unsigned long baud, unsigned char buffered);
char Serial0GetChar(void);
void Serial0PutChar(char);
char Serial0CharArrived(void);
void Serial0Baud(unsigned long baud);
void Serial0SendBreak(void);
void Serial0Flush(void);

void Serial0SwitchToBuffered(void); /* ds400 only. */

void Serial1Init (unsigned long baud, unsigned char buffered);
char Serial1GetChar(void);
void Serial1PutChar(char);
char Serial1CharArrived(void);
void Serial1Baud(unsigned long baud);
void Serial1SendBreak(void);
void Serial1Flush(void);

unsigned long ClockTicks();
void ClockMilliSecondsDelay(unsigned long ms);
void ClockMicroSecondsDelay(unsigned int us);

#define SERIAL_0_BAUD 115200L
#define SERIAL_1_BAUD 9600L

/* these need to be binary numbers */
#define SERIAL_0_RECEIVE_BUFFER_SIZE 1024
#define SERIAL_1_RECEIVE_BUFFER_SIZE 64

/* I know someone is fooling with the crystals */
#if defined(__SDCC_ds400)
# define OSCILLATOR 14745600L
#else
# define OSCILLATOR 18432000L
#endif

/* Set the cpu speed in clocks per machine cycle, valid values are:
   1024: Divide-by-1024 (power management) mode (screws ALL timers and serial)
      4: Standard 8051 divide-by-4 mode
      2: Use 2x xtal multiplier
      1: Use 4x xtal multiplier (Don't do this with a TINI at 18.432MHz)
*/
#define CPU_SPEED 2
void CpuSpeed(unsigned int speed);

/* The MOVX stretch cycles, see datasheet */
#define CPU_MOVX_STRETCH 0x01

/* from rtc390.c */
#define HAVE_RTC
unsigned char RtcRead(struct tm *rtcDate);
void RtcWrite(struct tm *rtcDate);

/* from lcd390.c */
extern void LcdInit(void);
extern void LcdOn(void);
extern void LcdOff(void);
extern void LcdClear(void);
extern void LcdHome(void);
extern void LcdGoto(unsigned int collumnRow);
extern void LcdPutChar(char c);
extern void LcdPutString(char *string);
extern void LcdLPutString(unsigned int collumnRow, char *string);
extern void LcdPrintf(const char *format, ...) __reentrant;
extern void LcdLPrintf(unsigned int collumnRow, const char *format, ...) __reentrant;

/* from i2c390.c */
#define I2C_BUFSIZE 128
extern char I2CReset(void);
extern char I2CStart(void);
extern char I2CStop(void);
extern char I2CSendStop(char addr, char count,
			char send_stop);
extern char I2CReceive(char addr, char count);
extern char I2CSendReceive(char addr, char tx_count,
			   char rx_count);
/*extern char I2CByteOut(char);*/
/*extern void I2CDumpError(char);*/

/* global transfer buffers */
extern char i2cTransmitBuffer[I2C_BUFSIZE];
extern char i2cReceiveBuffer[I2C_BUFSIZE];

/* Macro for normal send transfer ending with a stop condition */
#define I2CSend(addr, count)   I2CSendStop(addr, count, 1)


/* internal functions used by tinibios.c */
unsigned char _sdcc_external_startup(void);
void Serial0IrqHandler (void) __interrupt 4;
void Serial1IrqHandler (void) __interrupt 7;

#if !defined(__SDCC_ds400)
void ClockInit();
void ClockIrqHandler (void) __interrupt 1 __naked;
#endif

#if defined(__SDCC_ds400)
/* functions for dealing with the ds400 ROM firmware. */

/* A wrapper which calls rom_init allocating all available RAM in CE0
   to the heap, sets the serial port to SERIAL_0_BAUD, sets up the
   millisecond timer, and diddles the clock multiplier. */

/* Values for the romInit "speed" parameter. */
#define SPEED_1X	0 /* no clock multiplier, normal speed. */
#define SPEED_2X	1 /* 2x clock multiplier. */
#define SPEED_4X	2 /* 4x clock, DOESN'T WORK ON TINIm400! */

unsigned char romInit(unsigned char noisy,
		      char speed);

/* Install an interrupt handler. */
void installInterrupt(void (*isrPtr)(void), unsigned char offset);
#endif


#endif /* TINIBIOS_H */
<file_sep>/*---------------------------------------------------------------------------------

	Generic phoenix functions

	Copyright (C) 2018-2019
		Alekmaul

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:

	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.
	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.
	3.	This notice may not be removed or altered from any source
		distribution.

---------------------------------------------------------------------------------*/
/**
 * \file phoenix.h
 * \brief contains the basic definitions for controlling the Phoenix console.
 *
 * This unit provides generic features related to Phoenix console.<br>
 *<br>
 * Here is the list of features:<br>
 * - Test phoenix console<br>
*/

#ifndef COL_F18A_INCLUDE
#define COL_F18A_INCLUDE

#include <coleco/coltypes.h>
#include <coleco/f18a.h>

/**
 *  \brief vdp_f18aok is set if f18a module is present<br>
 *	when calling vdp_f18ainit function<br>
 */
#define sys_phoenixok vdp_f18aok;

/**
 * \fn void sys_phoenixinit(void)
 * \brief Test Phoenix console<br>
 * Activate f18a and init vdp_f18aok/sys_phoenixok variable with 1 if it is ok<br>
 * Testing sys_phoenixok variable to know if on Phoenix console<br>
*/
#define sys_phoenixinit vdp_f18ainit;

#endif
<file_sep>#ifndef _F18ABMPM1_MAIN_
#define _F18ABMPM1_MAIN_

#include <coleco.h>

#endif
<file_sep>#ifndef _F18ABMPM1_GFXS_
#define _F18ABMPM1_GFXS_

#include <coleco.h>

#include "ourvisiongfx.h"		// generetad by gfx2col

#endif
<file_sep>VERSION = "1.0.0"

#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
#CC=/d/MinGW32/bin/gcc
CC=gcc
CFLAGS=-g -O2 -Wall -D__BUILD_DATE="\"`date +'%Y%m%d'`\"" -D__BUILD_VERSION="\"$(VERSION)\""

SOURCES=cvmkcart.c
OBJS=cvmkcart.o
EXE=cvmkcart
DEFINES = 
LIBS = 

ifeq ($(OS),Windows_NT)
        EXT=.exe
else
        EXT=
endif

#---------------------------------------------------------------------------------
all: $(EXE)$(EXT)

#---------------------------------------------------------------------------------
$(EXE)$(EXT) : $(OBJS)
	@echo make exe $(notdir $<) 
	$(CC) $(CFLAGS) $(OBJS) -o $@
	
cvmkcart.o : cvmkcart.c
	@echo make obj $(notdir $<) 
	$(CC) $(CFLAGS) -c $<

#---------------------------------------------------------------------------------
clean:
	rm -f $(OBJS) $(EXE)$(EXT) *.tds

install:
	mkdir -p ../../devkitcol/tools && cp $(EXE)$(EXT) ../../devkitcol/tools/$(EXE)$(EXT)

<file_sep>/*---------------------------------------------------------------------------------

	Copyright (C) 2018-2019
		Alekmaul 

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:

	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.
	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.
	3.	This notice may not be removed or altered from any source
		distribution.

	Image converter for colecovision.
	BMP BI_RLE8 compression support by <NAME>
	
***************************************************************************/

#ifndef GFX2COL_H
#define GFX2COL_H

#ifndef __BUILD_VERSION
#include "config.h"
#else
#define GFX2COLVERSION __BUILD_VERSION
#define GFX2COLDATE __BUILD_DATE
#endif /* __BUILD_VERSION */


//MACROS
#define HI_BYTE(n)  (((int)n>>8) & 0x00ff)  // extracts the hi-byte of a word
#define LOW_BYTE(n) ((int)n & 0x00ff)       // extracts the low-byte of a word

#define HIGH(n)     ((int)n<<8)             // turn the char into high part of int

#endif
<file_sep># PVcollib is an open and free library to develop programs for your  Coleco (Connecticut Leather Company) Colecovision

![PVcollib](https://www.portabledev.com/wp-content/uploads/2019/11/pvcollib_logo.png)

PVcollib is split in 3 parts
* The library itself provided with full code sources, obj files of each function and a Doxygen documentation (in the docs folder).
* The tools and compiler (for Windows system only)
* The examples (sprites, sound, graphics, debug)

Download the complete archive in [Download Section](https://github.com/alekmaul/pvcollib/wiki/Download).

After you downloaded the PVcollib archive, check the Wiki Section to get installation instructions and basics tutorials.

Welcome to PVcollib world and enjoy doing some homebrews for your Coleco :-P !


<file_sep>#ifndef COMPDAN1_H
#define COMPDAN1_H

#include <stdio.h>
#include <stdlib.h>
#include <mem.h>

#define bool unsigned char
#define byte unsigned char
#define false 0
#define true 0xff

#define BIT_OFFSET1 1
#define BIT_OFFSET2 4
#define BIT_OFFSET3 8
#define BIT_OFFSET4 12
#define MAX_OFFSET1 (1<<BIT_OFFSET1)
#define MAX_OFFSET2 MAX_OFFSET1 + (1<<BIT_OFFSET2)
#define MAX_OFFSET3 MAX_OFFSET2 + (1<<BIT_OFFSET3)

// - INITIALIZE MATCHES TABLE -
#define MAXINFILE 512*1024

// COMPRESSION CONSTANTS
#define MAX_ELIAS_GAMMA (1<<16)
#define MAX_LEN (1<<16)-1

#define MAX_OFFSET  MAX_OFFSET3 + (1<<BIT_OFFSET4)

//---------------------------------------------------------------------------
typedef struct 
{
	int bits; //COST
	int offset;
	int len;
} t_optimal;

struct t_match
{
	int index;
	struct t_match *next;
};

extern t_optimal optimals[MAXINFILE];
extern struct t_match matches[65536];

extern int index_src,index_dest;
extern int rle_ntimes;
extern int bRLEDATA;
extern byte bit_mask;

//---------------------------------------------------------------------------
extern int elias_gamma_bits(int value);
extern void cleanup_optimals(void);
extern void reset_matches(void);
extern void free_matches(void);
extern void write_lz(byte *data_src, byte *data_dest);
extern void flush_match(struct t_match *match);
extern void insert_match(struct t_match *match, int index);
extern int dan1Compress(byte *src,byte *dst,int n);

#endif<file_sep>/*---------------------------------------------------------------------------------


	Simple sound demo
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "music.h"

//---------------------------------------------------------------------------------
// sound declaration
const u8 musicch1[]={	 					// From Smurf rescue, channel 1
	0x38,  									// rest - length 24
	0x38,  									// rest - length 24
	0xc2,0x47,0x40,0x40,0x18,0x38,			// tone freq 1575,5Hz - vol 11 swept down - length 64
	0xc2,0x55,0x40,0x40,0x18,0x38,			// tone freq 1316,0Hz - vol 11 swept down - length 64
	0xc0,0x50,0x40,0x20,					// tone freq 1398,3Hz - vol 11 - length 32
	0xc0,0x5f,0x40,0x20,					// tone freq 1177,5Hz - vol 11 - length 32
	0xc2,0x55,0x40,0x40,0x18,0x38,			// tone freq 1316,0Hz - vol 11 swept down - length 64
	0xc2,0x5f,0x40,0x40,0x18,0x38,			// tone freq 1177,5Hz - vol 11 swept down - length 64
	0xc2,0x71,0x40,0x40,0x18,0x38,			// tone freq 989,9Hz - vol 11 swept down - length 64
	0xc0,0x6b,0x40,0x20,					// tone freq 1045,4Hz - vol 11 - length 32
	0xc0,0x7f,0x50,0x20,					// tone freq 880,8Hz - vol 10 - length 32
	0xc0,0x5f,0x50,0x10,					// tone freq 1177,5Hz - vol 10 - length 16
	0x18									// repeat
};

const u8 musicch2[]={	 					// From Smurf rescue, channel 2
	0x30,									// rest - length 16
	0x80,0x1d,0x41,0x0e,					// tone freq 392,5Hz - vol 11 - length 14
	0x22,									// rest - length 2
	0x80,0x1d,0x41,0x0e,					// tone freq 392,5Hz - vol 11 - length 14
	0x22,									// rest - length 2
	0x82,0xd6,0x40,0x18,0x15,0x38,			// tone freq 522,7Hz - vol 11 swept down - length 24
	0x80,0xd6,0x40,0x06,					// tone freq 522,7Hz - vol 11 - length 6
	0x22,									// rest - length 2
	0x80,0xd6,0x40,0x0e,					// tone freq 522,7Hz - vol 11 - length 14
	0x22,									// rest - length 2
	0x80,0xbe,0x40,0x0e,					// tone freq 588,7Hz - vol 11 - length 14
	0x22,									// rest - length 2
	0x80,0xaa,0x40,0x10,					// tone freq 658,0Hz - vol 11 - length 16
	0x80,0xd6,0x40,0x10,					// tone freq 522,7Hz - vol 11 - length 16
	0x80,0xaa,0x40,0x10,					// tone freq 658,0Hz - vol 11 - length 16
	0x80,0xa0,0x40,0x10,					// tone freq 699,1Hz - vol 11 - length 16
	0x82,0x8f,0x40,0x18,0x15,0x38,			// tone freq 782,2Hz - vol 11 swept down - length 24
	0x80,0x8f,0x40,0x06,					// tone freq 782,2Hz - vol 11 - length 6
	0x22,									// rest - length 2
	0x80,0x8f,0x40,0x0e,					// tone freq 782,2Hz - vol 11 - length 14
	0x22,									// rest - length 2
	0x80,0xa0,0x40,0x10,					// tone freq 699,1Hz - vol 11 - length 16
	0x80,0xaa,0x40,0x20,					// tone freq 658,0Hz - vol 11 - length 32
	0x80,0xbe,0x40,0x10,					// tone freq 588,7Hz - vol 11 - length 16
	0x80,0xd6,0x40,0x10,					// tone freq 522,7Hz - vol 11 - length 16
	0x82,0xbe,0x40,0x18,0x15,0x38,			// tone freq 588,7Hz - vol 11 swept down - length 24
	0x80,0xbe,0x40,0x06,					// tone freq 588,7Hz - vol 11 - length 6
	0x22,									// rest - length 2
	0x80,0xbe,0x40,0x0e,					// tone freq 588,7Hz - vol 11 - length 14
	0x22,									// rest - length 2
	0x80,0xd6,0x40,0x10,					// tone freq 522,7Hz - vol 11 - length 16
	0x80,0xbe,0x40,0x10,					// tone freq 588,7Hz - vol 11 - length 16
	0x80,0xaa,0x40,0x10,					// tone freq 658,0Hz - vol 11 - length 16
	0x80,0xbe,0x40,0x10,					// tone freq 588,7Hz - vol 11 - length 16
	0x80,0xd6,0x40,0x10,					// tone freq 522,7Hz - vol 11 - length 16
	0x82,0xbe,0x40,0x18,0x15,0x38,			// tone freq 588,7Hz - vol 11 swept down - length 24
	0x80,0xbe,0x40,0x06,					// tone freq 588,7Hz - vol 11 - length 6
	0x22,									// rest - length 2
	0x80,0xbe,0x40,0x0e,					// tone freq 588,7Hz - vol 11 - length 14
	0x22,									// rest - length 2
	0x80,0xe2,0x50,0x10,					// tone freq 495,0Hz - vol 10 - length 16
	0x80,0x1d,0x51,0x10,					// tone freq 392,5Hz - vol 10 - length 16
	0x18,									// repeat
};

const u8 musicch3[]={ 						// From Smurf rescue, channel 3
	0x40,0x55,0x30,0x10,					// tone freq 1316,0Hz - vol 12 - length 16
	0x40,0x50,0x20,0x10,					// tone freq 1398,3Hz - vol 13 - length 16
	0x40,0x40,0x30,0x10,					// tone freq 1747,8Hz - vol 12 - length 16
	0x40,0x47,0x20,0x10,					// tone freq 1575,5Hz - vol 13 - length 16
	0x40,0x50,0x20,0x08,					// tone freq 1398,3Hz - vol 13 - length 8
	0x40,0x55,0x30,0x08,					// tone freq 1316,0Hz - vol 12 - length 8
	0x40,0x5f,0x30,0x10,					// tone freq 1177,5Hz - vol 12 - length 16
	0x40,0x8f,0x30,0x10,					// tone freq 782,2Hz - vol 12 - length 16
	0x40,0x6b,0x20,0x10,					// tone freq 1045,4Hz - vol 13 - length 16
	0x40,0x5f,0x30,0x10,					// tone freq 1177,5Hz - vol 12 - length 16
	0x40,0x55,0x20,0x10,					// tone freq 1316,0Hz - vol 13 - length 16
	0x40,0x50,0x30,0x08,					// tone freq 1398,3Hz - vol 12 - length 8
	0x40,0x55,0x30,0x08,					// tone freq 1316,0Hz - vol 12 - length 8
	0x40,0x5f,0x20,0x10,					// tone freq 1177,5Hz - vol 13 - length 16
	0x40,0x55,0x30,0x10,					// tone freq 1316,0Hz - vol 12 - length 16
	0x40,0x50,0x20,0x10,					// tone freq 1398,3Hz - vol 13 - length 16
	0x40,0x47,0x30,0x08,					// tone freq 1575,5Hz - vol 12 - length 8
	0x40,0x50,0x30,0x08,					// tone freq 1398,3Hz - vol 12 - length 8
	0x40,0x55,0x20,0x10,					// tone freq 1316,0Hz - vol 13 - length 16
	0x40,0x47,0x20,0x08,					// tone freq 1575,5Hz - vol 13 - length 8
	0x68,									// rest - length 8
	0x40,0x47,0x20,0x08,					// tone freq 1575,5Hz - vol 13 - length 8
	0x68,									// rest - length 8
	0x40,0x47,0x20,0x08,					// tone freq 1575,5Hz - vol 13 - length 8
	0x68,									// rest - length 8
	0x40,0x47,0x20,0x20,					// tone freq 1575,5Hz - vol 13 - length 32
	0x40,0x50,0x20,0x08,					// tone freq 1398,3Hz - vol 13 - length 8
	0x40,0x55,0x20,0x08,					// tone freq 1316,0Hz - vol 13 - length 8
	0x40,0x5f,0x20,0x08,					// tone freq 1177,5Hz - vol 13 - length 8
	0x40,0x6b,0x40,0x08,					// tone freq 1045,4Hz - vol 11 - length 8
	0x40,0x71,0x30,0x10,					// tone freq 989,9Hz - vol 12 - length 16
	0x40,0x6b,0x40,0x10,					// tone freq 1045,4Hz - vol 11 - length 16
	0x40,0x5f,0x40,0x10,					// tone freq 1177,5Hz - vol 11 - length 16
	0x40,0x55,0x40,0x08,					// tone freq 1316,0Hz - vol 11 - length 8
	0x40,0x5f,0x40,0x08,					// tone freq 1177,5Hz - vol 11 - length 8
	0x40,0x6b,0x30,0x10,					// tone freq 1045,4Hz - vol 12 - length 16
	0x40,0x5f,0x40,0x10,					// tone freq 1177,5Hz - vol 11 - length 16
	0x40,0x55,0x40,0x10,					// tone freq 1316,0Hz - vol 11 - length 16
	0x40,0x50,0x40,0x08,					// tone freq 1398,3Hz - vol 11 - length 8
	0x40,0x55,0x40,0x08,					// tone freq 1316,0Hz - vol 11 - length 8
	0x40,0x5f,0x30,0x10,					// tone freq 1177,5Hz - vol 12 - length 16
	0x40,0x50,0x40,0x08,					// tone freq 1398,3Hz - vol 11 - length 8
	0x28,									// rest - length 8
	0x40,0x50,0x40,0x08,					// tone freq 1398,3Hz - vol 11 - length 8
	0x28,									// rest - length 8
	0x40,0x50,0x40,0x08,					// tone freq 1398,3Hz - vol 11 - length 8
	0x28,									// rest - length 8
	0x42,0x50,0x30,0x20,0x18,0x44,			// tone freq 1398,3Hz - vol 12 swept down - length 32
	0x10,									// end
};

//---------------------------------------------------------------------------------
// mandatory soundtable declaration
// For some reason the very first entry MUST be SOUNDAREA1.  SOUNDAREA1 is the lowest priority sound effect.  
// I recommend using SOUNDAREA1-SOUNDAREA3 to be music track. SOUNDAREA4-6 to be sound effects. 
const sound_t snd_table[]={
	{ musicch1,			  				SOUNDAREA1},	// sound entry 1	
	{ musicch2,			  				SOUNDAREA2},	// sound entry 1	
	{ musicch3,			  				SOUNDAREA3},	// sound entry 1	

};

//---------------------------------------------------------------------------------
// The NMI routine. Gets called 50 or 60 times per second 
// nothing to update for Input example
void nmi (void) {
}

//---------------------------------------------------------------------------------
void main (void) {
	// Put sound table and mute all channel
	snd_settable(snd_table);
	snd_stopall();

	// Put screen in text mode 2
	vdp_setmode2txt();
	
	// Put default char in VRAM and duplicate to all areas
	//  as we are going to write to line 10, it is in the second area
	vdp_setdefaultchar(FNTNORMAL);
	vdp_duplicatevram();
	vdp_fillvram(0x2000,0xf1,128*8); // Change color (or we will see nothing)
	vdp_putstring(7,6,"PUT RIGHT FOR MUSIC");
    
    // Display screen and enable audio
    vdp_enablescr();
    vdp_enablenmi();
    
	// Wait for nothing :P
	while(1) {
		// Update display with current pad 1 values
		if (joypad_1 & PAD_RIGHT) { vdp_putstring(11,10,"MUSIC"); snd_startplay(1); snd_startplay(2); snd_startplay(3); }

		while (joypad_1) vdp_waitvblank(1); // Wait Vblank while joy pressed 
		
		vdp_waitvblank(1); // default wait vblank
	}
	// startup module will issue a soft reboot if it comes here 
}
<file_sep>/*---------------------------------------------------------------------------------


	bitmap demo with less than 256 tiles
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "grafnocomp.h"

#include "gfxs.h"									// to add definition of graphics

//---------------------------------------------------------------------------------
// The NMI routine. Gets called 50 or 60 times per second 
// nothing to update for bitmap example
void nmi (void) {
}

//---------------------------------------------------------------------------------
void main (void) {
	// Put screen in text mode 2
	vdp_disablescr();
	
	vdp_setmode2txt();
	
	// Put image in vram  and duplicate to the 2nd & 3rd zone
	vdp_putvram (chrgen,TILourvisiongfx,SZTILourvisiongfx); // characters
	vdp_putvram (coltab,COLourvisiongfx,SZCOLourvisiongfx); // colors
	vdp_putvram (chrtab,MAPourvisiongfx,SZMAPourvisiongfx); // map

	vdp_duplicatevram();
	vdp_enablescr();
	
	// Wait for nothing :P
	while(1) {
		// Wait Vblank
		vdp_waitvblank(1);
	}
	// startup module will issue a soft reboot if it comes here 
}
<file_sep>#include "comptool.h"

//---------------------------------------------------------------------------
unsigned char *d;

// Maximum offset for each mode
unsigned int maxlen[7] = {
  128,
  128 + 128,
  512 + 128,
  1024 + 128,
  2048 + 128,
  4096 + 128,
  8192 + 128
};

// Cost of coding a constant
unsigned int varcost[65536];

// Metadata per byte
struct metadata {
  unsigned int reeks;           /* Total times that byte is repeated */
  unsigned int cpos[7];
  unsigned int clen[7];
} *m;

// Compression per byte for each mode
struct pakdata {
  unsigned int cost;
  unsigned int mode;
  unsigned int mlen;
} *p[7];

int savelength;
unsigned int source_size;
unsigned int offset;

struct saves {
  unsigned char *buf;
  int ep, dp, p, e;
} s;

// Inits output buffer
void init(void)
{
  s.ep = s.dp = s.p = s.e = 0;
  s.buf = malloc(source_size * 2);
}

// Adds a zero bit to output
void add0(void)
{
  if (s.p == 0)
    claimevent();
  s.e *= 2;
  ++s.p;
  if (s.p == 8)
    addevent();
}


// Adds an one bit to output
void add1(void)
{
  if (s.p == 0)
    claimevent();
  s.e *= 2;
  ++s.p;
  ++s.e;
  if (s.p == 8)
    addevent();
}

// Add a X bit to output
void addbit(int b)
{
  if (b)
    add1();
  else
    add0();
}

/*
** Add three bits to output
*/
void add3(int b)
{
  addbit(b & 4);
  addbit(b & 2);
  addbit(b & 1);
}

/*
** Add a variable number to output
*/
void addvar(int i)
{
  int j = 0x8000;

  /*
  ** Looks for the first bit set at one
  */
  while ((i & j) == 0)
    j >>= 1;
    
  /*
  ** Like in floating point, the uncompressed adds an extra one
  */
  while (j != 1) {
    j >>= 1;
    add1();
    if ((i & j) != 0)
      add1();
    else
      add0();
  }
  add0();  /* Ending signal */
}

// Add a data to output
void adddata(unsigned char d)
{
  s.buf[s.dp++] = d;
}

// Dump bits buffer
void addevent(void)
{
  s.buf[s.ep] = s.e;
  s.e = s.p = 0;
}

// Take note where it will save the following 8 bits
void claimevent(void)
{
  s.ep = s.dp;
  ++s.dp;
}

/*
** Take note of cost of using a variable number
*/
void initvarcost(void)
{
  int v = 1;
  int b = 1;
  int r = 1;
  int j;

  /*
  ** Depict a one costs one bit  (0)
  ** 2-3 costs three bits            (1x0)
  ** 4-7 costs five bits.          (1x1x0)
  */
  while (r != 65536) {
    for (j = 0; j != r; ++j)
      varcost[v++] = b;
    b += 2;
    r *= 2;
  }
}

/*
** Pre-compresses the source file
*/
void createmetadata(void)
{
  unsigned int i;
  unsigned int j;
  unsigned int *last = malloc(65536 * sizeof(unsigned int));
  unsigned int *prev = malloc((source_size + 1) * sizeof(unsigned int));
  unsigned int r;
  unsigned int t;
  int bl;

  /*
  ** For speeding up the search for pairing strings:
  **
  ** as it advances, prev[byte] points to the string immediately previous
  ** that starts with the same two current bytes, it doesn't matter to link
  ** by individual bytes as each offset needs at least one byte.
  **
  ** last is a kind of hash table pointing to each two-byte string found.
  */
  memset(last, -1, 65536 * sizeof(unsigned int));
  for (i = 0; i != source_size; ++i) {
    m[i].cpos[0] = m[i].clen[0] = 0;
    prev[i] = last[d[i] + d[i + 1] * 256];
    last[d[i] + d[i + 1] * 256] = i;
  }

  /*
  ** Counts the bytes repeated from each starting position
  */
  r = -1;
  t = 0;
  for (i = source_size - 1; i != -1; --i) {
    if (d[i] == r)
      m[i].reeks = ++t;
    else {
      r = d[i];
      m[i].reeks = t = 1;
    }
  }

  /*
  ** Now for each possible mode
  */
  for (bl = 0; bl != 7; ++bl) {

    /*
    ** Process the input file
    */
    for (i = 0; i < source_size; ++i) {
      unsigned int l;
      unsigned int p;

      p = i;
      if (bl) {
        m[i].clen[bl] = m[i].clen[bl - 1];
        m[i].cpos[bl] = m[i].cpos[bl - 1];
        p = i - m[i].cpos[bl];
      }
      
      /*
      ** For each repeated string
      */
      while ((p = prev[p]) != -1) {
        if (i - p > maxlen[bl])  /* Exceeded possible offset? */
          break;                 /* Yes, finish */
        l = 0;
        while (d[p + l] == d[i + l] && (i + l) < source_size) {

          /*
          ** Speed up trick:
          **   If the string that is going to replace has repeated bytes...
          **   and the replacing string has less repeated bytes...
          **   then it can take only existing ones and avoids the
          **   classic problem o(n2)
          */
          if (m[i + l].reeks > 1) {
            if ((j = m[i + l].reeks) > m[p + l].reeks)
              j = m[p + l].reeks;
            l += j;
          } else
            ++l;
        }
        if (l > m[i].clen[bl]) {  /* Look for the longest string */
          m[i].clen[bl] = l;      /* Longitude */
          m[i].cpos[bl] = i - p;  /* Position (offset) */
        }
      }
    }
    putchar('.');
  }
  putchar(' ');
  free(prev);
  free(last);
}

// Get the final size of file with a mode
int getlen(struct pakdata *p, unsigned int mode)
{
  unsigned int i;
  unsigned int j;
  unsigned int cc;
  unsigned int ccc;
  unsigned int kc;
  unsigned int kmode;
  unsigned int kl;

  p[source_size].cost = 0;
  
  /*
  ** Trick: goes from onwards to backwards, this way can know all
  ** possible combinations for compressing.
  */
  for (i = source_size - 1; i != -1; --i) {
    kmode = 0;  /* Literal */
    kl = 0;
    kc = 9 + p[i + 1].cost;
    
    /* Test every size until getting the most short */
    j = m[i].clen[0];
    while (j > 1) {
      cc = 9 + varcost[j - 1] + p[i + j].cost;
      if (cc < kc) {
        kc = cc;
        kmode = 1;  /* Short offset */
        kl = j;
      }
      --j;
    }
    
    /* Test all sizes until getting the most short */
    j = m[i].clen[mode];
    if (mode == 1)
      ccc = 9;
    else
      ccc = 9 + mode;
    while (j > 1) {
      cc = ccc + varcost[j - 1] + p[i + j].cost;
      if (cc < kc) {
        kc = cc;
        kmode = 2;  /* Long offset */
        kl = j;
      }
      --j;
    }
    p[i].cost = kc;
    p[i].mode = kmode;
    p[i].mlen = kl;
  }
  return p[0].cost;
}

// Save the compressed file
int  save(struct pakdata *p, unsigned int mode,byte *dstcomp)
{
  unsigned int i;
  unsigned int j;

  init();
  if (savelength) {
    adddata(source_size & 255);
    adddata(source_size >> 8);
  }
  add3(mode - 1);
  adddata(d[0]);
  i = 1;
  while (i < source_size) {
    switch (p[i].mode) {
      case 0:  /* Literal */
        add0();
        adddata(d[i]);
        ++i;
        break;
      case 1:  /* Short offset */
        add1();
        addvar(p[i].mlen - 1);
        j = m[i].cpos[0] - 1;
        //if (j > 127)
        //  printf("-j>128-");
        adddata(j);
        i += p[i].mlen;
        break;
      case 2:  /* Long offset */
        add1();
        addvar(p[i].mlen - 1);
        j = m[i].cpos[mode] - 1;
        //if (j < 128)
        //  printf("-j<128-");
        adddata(128 | (j & 127));
        j -= 128;
        switch (mode) {
          case 6:
            addbit(j & 4096);
          case 5:
            addbit(j & 2048);
          case 4:
            addbit(j & 1024);
          case 3:
            addbit(j & 512);
          case 2:
            addbit(j & 256);
            addbit(j & 128);
          case 1:
            break;
          default:
            //printf("-2-");
            break;
        }
        i += p[i].mlen;
        break;
      default:
        //printf("-?-");
        break;
    }
  }
  for (i = 0; i != 34; ++i)
    add1();
  //done();

	if (s.p != 0) {
		while (s.p != 8) {
			s.e *= 2;
			s.p++;
		}
		addevent();
	}
	fflush(stdout);
	memcpy(dstcomp,s.buf,s.dp);
	
    return s.dp;
}

int pleCompress(byte *src,byte *dst,int n)
{
	int i,count;
	int l;
	int minlen;
	int minbl;

	offset = 0;
	source_size = n;

	d = malloc(source_size + 1);
	m = malloc(sizeof(struct metadata) * (source_size + 1));
	memcpy(d,src,source_size);
	d[source_size] = 0;

	initvarcost();
	createmetadata();
	
	minlen = source_size * 1000;
	minbl = 0;
	for (i = 1; i != 7; ++i) {
		p[i] = malloc(sizeof(struct pakdata) * (source_size + 1));
		l = getlen(p[i], i);
		if (l < minlen && i) {
			minlen = l;
			minbl = i;
		}
		putchar('.');
	}

	count=save(p[minbl], minbl,dst);
	for (i = 1; i != 7; ++i)
		free(p[i]);
	free(m);
	free(d);

    return count;
}<file_sep>#ifndef _GRAFNOCMP_GFXS_
#define _GRAFNOCMP_GFXS_

#include <coleco.h>

#include "ourvisiongfx.h"		// generetad by gfx2col

#endif
<file_sep>/*---------------------------------------------------------------------------------

	Generic console functions.

	Copyright (C) 2018-2020
		Alekmaul

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:

	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.
	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.
	3.	This notice may not be removed or altered from any source
		distribution.


---------------------------------------------------------------------------------*/
/**
 * \file console.h
 * \brief coleco generic console support.
 *
 * This unit provides generic features related to the console.<br>
 *<br>
 * Here is the list of features:<br>
 * - variable with 32 bytes long in RAM<br>
 * - video frequency<br>
 * - string management<br>
*/

#ifndef COL_CONSOLE_H
#define COL_CONSOLE_H

#include <coleco/coltypes.h>

/**
 * \brief
 * buffer32 used for some functions.<br>
 * can be used by program too.
 */
extern u8 buffer32[32];

/**
 * \brief
 * vid_freq is set with video frequency (50 or 60) hz.
 */
extern volatile u8 vid_freq;

/**
 * \fn u16 sys_random(void)
 * \brief Generate and return a randomized 16 bit number 
 *
 * \return unsigned short of a randomized number
*/
u16 sys_random(void);

/**
 * \fn u8 sys_randbyte(u8 A, u8 B)
 * \brief Generate and return a randomized a 8 bit number between two numbers named A and B
 *
 * \param A minimum value of random number
 * \param B maximum value of random number
 * \return unsigned char of a randomized number
*/
u8 sys_randbyte(u8 A, u8 B);


/**
 * \fn void sys_pause(void)
 * \brief Wait until a fire button is pressed (do a pause)
*/
void sys_pause(void);

/**
 * \fn void sys_pause_delay(unsigned cycles)
 * \brief Wait until delay is over or a fire button is pressed
 * 
 * \param cycles number of cycles to wait
*/
void sys_pause_delay(unsigned cycles);

/**
 * \fn u16 sys_strlen(char *text)
 * \brief return the length of a string
 * 
 * \param text text to analyze
 * \return unsigned short of string length
*/
u16 sys_strlen(char *text);

/**
 * \fn void sys_utoa(unsigned value,char *buffer)
 * \brief Convert an unsigned value to ascii text. Leading zeros are put in buffer
 *
 * \param value value to convert to text
 * \param buffer text that will receive vvalue converted
*/
void sys_utoa(unsigned value,char *buffer);

/**
 * \fn char *sys_str(unsigned value)
 * \brief return a converted value in string
 *
 * \param value number to convert
 * \return pointer to converted string
*/
char *sys_str(unsigned value);

/**
 * \fn void sys_memcpyb (void *dest,void *src,unsigned num)
 * \brief Copy memory backward
 *
 * \param dest destination memory
 * \param src source memory
 * \param num number of bytes to copy
*/
void sys_memcpyb (void *dest,void *src,unsigned num);

/**
 * \fn void sys_memcpyf (void *dest,void *src,unsigned num)
 * \brief Copy memory forward
 *
 * \param dest destination memory
 * \param src source memory
 * \param num number of bytes to copy
*/
void sys_memcpyf(void *dest,void *src,unsigned num);

/**
 * \fn sys_choice_keypad1(u8 minval, u8 maxval)
 * \brief Wait until a key between two values if pressed on keypad 1
 *
 * \param minval  minimum value of key pressed
 * \param maxval  maximum value of key pressed
 * \return value of key pressed
*/
u8 sys_choice_keypad1(u8 minval, u8 maxval);

/**
 * \fn sys_choice_keypad2(u8 minval, u8 maxval)
 * \brief Wait until a key between two values if pressed on keypad 2
 *
 * \param minval  minimum value of key pressed
 * \param maxval  maximum value of key pressed
 * \return value of key pressed
*/
u8 sys_choice_keypad2(u8 minval, u8 maxval);

#endif
<file_sep>#include <coleco.h>

static const u8 level2[] = {
       1,0xff,  50,   0,  20,0xff,   4,0xa8,0xe0,  45,
    0xe1,0xb9,  47,0xff,   2,0xff,  30,0xb4
    };
static const u8 level1[] = {
       1,0xff,   2,0xff,   2,0xff,   2,0xff,   2,0xff,
       2,0xff,  32,0x8c,0xcc,  55,0x82,  83,0xff,0x82,
      17,0xff,  64,0xff,0xce,  56,   0,   2,0xdc
    };

static const u8 level5[] = {
      87,0xff,   7,0xff,   8,0xff,  53,0x85,  10,0x85,
      10,0x85,  58,0x00,  25,0xc2};
static const u8 level7[] = {
	  38,0xff,   2,0xff,   9,0xa1,  31,0xff,  32,0xa1,
    0xe2,0xa1,   4,0xff,   7,0xc2,  42,0x82,  37,0xa2,
	  36,0xff,   9,0xff,   7,0xff,  42,0xff,   9,0x81,
	   2,0xc2,  29,0xff,   9,0xff,   2,0xe1,  20,0x00,
	  11,0xff,   2,0xa2,   6,0xa2,  19,0xff,  16,0x82,
	  18,0xff,  13,0xe2,  28,0xff,   6,0xa2,   7,0xff,
	0xc2,   6,0xff,  10,0xe3,   8,0xe2,  27,0xc1,   1};
static const u8 level6[] = {
      56,0xff,   2,0xff,  15,0xff,   2,0xff,  11,0xff,
       3,0xff,  11,0xc0,   2,0xc0,  15,0xc0,   2,0xc0,
       3,0xff,   2,0xff,  11,0xff,   2,0xff,  14,0xc3,
      11,   0,  26,0xa8,   9,0xa8,  55,0xff,   2,0xff,
       2,0xff,   9,0xff,   2,0xff,   2,0xff,  10,0xa1,
    0xe1,0xa1,  38,0xa9,   7,0xa9};
static const u8 level8[] = {    
      40,0xff,0xff,  45,0xff,   2,0xff,   2,0x81,   2,
    0xff,   2,0xff,  68,0x82,   5,0x82,  36,0x82,  19,
    0x82,  61,0x82,  11,0x82,   6,0xff,  21,0xff,  12,
    0xff,   3,0xff,  14,0x84,   9,0x84,  16,0x81,  13,
    0xff,  23,0xff,  10,0xff,   5,0xff,   9,0x83,  19,
    0x83,  11,0x83,  67,   0,  26,0x8b,   3,0x8b};

const u8* const levels[]={
    level1,level2,
    level7,level8,
    level5,level6,
    level7,level8};
<file_sep>/*---------------------------------------------------------------------------------

	Generic sprites functions.

	Copyright (C) 2018-2019
		Alekmaul

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:

	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.
	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.
	3.	This notice may not be removed or altered from any source
		distribution.


---------------------------------------------------------------------------------*/
/**
 * \file sprite.h
 * \brief coleco generic sprites support.
 *
 * This unit provides methods to display / remove sprites on screen.<br>
*/

#ifndef COL_SPRITE_H
#define COL_SPRITE_H

#include <coleco/coltypes.h>

#define SPHIDE		0xCF
#define SPHIDE1		0xCE

#define MAXSPRITE	32
#define MAXSPRITE4	(MAXSPRITE*4)
#define MAXSPRITE2	(MAXSPRITE*2)

/**
 *  \brief
 *      sprite entry :
 *			y,x     : coordinates (y,x) with y 0..191 and x 0..255
 *          pattern : pattern number of sprite
 *          colour  : colour between 0..15
 */
typedef struct
{
	u8 y;
	u8 x;
	u8 pattern;
	u8 colour;
} sprite_t;

/**
 *  \brief
 *      32 sprites entries
 */
extern volatile sprite_t sprites[MAXSPRITE];	// sprites entries

/**
 *  \brief
 *      0 or 1 if sprites can be displayed or not
 */
extern volatile u8 spr_enable;

/**
 * \fn void spr_clear(void)
 * \brief Remove all sprite from screen and init their positions
*/
void spr_clear(void);

/**
 * \fn void spr_clear30r(void)
 * \brief Remove all sprite from screen and init their positions in F18a 30 rows mode
*/
void spr_clear30r(void);

/*! \fn spr_update(void)
	\brief put sprite on screen
	Put all 32 sprites on screen.
	<b>Must be call in NMI routine.</b>
*/
void spr_update(void);

/*! \fn spr_updatefast(void)
	\brief put sprite on screen without checking order
	Put all 32 sprites on screen.
	<b>Must be call in NMI routine.</b>
*/
void spr_updatefast(void);

/*! \fn spr_getentry(void)
	\brief get a sprite id in sprite list 
	\return sprite entry (0..31)
	Must be used to allocate sprite because we swap sprite each NMI to <b>avoid 4 sprites limit per line.</b><br>
	<b>Warning, it uses 0xcf Y attribute to know if sprite is used or not.</b>
*/
u8 spr_getentry(void);

/*! \fn spr_getentry30r(void)
	\brief get a sprite id in sprite list 
	\return sprite entry (0..31)
	Must be used to allocate sprite because we swap sprite each NMI to <b>avoid 4 sprites limit per line.</b><br>
	<b>Warning, it uses 0xf0 Y attribute to know if sprite is used or not.</b>
*/
u8 spr_getentry30r(void);


/*! \fn spr_mode8x8(void)
	\brief put sprite in 8x8 pix mode
	Put all 32 sprites on screen in 8x8 pixels depth.
*/
void spr_mode8x8(void);

/*! \fn spr_mode16x16(void)
	\brief put sprite in 16x16 pix mode
	Put all 32 sprites on screen in 16x16 pixels depth.
*/
void spr_mode16x16(void);

/*! \fn spr_set(id,xp,yp,col,pat) 
	\brief sets an sprite entry to the supplied values
    \param id the sprite number to be get [0 - 31]
    \param xp the x location of the sprite in pixels
    \param yp the y location of the sprite in pixels
    \param col the sprite color (0 to 15)
    \param pat the pattern number of sprite (must be a multiple of 4)
*/
#define spr_set(id,  xp, yp, col, pat) \
	{ \
	sprites[id].x=xp; \
	sprites[id].y=yp; \
	sprites[id].colour=col; \
	sprites[id].pattern=pat; \
	}

/*! \fn spr_setxy(id,xp,yp) 
	\brief sets an sprite coordinate to the supplied values
    \param id the sprite number to be get [0 - 31]
    \param xp the x location of the sprite in pixels
    \param yp the y location of the sprite in pixels
*/
#define spr_setxy(id, xp, yp) \
	{ \
	sprites[id].x=xp; \
	sprites[id].y=yp; \
	}

/*! \fn spr_setx(id) 
	\brief set the x sprite coordinate 
    \param id the sprite number to be get [0 - 31]
    \param xp the x location of the sprite in pixels
*/
#define spr_setx(id,xp) { sprites[id].x=xp; }

/*! \fn spr_sety(id,yp) 
	\brief set the y sprite coordinate 
    \param id the sprite number to be get [0 - 31]
    \param yp the y location of the sprite in pixels
*/
#define spr_sety(id,yp) { sprites[id].y=yp; }

/*! \fn spr_setpat(id) 
	\brief set the sprite pattern
    \param id the sprite number to be get [0 - 31]
    \param pat the pattern of the sprite (multiple of 4)
*/
#define spr_setpat(id,pat) { sprites[id].pattern=pat; }

/*! \fn spr_setcol(id) 
	\brief set the sprite color
    \param id the sprite number to be get [0 - 31]
    \param col the sprite color (0 to 15)
*/
#define spr_setcol(id,col) { sprites[id].colour=col; }

/*! \fn spr_getx(id) 
	\brief get the x sprite coordinate 
    \param id the sprite number to be get [0 - 31]
*/
#define spr_getx(id) (sprites[id].x)

/*! \fn spr_gety(id) 
	\brief get the y sprite coordinate 
    \param id the sprite number to be get [0 - 31]
*/
#define spr_gety(id) (sprites[id].y)

/*! \fn spr_collide (sprite_t *sp1,sprite_t *sp2,unsigned sp1width,unsigned sp1height,unsigned sp2width,unsigned sp2height)
	\brief check collision between two sprites
    \param sp1 the first sprite structure
    \param sp2 the second sprite structure
    \param sp1width width of first sprite
    \param sp1height height of first sprite
    \param sp2width width of second sprite
    \param sp2height height of second sprite
    \return lobyte - first pixel set, hibyte - number of pixels set
*/
u8 spr_collide (sprite_t *sp1,sprite_t *sp2,unsigned sp1width,unsigned sp1height,unsigned sp2width,unsigned sp2height);

#endif
<file_sep>#ifndef _DIAMOND_GFXS_
#define _DIAMOND_GFXS_

#include <coleco.h>

extern const u8 NAMERLE[];
extern const u8 PATTERNRLE[];
extern const u8 COLORRLE[];

#endif
<file_sep>/*---------------------------------------------------------------------------------


	random value demo
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "randvalue.h"

//---------------------------------------------------------------------------------
// The NMI routine. Gets called 50 or 60 times per second 
// nothing to update for Input example
void nmi (void) {
}

//---------------------------------------------------------------------------------
void main (void) {
	// Put screen in text mode 2
	vdp_setmode2txt();
	
	// Put default char in VRAM and duplicate to all areas
	//  as we are going to write to line 10, it is in the second area
	vdp_setdefaultchar(FNTNORMAL);
	vdp_duplicatevram();
	vdp_fillvram(0x2000,0xf1,128*8); // Change color (or we will see nothing)
	vdp_enablescr();
	
	// Print at 10,text for the random number
	vdp_putstring(4,10,"RANDOM NUMBER=");
	
	// Wait for nothing :P
	while(1) {
		// Update display with random number and wait pad 1
		sys_utoa(sys_random(),buffer32);
		vdp_putstring(18,10,buffer32);
		
		// Wait Fire and then Vblank
		while ((joypad_1 & PAD_FIRE1)==0) { vdp_waitvblank(1); }
		vdp_waitvblank(1);
	}
	// startup module will issue a soft reboot if it comes here 
}
<file_sep>#ifndef _GRAFNOCMP_MAIN_
#define _GRAFNOCMP_MAIN_

#include <coleco.h>

#endif
<file_sep>#ifndef _DIAMOND_MAIN_
#define _DIAMOND_MAIN_

#include <coleco.h>

#endif
<file_sep>#ifndef _ANIMATEDSPR__MAIN_
#define _ANIMATEDSPR__MAIN_

#include <coleco.h>

#endif
<file_sep>/*---------------------------------------------------------------------------------

	Copyright (C) 2018-2019
		Alekmaul 

	This software is provided 'as-is', without any express or implied
	warranty.  In no event will the authors be held liable for any
	damages arising from the use of this software.

	Permission is granted to anyone to use this software for any
	purpose, including commercial applications, and to alter it and
	redistribute it freely, subject to the following restrictions:

	1.	The origin of this software must not be misrepresented; you
		must not claim that you wrote the original software. If you use
		this software in a product, an acknowledgment in the product
		documentation would be appreciated but is not required.
	2.	Altered source versions must be plainly marked as such, and
		must not be misrepresented as being the original software.
	3.	This notice may not be removed or altered from any source
		distribution.

	Image converter for colecovision.
	BMP BI_RLE8 compression support by <NAME>
	
***************************************************************************/

//INCLUDES
#include "lodepic.h"

//---------------------------------------------------------------------------
int PCX_Load(char *filename, pcx_picture_ptr image)
{
	// this function loads a pcx file into a picture structure, the actual image
	// data for the pcx file is decompressed and expanded into a secondary buffer
	// within the picture structure, the separate images can be grabbed from this
	// buffer later.  also the header and palette are loaded

	long num_bytes,index;
	long count;
	long x,y;
	unsigned char data;
	pcx_header *header;
	FILE *fp;

	// open the file
	fp = fopen(filename,"rb");
	if(fp==NULL)
	{
		printf("\nERROR: Can't open file [%s]",filename);
		return 0;
	}

	// load the header
	header = &image->header;
	fread(header, 1, 128, fp);

	header->width++;
	header->height++;

	// check to make sure this is a 256 color PCX
	if( (header->manufacturer != 10) ||
		(header->encoding != 1) ||
		(header->bits_per_pixel != 8) ||
		(header->num_color_planes != 1) ||
		(header->palette_type != 1) )
	{
		printf("\nERROR: File [%s] is not recognized as a 256 color PCX.",filename);
		fclose(fp);
		return 0;
	}

	//allocate memory for the picture + 64 empty lines
	image->buffer = malloc( (size_t)(header->height+64)*header->width );
	if(image->buffer == NULL)
	{
		printf("\nERROR: Can't allocate enough memory for the picture.");
		fclose(fp);
		return 0;
	}

	//initally clear the memory (to make those extra lines be blank)
	memset(image->buffer,0,(size_t)(header->height+64)*header->width);

	// load the data and decompress into buffer
	count=0;
	for(y=0; y < header->height; y++)
	{
		for(x=0; x < header->width; x++)
		{
			// get the first piece of data
			data = getc(fp);

			// is this a rle?
			//if ( (data>=192) && (data<=255))
			if (data>=192)
			{
				// how many bytes in run?
				num_bytes = data-192;
				x += (num_bytes-1);

				// get the actual data for the run
				data = getc(fp);

				// replicate data in buffer num_bytes times
				while( num_bytes-- > 0)
					image->buffer[count++] = data;

			} // end if rle
			else
		    {
				// actual data, just copy it into buffer at next location
				image->buffer[count++] = data;
			} // end else not rle

		} //end of x loop

		//get rid of the padding byte if there is one
		if( x < header->bytes_per_line)
			data = getc(fp);

	} //end of y loop

	//Get the Palette header (one byte, should equal 12)
	data = getc(fp);
	if(data != 12)
	{
		printf("\nERROR: Couldn't find palette header [%s]",filename);
		free(image->buffer);
		fclose(fp);

		return 0;
	}

	//get the pallete data
	for (index=0; index<256; index++)
    {
	    image->palette[index].red   = (getc(fp) >> 3);
	    image->palette[index].green = (getc(fp) >> 3);
	    image->palette[index].blue  = (getc(fp) >> 3);
    }

	//check to make sure there weren't errors while reading the file
	if(ferror(fp))
	{
		printf("\nERROR: Error reading file [%s]",filename);
		free(image->buffer);
		fclose(fp);
		return 0;
	}

	fclose(fp);

	return -1;

} // end PCX_Load

//---------------------------------------------------------------------------
void BMP_BI_RLE8_Load(pcx_picture_ptr image,
	const bmp_header* const bmphead, const bmp_info_header* const bmpinfohead,
	FILE* fp)
{
	// BI_RLE8 decompress according to:
	// https://technet.microsoft.com/ru-ru/dd183383

	unsigned long line, i, count;
	// offset in image buffer where current line starts
	unsigned int pos;
	unsigned char ch, ch2;

	// start from bottom line
	line = bmpinfohead->biHeight;
	pos = (line-1) * bmpinfohead->biWidth;

	count = 0;
	// read all image bytes
	while (count < bmpinfohead->biSizeImage)
	{
		ch = getc(fp);
		++count;
		if (ch)
		{
			// repeat byte
			ch2 = getc(fp);
			++count;
			for (i = 0; i < ch; ++i) image->buffer[pos++] = ch2;
			continue;
		}

		// escape char
		ch = getc(fp);
		++count;
		if (ch == 0)
		{
			// End of line.

			// go one line up
			--line;
			// start of this line.
			pos = (line-1) * bmpinfohead->biWidth;
		}
		else if (ch == 1)
		{
			// End of bitmap.
			break;
		}
		else if (ch == 2)
		{
			// Delta.
			// The two bytes following the escape contain unsigned values
			// indicating the horizontal and vertical offsets of the next pixel
			// from the current position.

			ch = getc(fp);
			++count;
			// go right in the buffer
			pos += ch;

			ch = getc(fp);
			++count;
			// go given lines up
			line -= ch;
			pos -= bmpinfohead->biWidth * ch;
		}
		else
		{
			// Absolute mode.
			// The second byte represents the number of bytes that follow,
			// each of which contains the color index of a single pixel.
			ch = getc(fp);
			++count;
			for (i = 0; i < ch; ++i)
			{
				image->buffer[pos++] = getc(fp);
				++count;
			}
			if (i%2)
			{
				// Each run must be aligned on a word boundary.
				// Read and throw away the placeholder.
				ch2 = getc(fp);
				++count;
			}
		}
	}
} // end BMP_BI_RLE8_Load

//---------------------------------------------------------------------------
int BMP_Load(char *filename, pcx_picture_ptr image)
{
	// this function loads a bmp file into a picture structure, the actual image
	// data for the bmp file is decompressed and expanded into a secondary buffer
	// within the picture structure, the separate images can be grabbed from this
	// buffer later.  also the header and palette are loaded
	FILE *fp;
	int index,i;
	pcx_header *header;
	bmp_header bmphead;
	bmp_info_header bmpinfohead;

	// open the file
	fp = fopen(filename,"rb");
	if(fp==NULL)
	{
		printf("\nERROR: Can't open file [%s]",filename);
		return 0;
	}

	// check to see if it is a valid bitmap file
	if (fread(&bmphead, sizeof(bmp_header), 1, fp)  < 1)
	{
		printf("\nERROR: File [%s] has no correct BMP header.",filename);
		fclose(fp);
		return 0;
	}

	if (bmphead.bfType != BF_TYPE)
	{
		printf("\nERROR: File [%s] is not recognized as a BMP file.",filename);
		fclose(fp);
		return 0;
	}

	// check to see if it is a valid bitmap file
	if (fread(&bmpinfohead, sizeof(bmpinfohead), 1, fp)  < 1)
	{
		printf("\nERROR: File [%s] has no correct BMP info header.",filename);
		fclose(fp);
		return 0;
	}

	if (bmpinfohead.biBitCount != 8 || (bmpinfohead.biCompression != 0 && bmpinfohead.biCompression != 1 /*BI_RLE8*/))
	{
		printf("\nERROR: File [%s] is not a valid BMP file: 256 colors, non-compressed or BI_RLE8 supported.",filename);
		fclose(fp);
		return 0;
	}

	// seek to palette
	fseek(fp, sizeof(bmp_header) + bmpinfohead.biSize, 0);

	// initally clear the palette if there are less then 256 colors in the file
	memset(image->palette, 0, (size_t)(256 * sizeof(RGB_color)));

	// read the palette information
	for (index = 0; index<256; index++)
	{
		image->palette[index].blue = getc(fp) >> 3;
		image->palette[index].green = getc(fp) >> 3;
		image->palette[index].red = getc(fp) >> 3;
		//data=getc(fp);
		getc(fp);
	}

	header = &image->header;
	header->width = bmpinfohead.biWidth;
	header->height = bmpinfohead.biHeight;

	// allocate memory for the picture + 64 empty lines
	image->buffer = malloc( (size_t)(header->height+64) * header->width );
	if(image->buffer == NULL)
	{
		printf("\nERROR: Can't allocate enough memory for the picture.");
		fclose(fp);
		return 0;
	}

	// initally clear the memory (to make those extra lines be blank)
	memset(image->buffer,0,(size_t)(header->height+64) * header->width);

	// seek to image data
	fseek(fp, bmphead.bfOffBits, 0);

	// read the bitmap
	if (bmpinfohead.biCompression == 0)
	{
		for(index=(header->height-1) * header->width;index>=0;index-=header->width)
			for(i=0;i<header->width;i++) 
				image->buffer[index+i] = getc(fp);
	}
	else if (bmpinfohead.biCompression == 1)
	{
		// BI_RLE8
		BMP_BI_RLE8_Load(image, &bmphead, &bmpinfohead, fp);
	}

	// check to make sure there weren't errors while reading the file
	if(ferror(fp))
	{
		printf("\nERROR: Error reading file [%s]",filename);
		free(image->buffer);
		fclose(fp);
		return 0;
	}

	fclose(fp);

	return -1;
} // end BMP_Load

//---------------------------------------------------------------------------
int TGA_Load(char *filename, pcx_picture_ptr image)
{
	// this function loads a tga file into a picture structure, the actual image
	// data for the bmp file is decompressed and expanded into a secondary buffer
	// within the picture structure, the separate images can be grabbed from this
	// buffer later.  also the header and palette are loaded
	FILE *fp;
	long index,i;
	tga_header tgahead;
	pcx_header *header;

	// open the file
	fp = fopen(filename,"rb");
	if(fp==NULL)
	{
		printf("\nERROR: Can't open file [%s]",filename);
		return 0;
	}

	// check to see if it is a valid bitmap file
	if (fread(&tgahead, sizeof(tga_header), 1, fp)  < 1)
	{
		printf("\nERROR: File [%s] has no correct TGA header.",filename);
		fclose(fp);
		return 0;
	}


		//check to make sure there weren't errors while reading the file
	if(ferror(fp))
	{
		printf("\nERROR: Error reading file [%s]",filename);
		free(image->buffer);
		fclose(fp);
		return 0;
	}


	if (tgahead.BPP != 8 || tgahead.ImageType != 1)
	{
		printf("\nERROR: File [%s] is not a valid indexed 256 colors TGA file.",filename);
		fclose(fp);
		return 0;
	}

	header = &image->header;
	header->width = tgahead.Width;
	header->height = tgahead.Height;

  //allocate memory for the picture + 64 empty lines
	image->buffer = malloc( (size_t)(header->height+64) * header->width );
	if(image->buffer == NULL)
	{
		printf("\nERROR: Can't allocate enough memory for the picture.");
		fclose(fp);
		return 0;
	}

	//initally clear the memory (to make those extra lines be blank)
	memset(image->buffer,0,(size_t)(header->height+64) * header->width);

	// read the palette information
	for(index=0;index<256;index++)
	{
		image->palette[index].blue = getc(fp) >> 3;
		image->palette[index].green = getc(fp) >> 3;
		image->palette[index].red = getc(fp) >> 3;
	}

	// read the bitmap
	for(index=(header->height-1) * header->width;index>=0;index-=header->width)
		for(i=0;i<header->width;i++)
			image->buffer[index+i] = getc(fp);

	fclose(fp);

	return -1;
} // end TGA_Load

//---------------------------------------------------------------------------
int PNG_Load(char *filename, pcx_picture_ptr image)
{
  unsigned error,sz,bpp;
  long i,index;
  unsigned char *pngimage;
  unsigned char* png = 0;
  size_t pngsize;
  LodePNGState state;
  unsigned int width, height;// , wal,hal;
  pcx_header *header;

  /*optionally customize the state*/
  lodepng_state_init(&state);

  // no conversion of color (to keep palette mode)
	state.decoder.color_convert = 0;

	error = lodepng_load_file(&png, &pngsize, filename);
  if (!error)  {
		error = lodepng_decode(&pngimage, &width, &height, &state, png, pngsize);
	}
	if(error) {
		printf("\nERROR: Decoder error %u: %s\n", error, lodepng_error_text(error));
		free(png);
		lodepng_state_cleanup(&state);
		free(pngimage);
		return 0;
	}

	bpp = state.info_raw.bitdepth;
	if ( (bpp  != 4) && (bpp != 8)) {
		printf("\nERROR: File [%s] is not a valid bbp value (%d bpp).",filename,bpp);
		free(png);
		lodepng_state_cleanup(&state);
		free(pngimage);
		return 0;
	}
	
	if (state.info_raw.colortype != LCT_PALETTE)
  {
		printf("\nERROR: File [%s] is not a valid indexed palette mode (mode %d).",filename,state.info_raw.colortype);
		free(png);
		lodepng_state_cleanup(&state);
		free(pngimage);
		return 0;
	}

	// read the palette information
	sz=state.info_png.color.palettesize;
	for(index=0;index<sz;index++) {
		image->palette[index].red = state.info_png.color.palette[(index*4) + 0]>>3;
		image->palette[index].green = state.info_png.color.palette[(index*4) + 1]>>3;
		image->palette[index].blue = state.info_png.color.palette[(index*4) + 2]>>3;
	}
	
	// get png information
	header = &image->header;
	header->width = width;
	header->height = height;

	printf("\nWidth %d Height %d",header->width,header->height);

  //allocate memory for the picture + 64 empty lines
	image->buffer = malloc( (size_t)(header->height+64) * header->width );
	if(image->buffer == NULL)	{
		printf("\nERROR: Can't allocate enough memory for the picture.");
		return 0;
	}

	//initally clear the memory (to make those extra lines be blank)
	memset(image->buffer,0,(size_t)(header->height+64) * header->width);

	// 4 bpps conversion
	if (bpp==4) {
	
		for (index = 0; index < header->height; index++) {
			for(i=0;i<header->width;i++)
				image->buffer[index+i] = pngimage[i +index*header->height];
		}
		/*
      // get buffer size
			*size = (wAligned / 2) * hAligned;
			// and alloc
			result = malloc(*size);

			srcPix = 0;
			for (i = 0; i < h; i++)
			{
				unsigned char *dst = &result[i * (wAligned / 2)];

				memset(dst, 0, wAligned / 2);

				for (j = 0; j < w; j++)
				{
						unsigned char v;

						if (srcPix & 1) v = (out[srcPix / 2] >> 4) & 0xF;
						else v =  (out[srcPix / 2] >> 0) & 0xF;
						srcPix++;

						if (j & 1) dst[j / 2] = (dst[j / 2] & 0x0F) | (v << 4);
						else dst[j / 2] = (dst[j / 2] & 0xF0) | (v << 0);
				}
			}
			for(;i < hAligned; i++)
				memset(&result[i * (wAligned / 2)], 0, wAligned / 2);
			*/
	}
	// 8 bpps conversion
	else {

		for (index = 0; index < header->height; index++) {
			for(i=0;i<header->width;i++) {
				image->buffer[i+(header->width*index)] = pngimage[i+(header->width*index)];
			}
		}
	}
			
	free(png);

	lodepng_state_cleanup(&state);

	free(pngimage);
	
	return -1;
} // end PNG_Load
<file_sep>/*---------------------------------------------------------------------------------


	small game from coder <NAME> : Easter Bunny
		made by her during 2007 MiniGame Competition 
	-- alekmaul


---------------------------------------------------------------------------------*/
#include "bunny.h"

volatile u8 color_offset;
volatile u8 flag_effect;

/* game levels */

static u8 no_level;

/* game properties */
u8 speed;
const int gravity = 384;
const int friction[] = {0,80,320,200,500,290,410,300,1024};

const int vy_min = -2048;
const int vy_max = 2048;
const int vx_min = -1024;
const int vx_max = 1024;

typedef struct
{
        unsigned y;
        unsigned x;
        int vy;
        int vx;
        int speed;
        u8 state;
} player_t;

player_t player;

u8 nbr_keys_left;

static void updatey_(u8 y)
{
        sprites[0].y = y;
        sprites[1].y = y;
        y-=8;
        sprites[2].y = y;
        sprites[3].y = y;
}

static void updatey(void)
{
        u8 y;
        y = player.y>>8;
        updatey_(y);
}

static void updatex_(u8 x)
{
        sprites[0].x = x;
        sprites[1].x = x;
        sprites[2].x = x;
        sprites[3].x = x;
}

static void updatex(void)
{
        u8 x;
        x = player.x>>8;
        updatex_(x);
}

static void slide_sprite(void)
{
    u8 i = sprites[0].x;
    u8 j = player.x>>8;
    if (i<j) i++;
    if (i>j) i--;
    updatex_(i);
    i = sprites[0].y;
    j = player.y>>8;
    if (i<j) i++;
    if (i>j) i--;
    updatey_(i);
}

static void smoke(void)
{
        sprites[4].y = (player.y>>8)+2;
        sprites[4].pattern = 0x26;
        sprites[4].colour = 0x0f;
}

static void update_smoke(void)
{
        if (sprites[4].pattern == 0x2a)
        {
                sprites[4].y = (u8) 0xf0;
        }
        else
        {
                sprites[4].y -= 4;
                sprites[4].x = player.x>>8;
                sprites[4].pattern++;
        }
}

static void bird(void)
{
        sprites[5].x = 128;
        sprites[5].y = 0;
        sprites[5].pattern = 44;
        sprites[5].colour = 0x0f;
}

static void update_bird(void)
{
    u8 i;
    u8 j;
    i = sprites[5].y;
    j = sprites[0].y;
    if (i<j) i++;
    if (i>j) i--;
    sprites[5].y=i;
    i = sprites[5].x;
    j = sprites[0].x;
    if (i<j) { i++; sprites[5].pattern=44+(i&1); }
    if (i>j) { i--; sprites[5].pattern=46+(i&1); }
    sprites[5].x=i;
}

char bird_kill(void)
{
    u8 kill = 0;
    u8 dx = (sprites[0].x-sprites[5].x);
    u8 dy = (sprites[0].y-sprites[5].y);
	dx = (dx>0x7f) ? dx : dx&0x7f;
	dy = (dy>0x7f) ? dy : dy&0x7f;
    if ( dx < 3 && dy < 5) kill = (u8)-1;
    return kill;
}

static void update_state()
{
        u8 i;
        u8 c[2];
        u8 cx[2];
        u8 cy;
        int rest_y;
        u8 nbr = 2;

        cx[0] = sprites[0].x + 2;
        cx[0] >>= 3;
        cx[1] = sprites[0].x + 5;
        cx[1] >>= 3;

        if (cx[0]==cx[1]) nbr=1;

        cy = sprites[0].y+9;
        rest_y = cy & 7;
        rest_y <<=8;
        cy >>= 3;

        player.state = AIR;
        for (i=0;i<nbr;i++)
        {
                c[i] = vdp_getchar(cx[i],cy);
                if ((c[i]&0xf0)==0x10)
                {
                        c[i]++;
                        vdp_putchar(cx[i],cy,c[i]);
                        if ((player.state & AIR) && (player.vy>=0))
                        {
                                player.state = NONE;
                                player.y -= rest_y;
                                player.y &= 0xff00;
                                updatey();
                        }
                        player.state |= GRASS;
                }
                else
                {
                        if ((c[i]&0xfc)==0x0c)
                        {
                                if ((player.state & AIR) && (player.vy>=0))
                                {
                                        player.state = NONE;
                                        player.y -= rest_y;
                                        player.y &= 0xff00;
                                        updatey();
                                }
                                if (c[i]==0x0c)
                                {
                                        player.state |= ICE;
                                }
                                if (c[i]==0x0d)
                                {
                                        player.state |= GRASS;
                                }
                                if (c[i]==0x0e)
                                {
                                        player.state |= SAND;
                                }
                                if (c[i]==0x0f)
                                {
                                        player.vy = vy_min<<1;
                                        player.state = AIR;
                                        smoke();
                                        snd_startplay(3);
                                        i = nbr;
                                }
                        }
                }
        }
        i = sprites[0].x + 3;
        i >>= 3;
        cy = sprites[0].y - 6;
        cy >>= 3;
        c[0] = vdp_getchar(i,cy);
        c[1] = vdp_getchar(i,cy+1);
        if (c[0]==0x21)
        {
                vdp_putchar(i,cy,0x20);
                nbr_keys_left--;
                snd_startplay(1);
        }
        if (c[1]==0x21)
        {
                vdp_putchar(i,cy+1,0x20);
                nbr_keys_left--;
                snd_startplay(1);
        }
}

static void update_player_y(void)
{
        if (player.state & AIR)
        {
                player.vy += gravity;
                if (player.vy > vy_max) player.vy = vy_max;
        }
        else
        {
                player.vy = 0;
                if (joypad_1 & PAD_FIRE1)
                {
                        player.vy = vy_min;
                        player.state = AIR;
                        snd_startplay(2);
                }
        }
        player.y += player.vy;
        updatey();
}

static void update_player_x(void)
{
        int abs_vx = player.vx & 0x7fff;

        if (joypad_1 & (PAD_LEFT | PAD_RIGHT))
        {
                if (joypad_1 & PAD_LEFT) player.vx -= player.speed;
                if (joypad_1 & PAD_RIGHT) player.vx += player.speed;
        }
        else
        {
                if (abs_vx > 0)
                {
                        if ((player.state & AIR)!=AIR)
                        {
                                int f = friction[player.state];
                                if (player.vx<0)
                                {
                                        if (abs_vx > f)
                                        {
                                                player.vx += f;
                                        }
                                        else
                                        {
                                                player.vx = 0;
                                        }
                                }
                                else
                                {
                                        if (abs_vx > f)
                                        {
                                                player.vx -= f;
                                        }
                                        else
                                        {
                                                player.vx = 0;
                                        }
                                }
                        }
                }
        }

        if (player.vx < vx_min) player.vx = vx_min;
        if (player.vx > vx_max) player.vx = vx_max;

        player.x += player.vx;
        if (player.x < 0x1000 || player.x > 0xE800)
        {
                player.vx = -player.vx;
                player.x += player.vx;
        }
}

static void update_player(void)
{
        update_player_x();
        update_player_y();
        update_state();
        /* Set Player Sprite Pattern */
        if (player.vx>128)
        {
            player_sprite(4);
        }
        if (player.vx<128)
        {
            player_sprite(8);
        }
        if (player.vx==0)
        {
            player_sprite(0);
        }
        /* Set Player Sprite Position */
        updatey();
        updatex();
        /* update smoke animation */
        update_smoke();
        /* update bird animation */
        update_bird();
        /* update_eggs(); */
        /* Update Sprites on Screen */
        vdp_putvram(sprgen, sprites, 25);
}

static const u8 floor_pattern[] = {0x99,0x66,0xdd,0x77,0xdd,0x77,0x99,0x66};

/* Initialise characters graphics in VideoRAM */
static void init_graphics(void)
{
        /* Load characters pattern and color */
        vdp_rle2vram(PATTERNRLE,chrgen);
		vdp_putvram_repeat (0x0060,floor_pattern,8,7);

        vdp_duplicatevram();
        vdp_rle2vram(COLORRLE,0x2000);
        /* Set sprites pattern as characters pattern */
        vdp_setreg(6,0);
}

const u8 left_border[]={0x24,0x23};
const u8 right_border[]={0x25,0x26};

static void decode_level(u8 *level)
{
	u8 x;
	u8 count;
	u8 item;
	u8 y=0;
	u8 *offset = level;
	nbr_keys_left = 0;
	count = read_next_code(&item, *offset++);
loop_y:
	vdp_waitvblank(1);
	vdp_putchar(0,y,left_border[0]);
	vdp_putchar(1,y,left_border[1]);
	x = 2;
loop_x:
	if (y==23 && item==0x20) item=0xf;
	if (item==0x22)
	{
		vdp_putchar(x,y-1,0x21);
		nbr_keys_left++;
	}
	if (item==0)
	{
		item=0x20;
		player.x = (unsigned) x;
		player.x <<= 11;
		player.y = (unsigned) y;
		player.y <<= 3;
		player.y--;
		player.y <<= 8;
		player.vx = 0;
		player.vy = 0;
		player.speed = 128;
		player.state = NONE;
	}
	vdp_putchar(x,y,item);
	count--;
	if (count==0) count = read_next_code(&item, *offset++);
	x++;
	if (x<30) goto loop_x;
	vdp_putchar(30,y,right_border[0]);
	vdp_putchar(31,y,right_border[1]);
	y++;
	if (y<24) goto loop_y;
}

static void anim_getready(void)
{
    u8 i;
    player_sprite(0);

    for (i=0;i<224;i++)
    {
        vdp_waitvblank(1);
        slide_sprite();
        invincible(i);
        vdp_putvram(sprgen, sprites, 25);
    }
    vdp_waitvblank(1);
    sprites[4].y = 0xd0;
    sprites[5].y = 0xd0;
    vdp_putvram(sprgen, sprites, 25);
}

static void game(void)
{
        u8 level_done = 0;
        decode_level((char*) levels[no_level&7]);
        snd_startplay(4);
        anim_getready();
        bird();
        /* Start BGSound */
        while(!level_done)
        {
                vdp_waitvblank(speed);
                update_player();
                if (nbr_keys_left == 0) {no_level++; level_done = (u8)-1;}
                if (bird_kill()) {snd_startplay(5); level_done=(u8)-1;}
                /* if (player.y >= 0xE000 && player.y <= 0xF000) level_done = -1; */
        }
        vdp_waitvblank(30);
        /* Stop All Sounds */
        snd_stopplay(1);
        snd_stopplay(2);
        snd_stopplay(3);
        vdp_waitvblank(1);
}

/* main function : starting point of any C program */
void main(void)
{
        snd_settable(snd_table);
        /* Default screen mode 2 setting is done in crtcv.as file */
        vdp_setmode2txt();
        /* Set Sprites to 8x8 pixels */
        spr_mode8x8();
        /* Initialise graphics and sounds */
        init_graphics();

        vdp_rle2vram(NAMERLE,0x1800);
        vdp_enablevdp();
    
        snd_startplay(6);
        snd_startplay(7);
        flag_effect = (u8)-1;
		vdp_enablenmi(); // NMI running from now till the end of the game!
        speed = 5 - sys_choice_keypad1(1,3); //choice_keypad1(1,3);
        flag_effect = 0;
        snd_stopplay(6);
        snd_stopplay(7);
    
        speed = 2;
        /* Set Player Sprite Color */
        player_color();
        /* Play game */
        no_level=0;
        while(1) game();
        /* END */
}

static const u8 colors[] = {
    0xd1,0xd1,0xd1,0x51,
    0xd1,0x51,0x51,0x51,
    0xc1,0x51,0xc1,0xc1,
    0xc1,0x21,0xc1,0x21,
    0x21,0x21,0x31,0x21,
    0x31,0x31,0x31,0xa1,
    0x31,0xa1,0xa1,0xa1,
    0x91,0xa1,0x91,0x91,
    0x91,0x81,0x91,0x81,
    0x81,0x81,0xd1,0x81,
    0xd1,0xd1,0xd1,0x51,
    0xd1,0x51,0x51,0x51,
    0xc1,0x51,0xc1,0xc1,
    0xc1,0x21,0xc1,0x21,
    };

void nmi(void)
{
    if (flag_effect)
    {
        color_offset++;
        if (color_offset > 39) color_offset = 0;
		vdp_putvram_repeat (0x2400,&colors[color_offset],8,12);
		vdp_putvram_repeat (0x2460,&colors[color_offset+8],8,12);    
    }    
}
<file_sep>#ifndef LODEPIC_H
#define LODEPIC_H

#include <stdio.h>
#include <malloc.h>
#include <string.h>

#include "lodepng.h"

#pragma pack(1)                        // for bmp header to avoid data alignment

//STRUCTURES

typedef struct RGB_color_typ
{
	unsigned char red;      			//Red component if color 0-63
	unsigned char green;    			//Green component of color 0-63
	unsigned char blue;     			//Blue component of color 0-63
} RGB_color, *RGB_color_ptr;

typedef struct pcx_header_typ
{
	char manufacturer;					// Always 10.
	char version;						// 0-Ver 2.5 Paintbrush, 2-Ver 2.8 with
										// palette, 3-Ver 2.8 use the default palette,
										// 5-Ver 3.0 or higher of Paintbrush
	char encoding;						// Always 1, meaning RLE encoding.
	char bits_per_pixel;				// Bits per pixel; in our case, eight
	short x,y;							// Upper-left corner of the image
	short width, height;				// Size of the image
	short horv_res;						// Pixels in the x direction
	short vert_res;						// Pixels in the y direction
	char ega_palette[48];				// The EGA palette; we can ignore it
	char reserved;						// Nothing
	char num_color_planes;				// The number of planes in the image
	short bytes_per_line;				// Bytes per one horizontal line
	short palette_type;					// 1 = Color or B&W    2 = Grayscale
	char padding[58];					// Extra bytes for a rainy day
} pcx_header, *pcx_header_ptr;

typedef struct pcx_picture_typ
{
	pcx_header header;					// The header
	RGB_color palette[256];				// The VGA palette
	unsigned char *buffer;				// The buffer to hold the image
} pcx_picture, *pcx_picture_ptr;

typedef struct bmp_header_typ           // *** BMP file header structure ***
{
    unsigned short bfType;				// Magic number for file
    unsigned int   bfSize;				// Size of file
    unsigned short bfReserved1;			// Reserved
    unsigned short bfReserved2;			//  ... 
    unsigned int   bfOffBits;			// Offset to bitmap data
} bmp_header;

#  define BF_TYPE 0x4D42				// "MB"

typedef struct bmp_info_header_typ
{
    unsigned int   biSize;				// Size of info header
    int            biWidth;				// Width of image
    int            biHeight;			// Height of image
    unsigned short biPlanes;			// Number of color planes
    unsigned short biBitCount;			// Number of bits per pixel
    unsigned int   biCompression;		// Type of compression to use
    unsigned int   biSizeImage;			// Size of image data
    int            biXPelsPerMeter;		// X pixels per meter
    int            biYPelsPerMeter;		// Y pixels per meter
    unsigned int   biClrUsed;			// Number of colors used 
    unsigned int   biClrImportant;		// Number of important colors 
} bmp_info_header;

typedef struct tga_hearder_type
{
	unsigned char Offset; 				// Usually 0,  add 18 to this value to find the start of the palette/image data.
	unsigned char ColorType; 			// Image type. 0 = RGB, 1 = Indexed.
	unsigned char ImageType;			// 0 = None, 1 = Indexed, 2 = RGB, 3 = Greyscale, +8 = RLE encoded.
 	unsigned short PaletteStart; 		// Start of palette.
  	unsigned short PaletteLen; 			// Number of palette entries.
  	unsigned char PalBits; 				// Bits per colour entry.
  	unsigned short XOrigin; 			// Image X Origin
 	unsigned short YOrigin; 			// Image Y Origin
 	unsigned short Width; 				// Image width (Pixels).
 	unsigned short Height; 				// Image height (Pixels)
 	unsigned char BPP; 					// Bits per pixel (8,16,24 or 32)
 	unsigned char Orientation; 			// If Bit 5 is set, the image will be upside down (like BMP)
} tga_header;

//---------------------------------------------------------------------------
extern int PCX_Load(char *filename, pcx_picture_ptr image);
extern int BMP_Load(char *filename, pcx_picture_ptr image);
extern int TGA_Load(char *filename, pcx_picture_ptr image);
extern int PNG_Load(char *filename, pcx_picture_ptr image);

#endif
<file_sep>#ifndef _HELLOWORLD_MAIN_
#define _HELLOWORLD_MAIN_

#include <coleco.h>

#endif
<file_sep>#ifndef _SGMTEST_MAIN_
#define _SGMTEST_MAIN_

#include <coleco.h>

#endif
<file_sep>cmake_minimum_required (VERSION 3.1)

project(bin2txt C)

set(bin2txt_major_version 1)
set(bin2txt_minor_version 0)
set(bin2txt_path_version 0)
set(bin2txt_version "${bin2txt_major_version}.${bin2txt_minor_version}.${bin2txt_path_version}")

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE "Debug")
endif()

set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}")

set(CMAKE_C_STANDARDS 11)

configure_file(config.h.in config.h)

set(bin2txt_sources
	bin2txt.c
)

set(bin2txt_headers
    config.h
)

add_executable(bin2txt ${bin2txt_sources} ${bin2txt_headers})
target_compile_options(bin2txt PRIVATE -Wall -Wshadow -Wextra)
target_include_directories(bin2txt PRIVATE ${CMAKE_BINARY_DIR})

install(TARGETS bin2txt RUNTIME DESTINATION bin)
<file_sep>#ifndef _MEGACART_MAIN_
#define _MEGACART_MAIN_

#include <coleco.h>

#endif
