msx: worked on kbd, psg, joy; added msx-libcv

This commit is contained in:
Steven Hugg 2019-08-17 14:12:14 -04:00
parent 30acd01f62
commit 04b6417ddf
37 changed files with 1434 additions and 35 deletions

1
presets/msx-libcv Symbolic link
View File

@ -0,0 +1 @@
coleco

View File

@ -1,13 +1,10 @@

; Hello World example
; ROM routine for character output
CHPUT: equ $00A2
; waste space @ 0x0000 - 0x3fff
org 0x0000
db 0
ds 0x3fff
org 0x4000
; MSX cartridge header @ 0x4000 - 0x400f
dw 0x4241

34
presets/msx/helloworld.s Normal file
View File

@ -0,0 +1,34 @@
; Hello World example
; ROM routine for character output
CHGET = #0x009F
CHPUT = #0x00A2
; Bank 1
.area _CODE
; MSX cartridge header @ 0x4000 - 0x400f
.dw 0x4241
.dw Init
.dw Init
.dw 0
.dw 0
.dw 0
.dw 0
.dw 0
; initialize and print message
Init:
ld hl,#msg
call puts
jp Init ; loop forever
puts: ; print 0-terminated string in HL
ld a,(hl)
or a
ret z
call CHPUT ; displays one character in A
inc hl
jr puts
; ASCII message + CR LF
msg: .ascii "Hello, world!\n\r\0"

View File

@ -39,6 +39,10 @@ export class AY38910_Audio {
setData(val : number) {
this.psg.writeRegisterAY(this.curreg, val & 0xff);
}
readData() {
return this.psg.readRegister(this.curreg);
}
currentRegister() { return this.curreg; }
}
export class SN76489_Audio {

View File

@ -1086,7 +1086,7 @@ export abstract class BasicZ80ScanlinePlatform extends BaseZ80Platform {
audio;
psg;
pixels : Uint32Array;
inputs = new Uint8Array(16);
inputs : Uint8Array = new Uint8Array(32);
mainElement : HTMLElement;
poller : ControllerPoller;

View File

@ -335,7 +335,8 @@ interface KeyMapEntry {
type KeyCodeMap = Map<number,KeyMapEntry>;
export const Keys : {[keycode:string]:KeyDef} = {
export const Keys = {
ANYKEY: {c: 0, n: "?"},
// gamepad and keyboard (player 0)
UP: {c: 38, n: "Up", plyr:0, yaxis:-1},
DOWN: {c: 40, n: "Down", plyr:0, yaxis:1},
@ -471,7 +472,12 @@ type KeyMapFunction = (o:KeyMapEntry, key:number, code:number, flags:number) =>
export function setKeyboardFromMap(video:RasterVideo, switches:number[]|Uint8Array, map:KeyCodeMap, func?:KeyMapFunction) {
var handler = (key,code,flags) => {
if (!map) {
func(null, key, code, flags);
return;
}
var o : KeyMapEntry = map[key];
if (!o) o = map[0];
if (o && func) {
func(o, key, code, flags);
}

View File

@ -1,9 +1,9 @@
"use strict";
import { Platform, BasicZ80ScanlinePlatform } from "../baseplatform";
import { PLATFORMS, newAddressDecoder, padBytes, noise, makeKeycodeMap, Keys } from "../emu";
import { PLATFORMS, newAddressDecoder, padBytes, noise, makeKeycodeMap, KeyFlags, Keys, EmuHalt } from "../emu";
import { hex, lzgmini, stringToByteArray } from "../util";
import { MasterAudio, SN76489_Audio } from "../audio";
import { MasterAudio, AY38910_Audio } from "../audio";
import { TMS9918A } from "../video/tms9918a";
// https://www.konamiman.com/msx/msx-e.html#msx2th
@ -12,28 +12,48 @@ import { TMS9918A } from "../video/tms9918a";
// https://openmsx.org/manual/setup.html
// https://www.msx.org/wiki/Slots
// https://www.msx.org/wiki/SDCC
// http://cbios.sourceforge.net/
var MSX_PRESETS = [
{id:'helloworld.asm', name:'Hello World (ASM)'},
];
var MSX_KEYCODE_MAP = makeKeycodeMap([
[Keys.UP, 0, 0x1],
[Keys.DOWN, 0, 0x4],
[Keys.LEFT, 0, 0x8],
[Keys.RIGHT, 0, 0x2],
[Keys.A, 0, 0x40],
[Keys.B, 1, 0x40],
[Keys.UP, 0, 0x1],
[Keys.DOWN, 0, 0x2],
[Keys.LEFT, 0, 0x4],
[Keys.RIGHT, 0, 0x8],
[Keys.A, 0, 0x10],
[Keys.B, 0, 0x20],
[Keys.P2_UP, 2, 0x1],
[Keys.P2_DOWN, 2, 0x4],
[Keys.P2_LEFT, 2, 0x8],
[Keys.P2_RIGHT, 2, 0x2],
[Keys.P2_A, 2, 0x40],
[Keys.P2_B, 3, 0x40],
[Keys.P2_UP, 1, 0x1],
[Keys.P2_DOWN, 1, 0x2],
[Keys.P2_LEFT, 1, 0x4],
[Keys.P2_RIGHT, 1, 0x8],
[Keys.P2_A, 1, 0x10],
[Keys.P2_B, 1, 0x20],
[Keys.ANYKEY, 2, 0x0],
]);
const JOY_INPUT_0 = 0;
const JOY_INPUT_1 = 1;
const KEYBOARD_ROW_0 = 16;
const MSX_KEYMATRIX_INTL_NOSHIFT = [
Keys.VK_7, Keys.VK_6, Keys.VK_5, Keys.VK_4, Keys.VK_3, Keys.VK_2, Keys.VK_1, Keys.VK_0,
Keys.VK_SEMICOLON, Keys.VK_CLOSE_BRACKET, Keys.VK_OPEN_BRACKET, Keys.VK_BACK_SLASH, Keys.VK_EQUALS, Keys.VK_MINUS, Keys.VK_9, Keys.VK_8,
Keys.VK_B, Keys.VK_A, null/*DEAD*/, Keys.VK_SLASH, Keys.VK_PERIOD, Keys.VK_COMMA, Keys.VK_ACUTE, Keys.VK_QUOTE,
Keys.VK_J, Keys.VK_I, Keys.VK_H, Keys.VK_G, Keys.VK_F, Keys.VK_E, Keys.VK_D, Keys.VK_C,
Keys.VK_R, Keys.VK_Q, Keys.VK_P, Keys.VK_O, Keys.VK_N, Keys.VK_M, Keys.VK_L, Keys.VK_K,
Keys.VK_Z, Keys.VK_Y, Keys.VK_X, Keys.VK_W, Keys.VK_V, Keys.VK_U, Keys.VK_T, Keys.VK_S,
Keys.VK_F3, Keys.VK_F2, Keys.VK_F1, null, Keys.VK_CAPS_LOCK, null, Keys.VK_CONTROL, Keys.VK_SHIFT,
Keys.VK_ENTER, null, Keys.VK_BACK_SPACE, null, Keys.VK_TAB, Keys.VK_ESCAPE, Keys.VK_F5, Keys.VK_F4,
Keys.VK_RIGHT, Keys.VK_DOWN, Keys.VK_UP, Keys.VK_LEFT, Keys.VK_DELETE, Keys.VK_INSERT, Keys.VK_HOME, Keys.VK_SPACE,
null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null,
// TODO: null keycodes
];
/// standard emulator
interface MSXSlot {
@ -47,16 +67,38 @@ class MSXPlatform extends BasicZ80ScanlinePlatform implements Platform {
canvasWidth = 304;
numTotalScanlines = 262;
numVisibleScanlines = 240;
defaultROMSize = 0x10000;
defaultROMSize = 0x8000;
vdp : TMS9918A;
bios : Uint8Array;
slots : MSXSlot[];
slotmask : number = 0;
ppi_c : number = 0;
getPresets() { return MSX_PRESETS; }
getKeyboardMap() { return MSX_KEYCODE_MAP; }
// http://map.grauw.nl/articles/keymatrix.php
getKeyboardFunction() {
return (o,key,code,flags) => {
//console.log(o,key,code,flags);
var keymap = MSX_KEYMATRIX_INTL_NOSHIFT;
for (var i=0; i<keymap.length; i++) {
if (keymap[i] && keymap[i].c == key) {
let row = i >> 3;
let bit = 7 - (i & 7);
//console.log(key, row, bit);
if (flags & KeyFlags.KeyDown) {
this.inputs[KEYBOARD_ROW_0+row] |= (1<<bit);
} else if (flags & KeyFlags.KeyUp) {
this.inputs[KEYBOARD_ROW_0+row] &= ~(1<<bit);
}
break;
}
}
};
}
getVideoOptions() { return {overscan:true}; }
@ -90,7 +132,13 @@ class MSXPlatform extends BasicZ80ScanlinePlatform implements Platform {
switch (addr) {
case 0x98: return this.vdp.readData();
case 0x99: return this.vdp.readStatus();
case 0xa2:
if (this.psg.currentRegister() == 14) return ~this.inputs[JOY_INPUT_0]; // TODO: joy 1?
else return this.psg.readData();
case 0xa8: return this.slotmask;
case 0xa9: return ~this.inputs[KEYBOARD_ROW_0 + (this.ppi_c & 15)];
case 0xaa: return this.ppi_c; // TODO?
//default: throw new EmuHalt("Read I/O " + hex(addr));
}
return 0;
},
@ -102,6 +150,19 @@ class MSXPlatform extends BasicZ80ScanlinePlatform implements Platform {
case 0x98: this.vdp.writeData(val); break;
case 0x99: this.vdp.writeAddress(val); break;
case 0xa8: this.slotmask = val; break;
case 0xaa: this.ppi_c = val; break;
case 0xab: // command register, modifies PPI C
let ibit = (val >> 1) & 7;
this.ppi_c = (this.ppi_c & ~(1<<ibit)) | ((val&1)<<ibit);
break;
case 0xa0: this.psg.selectRegister(val); break;
case 0xa1: this.psg.setData(val); break;
case 0xfc:
case 0xfd:
case 0xfe:
case 0xff:
break; // memory mapper (MSX2)
//default: throw new EmuHalt("Write I/O " + hex(addr));
}
}
};
@ -110,6 +171,11 @@ class MSXPlatform extends BasicZ80ScanlinePlatform implements Platform {
start() {
super.start();
this.bios = new lzgmini().decode(stringToByteArray(atob(MSX1_BIOS_LZG)));
// skip splash screen
this.bios[0xdd5] = 0;
this.bios[0xdd6] = 0;
this.bios[0xdd7] = 0;
// slot definitions
this.slots = [
// slot 0 : BIOS
{
@ -118,11 +184,14 @@ class MSXPlatform extends BasicZ80ScanlinePlatform implements Platform {
},
// slot 1: cartridge
{
read: (a) => { return this.rom[a] | 0; },
read: (a) => { return this.rom[a - 0x4000] | 0; },
write: (a,v) => { }
},
// slot 2: cartridge
{
read: (a) => { return this.rom[a - 0x4000] | 0; },
write: (a,v) => { }
},
// slot 2 : empty
null,
// slot 3 : RAM
{
read: (a) => { return this.ram[a] | 0; },
@ -130,11 +199,11 @@ class MSXPlatform extends BasicZ80ScanlinePlatform implements Platform {
},
];
this.audio = new MasterAudio();
this.psg = new SN76489_Audio(this.audio);
this.psg = new AY38910_Audio(this.audio);
var cru = {
setVDPInterrupt: (b) => {
if (b) {
this.cpu.nonMaskableInterrupt();
this.cpu.requestInterrupt(0x38);
} else {
// TODO: reset interrupt?
}
@ -158,11 +227,15 @@ class MSXPlatform extends BasicZ80ScanlinePlatform implements Platform {
super.loadState(state);
this.vdp.restoreState(state['vdp']);
this.slotmask = state['slotmask'];
this.ppi_c = state['ppi_c'];
this.psg.selectRegister(state['psgRegister']);
}
saveState() {
var state = super.saveState();
state['vdp'] = this.vdp.getState();
state['slotmask'] = this.slotmask;
state['ppi_c'] = this.ppi_c;
state['psgRegister'] = this.psg.currentRegister();
return state;
}
reset() {
@ -170,6 +243,15 @@ class MSXPlatform extends BasicZ80ScanlinePlatform implements Platform {
this.vdp.reset();
this.psg.reset();
this.slotmask = 0;
this.ppi_c = 0;
}
resume() {
super.resume();
this.resetInputs();
}
resetInputs() {
// clear keyboard matrix
this.inputs.fill(0);
}
getDebugCategories() {
@ -192,9 +274,18 @@ class MSXPlatform extends BasicZ80ScanlinePlatform implements Platform {
///
PLATFORMS['msx'] = MSXPlatform;
PLATFORMS['msx-libcv'] = MSXPlatform;
///
/*
C-BIOS is a BIOS compatible with the MSX BIOS
C-BIOS was written from scratch by BouKiCHi
C-BIOS is available for free, including its source code (2-clause BSD license)
C-BIOS can be shipped with MSX emulators so they are usable out-of-the-box without copyright issues
http://cbios.sourceforge.net/
*/
var MSX1_BIOS_LZG = `
TFpHAADAAAAAI8Sp+W4NAVo7UZPzwxINvxuYmMPtEADDvyMAw/+T4QAkAMMbEQDDNJPhIZPhc5Ph
JxEhAgAAAMM5EZOhk+HmGMNOEcNYEcMWAsMiAsMuAsNFAsNNAsNVAsNgAsNtAsOBAsOXAsOtAsPU

View File

@ -0,0 +1,91 @@
1 ; crt0.s for Colecovision cart
2
3 .module crt0
4 .globl _main
5 .globl _cv_init
6 .globl _cv_spint_handler
7 .globl _cv_vint
8 .globl _cv_start
9 .globl ___sdcc_call_hl
10
11 ; Ordering of segments for the linker - copied from sdcc crt0.s
12 .area _CODE
13 .area _INITIALIZER
14 .area _HOME
15 .area _GSINIT
16 .area _GSFINAL
17 .area _DATA
18 .area _INITIALIZED
19 .area _BSEG
20 .area _BSS
21 .area _HEAP
22
23 .area _CODE
24 ; MSX cartridge header @ 0x4000 - 0x400f
0000 41 42 25 .dw 0x4241
0002r10r00 26 .dw _cv_start
0004r10r00 27 .dw _cv_start
0006 00 00 28 .dw 0
0008 00 00 29 .dw 0
000A 00 00 30 .dw 0
000C 00 00 31 .dw 0
000E 00 00 32 .dw 0
33
0010 34 _cv_start:
0010 F3 [ 4] 35 di
0011 31 00 E0 [10] 36 ld sp, #0xe000 ; Set stack pointer directly above top of memory.
0014 ED 56 [ 8] 37 im 1
38
0016 CDr00r00 [17] 39 call gsinit ; Initialize global and static variables.
0019 CDr00r00 [17] 40 call vinthook
001C CDr00r00 [17] 41 call _cv_init ; Initialize Colecovision specific stuff.
001F CDr00r00 [17] 42 call _main
0022 C7 [11] 43 rst 0x0 ; Restart when main() returns.
44
45 .area _GSINIT
0000 46 gsinit::
47
48 ; Implicitly zeroed global and static variables.
0000 01r00r00 [10] 49 ld bc, #l__DATA
0003 78 [ 4] 50 ld a, b
0004 B1 [ 4] 51 or a, c
0005 28 0F [12] 52 jr Z, zeroed_data
0007 21r00r00 [10] 53 ld hl, #s__DATA
000A 36 00 [10] 54 ld (hl), #0x00
000C 0B [ 6] 55 dec bc
000D 78 [ 4] 56 ld a, b
000E B1 [ 4] 57 or a, c
000F 28 05 [12] 58 jr Z, zeroed_data
0011 5D [ 4] 59 ld e, l
0012 54 [ 4] 60 ld d, h
0013 13 [ 6] 61 inc de
0014 ED B0 [21] 62 ldir
0016 63 zeroed_data:
64
65 ; Explicitly initialized global variables.
0016 01r00r00 [10] 66 ld bc, #l__INITIALIZER
0019 78 [ 4] 67 ld a, b
001A B1 [ 4] 68 or a, c
001B 28 08 [12] 69 jr Z, gsinit_static
001D 11r00r00 [10] 70 ld de, #s__INITIALIZED
0020 21r00r00 [10] 71 ld hl, #s__INITIALIZER
0023 ED B0 [21] 72 ldir
73
0025 74 gsinit_static:
75 ; Explicitly initialized static variables inserted by compiler here.
76
77 .area _GSFINAL
0000 C9 [10] 78 ret
79
80 .area _HOME
81
82 ; set up timer hook
FD9F 83 H_TIMI = 0xFD9F
0000 84 vinthook:
0000 3E C3 [ 7] 85 ld a,#0xc3
0002 32 9F FD [13] 86 ld (H_TIMI),a
0005 3Er00 [ 7] 87 ld a, #<(_cv_vint)
0007 32 A0 FD [13] 88 ld (H_TIMI+1),a
000A 3Es00 [ 7] 89 ld a, #>(_cv_vint)
000C 32 A1 FD [13] 90 ld (H_TIMI+2),a
000F C9 [10] 91 ret

View File

@ -0,0 +1,58 @@
XL2
H A areas D global symbols
M crt0
S _cv_spint_handler Ref0000
S l__DATA Ref0000
S _main Ref0000
S s__DATA Ref0000
S _cv_init Ref0000
S _cv_vint Ref0000
S .__.ABS. Def0000
S s__INITIALIZED Ref0000
S ___sdcc_call_hl Ref0000
S l__INITIALIZER Ref0000
S s__INITIALIZER Ref0000
A _CODE size 23 flags 0 addr 0
S _cv_start Def0010
A _INITIALIZER size 0 flags 0 addr 0
A _HOME size 10 flags 0 addr 0
A _GSINIT size 25 flags 0 addr 0
S gsinit Def0000
A _GSFINAL size 1 flags 0 addr 0
A _DATA size 0 flags 0 addr 0
A _INITIALIZED size 0 flags 0 addr 0
A _BSEG size 0 flags 0 addr 0
A _BSS size 0 flags 0 addr 0
A _HEAP size 0 flags 0 addr 0
T 00 00 41 42 10 00 10 00 00 00 00 00 00 00 00 00
R 00 00 00 00 00 04 00 00 00 06 00 00
T 0E 00 00 00
R 00 00 00 00
T 10 00
R 00 00 00 00
T 10 00 F3 31 00 E0 ED 56 CD 00 00 CD 00 00 CD
R 00 00 00 00 00 09 03 00 00 0C 02 00
T 1D 00 00 00 CD 00 00 C7
R 00 00 00 00 02 02 04 00 02 05 02 00
T 00 00
R 00 00 03 00
T 00 00 01 00 00 78 B1 28 0F 21 00 00 36 00 0B 78
R 00 00 03 00 02 03 01 00 02 0A 03 00
T 0E 00 B1 28 05 5D 54 13 ED B0
R 00 00 03 00
T 16 00
R 00 00 03 00
T 16 00 01 00 00 78 B1 28 08 11 00 00 21 00 00 ED
R 00 00 03 00 02 03 09 00 02 0A 07 00 02 0D 0A 00
T 24 00 B0
R 00 00 03 00
T 25 00
R 00 00 03 00
T 00 00 C9
R 00 00 04 00
T 00 00
R 00 00 02 00
T 00 00 3E C3 32 9F FD 3E 00 00 32 A0 FD 3E 00 00
R 00 00 02 00 0B 08 05 00 8B 0E 05 00
T 0C 00 32 A1 FD C9
R 00 00 02 00

62
src/worker/lib/msx-libcv/cv.h Executable file
View File

@ -0,0 +1,62 @@
// (c) 2013 Philipp Klaus Krause
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, 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
// Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef CV_H
#define CV_H 1
#include <stdint.h>
#define CV_LIBVERSION_MAJOR 0
#define CV_LIBVERSION_MINOR 24
#define CV_LIBVERSION_STRING "0.24"
#include "cv_input.h"
#include "cv_graphics.h"
#include "cv_sound.h"
// Set the handler for the vertical retrace interrupt.
extern void cv_set_vint_handler(void (* handler)(void));
// Get the handler for the vertical retrace interrupt.
extern void *cv_get_vint_handler(void);
// Get the vertical retrace frequency in Hz. 50 for PAL, 60 for NTSC.
unsigned char cv_get_vint_frequency(void);
#ifdef CV_CV
enum cv_machine {
CV_COLECOVISION = 0, // Coleco ColecoVision
//CV_ADAM = 1, // Coleco Adam - TODO
//CV_SUPERGAME = 2, // Coleco ColecoVision with super game module
};
#endif
#ifdef CV_SMS
enum cv_machine {
CV_SG1000 = 0, // Sega SG-1000
CV_SC3000 = 1, // Sega SC-3000
CV_MARKIII = 2, // Sega Mark III or Master System
//CV_GAMEGEAR = 3, // Sega Game Gear - TODO
};
#endif
// Find out on which machine we are running
enum cv_machine cv_get_machine(void);
// Get the contents of the refresh register R. Can be useful for seeding PRNGs.
uint8_t cv_get_r(void) __preserves_regs(b, c, d, e, h, iyl, iyh);
#endif

View File

@ -0,0 +1,255 @@
#ifndef CV_GRAPHICS_H
#define CV_GRAPHICS_H 1
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
/*
These are the functions for controlling the graphics chip.
While a function marked as not reentrant is called no other
such function from this file may be called at the same time.
*/
typedef uint16_t cv_vmemp; // 14-Bit video memory address type
#ifdef CV_SMS
typedef uint8_t cv_cmemp; // 5-bit color memory address type
#endif
/*
Activate / deactivate screen
This function is not reentrant!
*/
extern void cv_set_screen_active(bool status);
/*
Get screen status
*/
extern bool cv_get_screen_active(void);
/*
Enable / disable external video source.
This function is not reentrant!
*/
extern void cv_set_external_video(bool status);
/*
Get external video source enabled.
*/
extern bool cv_get_external_video(void);
// TMS99xxA and Sega Master System screen modes
enum cv_screenmode {
CV_SCREENMODE_STANDARD = 0x00, // Standard screen modes
CV_SCREENMODE_TEXT = 0x10,
CV_SCREENMODE_MULTICOLOR = 0x08,
CV_SCREENMODE_BITMAP = 0x02,
CV_SCREENMODE_BITMAP_TEXT = 0x12, // Usefull undocumented screen modes
CV_SCREENMODE_BITMAP_MULTICOLOR = 0x0a,
CV_SCREENMODE_TEXT_MULTICOLOR = 0x18, // Useless undocumented screen modes
CV_SCREENMODE_BITMAP_TEXT_MULTICOLOR = 0x1a,
CV_SCREENMODE_4 = 0x06, // Sega Master System 315-5124 mode
CV_SCREENMODE_4_224 = 0x16, // Sega Master System 315-5246 modes
CV_SCREENMODE_4_240 = 0x0e,
};
/*
Set screen mode.
This function is not reentrant!
*/
extern void cv_set_screen_mode(enum cv_screenmode mode);
/*
Get screen mode.
*/
extern enum cv_screenmode cv_get_screen_mode(void);
// TMS99xxA colors
enum cv_color {
CV_COLOR_TRANSPARENT = 0x0,
CV_COLOR_BLACK = 0x1,
CV_COLOR_GREEN = 0x2,
CV_COLOR_LIGHT_GREEN = 0x3,
CV_COLOR_BLUE = 0x4,
CV_COLOR_LIGHT_BLUE = 0x5,
CV_COLOR_DARK_RED = 0x6,
CV_COLOR_CYAN = 0x7,
CV_COLOR_RED = 0x8,
CV_COLOR_LIGHT_RED = 0x9,
CV_COLOR_YELLOW = 0xa,
CV_COLOR_LIGHT_YELLOW = 0xb,
CV_COLOR_DARK_GREEN = 0xc,
CV_COLOR_MAGENTA = 0xd,
CV_COLOR_GRAY = 0xe,
CV_COLOR_WHITE = 0xf
};
/*
Set colors. The foreground color is the text color in text mode,
in other modes it is unused.
The background color is used in all modes for the backdrop plane
(screen outside display area) and as the color that appears under
transparent characters. In text mode it is used for character
background. If the background color is the to cv_transparent,
the external video source is used as background image.
*/
extern void cv_set_colors(enum cv_color foreground, enum cv_color background);
/*
Set the location of the screen image table.
Must be a multiple of 0x400. Valid range: [0; 15360].
When the screenmode is CV_SCREENMODE4 on the Sega 315-5124,
the location is a multible of 0x800, and the bit 0x400 is and mask to the location.
This masking functionality is undocumented. To use only the documented
graphics chip functionality always set bit 0x400.
*/
extern void cv_set_image_table(cv_vmemp loc);
/*
Set the location of the color table. Must be a multiple of 0x40.
Valid range: [0; 16320].
When the screen mode ist CV_SCREENMODE_BITMAP,
CV_SCREENMODE_BITMAP_TEXT or CV_SCREENMODE_BITMAP_MULTICOLOR
this has a different meaning: The location of the color pattern table is
either 0 or 8192. The bits 4096 downto 128 are an and mask to the location.
This masking functionality is undocumented. To use only the documented
graphics chip functionality always set bits 4096 downto 128.
*/
void cv_set_color_table(cv_vmemp loc);
/*
Set the location of the character pattern table. Must be a multiple
of 0x800. Valid range: [0; 14336].
When the screen mode ist CV_SCREENMODE_BITMAP,
CV_SCREENMODE_BITMAP_TEXT or CV_SCREENMODE_BITMAP_MULTICOLOR
this has a different meaning: The location of the character pattern table is
either 0 or 8192. Unless you add 4096 to the location the first third of the table
is used for the last third of the screen. Unless you add 2048 to the location the
first third of the table is used for the middle part of the screen.
Thus the bits 4096 and 2048 are and and mask to the highest bits of the
address. This masking functionality is undocumented. To use only the
documented graphics chip functionality always set bits 4096 and 2048.
*/
// sdcc doesn't accept long function names.
extern void cv_set_character_pattern_t(cv_vmemp loc);
/*
Set the location of the sprite pattern table.
Must be a multiple of 0x800. Valid range: [0; 14336].
When the screenmode is CV_SCREENMODE4 the location is a multiple of 0x2000.
For the Sega 315-5124 and CV_SCREENMODE4, bits 0x800 and 0x1000 are
used as and mask. This masking functionality is undocumented. To use only the documented
graphics chip functionality always set bits 0x1000 downto 0x800.
*/
extern void cv_set_sprite_pattern_table(cv_vmemp loc);
/*
Set the location of the sprite attribute table.
Must be a multiple of 0x80. Valid range: [0; 16256].
*/
extern void cv_set_sprite_attribute_table(cv_vmemp loc);
/*
Set sprite size; When active, sprites are 16x16 pixels instead of 8x8.
This function is not reentrant!
*/
extern void cv_set_sprite_big(bool status);
/*
Get sprite size.
*/
extern bool cv_get_sprite_big(void);
/*
Set sprite magnification. When active, all sprites are displayed twice as big.
This function is not reentrant!
*/
extern void cv_set_sprite_magnification(bool status);
/*
Get sprite magnification.
*/
extern bool cv_get_sprite_magnification(void);
/*
Get sprite collission.
*/
extern bool cv_get_sprite_collission(void);
/*
Get invalid sprite. Returns true if there was an invalid sprite.
If sprite is not 0 it will point to the number of the invalid sprite.
*/
extern bool cv_get_sprite_invalid(uint8_t *sprite);
extern void cv_set_write_vram_address(cv_vmemp address) __preserves_regs(b, c, d, e);
extern void cv_set_read_vram_address(cv_vmemp address) __preserves_regs(b, c, d, e);
#ifdef CV_SMS
extern void cv_set_write_cram_address(cv_cmemp address) __preserves_regs(b, c, d, e);
#endif
extern void cv_memtovmemcpy_slow(const void *src, size_t n);
extern void cv_memtovmemcpy_fast(const void *src, size_t n);
extern void cv_vmemtomemcpy_slow(void *dest, size_t n);
extern void cv_vmemtomemcpy_fast(void *dest, size_t n);
extern void cv_vmemset_slow(int c, size_t n) __preserves_regs(iyl, iyh);
extern void cv_vmemset_fast(int c, size_t n) __preserves_regs(iyl, iyh);
#ifdef CV_MSX
static volatile __sfr __at 0x98 cv_graphics_port;
#else
static volatile __sfr __at 0xbe cv_graphics_port;
#endif
inline void cv_voutb(const uint8_t value)
{
__asm
cp a, (hl)
cp a, (hl)
nop
__endasm;
cv_graphics_port = value;
}
inline uint8_t cv_vinb(void)
{
__asm
cp a, (hl)
cp a, (hl)
nop
__endasm;
return(cv_graphics_port);
}
#ifdef CV_SMS
void cv_set_left_column_blank(bool status);
void cv_set_sprite_shift(bool status);
enum cv_scroll_inhibit {
CV_HORIZONTAL_SCROLL_INHIBIT = 0x40, // Do not scroll top 2 rows
CV_VERTICAL_SCROLL_INHIBIT = 0x80, // Do not scroll right 8 columns
};
void cv_set_scroll_inhibit(enum cv_scroll_inhibit inhibit);
void cv_set_hscroll(uint8_t offset);
void cv_set_vscroll(uint8_t offset);
#endif
#endif

View File

@ -0,0 +1,60 @@
#ifndef CV_INPUT_H
#define CV_INPUT_H 1
#include <stdint.h>
#ifdef CV_CV
#define CV_FIRE_0 0x40
#define CV_FIRE_1 0x80
#define CV_FIRE_2 0x10
#define CV_FIRE_3 0x20
#define CV_LEFT 0x08
#define CV_DOWN 0x04
#define CV_RIGHT 0x02
#define CV_UP 0x01
#endif
#ifdef CV_SMS
#define CV_UP 0x01
#define CV_DOWN 0x02
#define CV_LEFT 0x04
#define CV_RIGHT 0x08
#define CV_FIRE_0 0x10
#define CV_FIRE_1 0x20
#endif
#ifdef CV_MSX
#define CV_UP 0x01
#define CV_DOWN 0x02
#define CV_LEFT 0x04
#define CV_RIGHT 0x08
#define CV_FIRE_0 0x10
#define CV_FIRE_1 0x20
#endif
struct cv_controller_state
{
uint8_t keypad; // Keypad: 0 - 9 as on keypad, * as 0xa, # as 0xb, 0xf for no key pressed or error.
uint8_t joystick;// Joystick: lowest 4 bit for joystick, higher 4 bit for fire buttons.
};
// Get keypad and joystick values.
void cv_get_controller_state(struct cv_controller_state *state, uint_fast8_t controller);
#define CV_SPIN_ACTIVE 0x10
#define CV_SPIN_RIGHT 0x20
// Set the handler for the spinner interrupt.
// This handler will be called when the wheel on the super action controller or the ball in the roller controller spin.
// The parameters passed to the handler correspond to the two super action controllers or
// the two axis in the roller controller. They can be anded with the above masks to test if they spinned, and which direction.
void cv_set_spint_handler(void (* handler)(uint_fast8_t, uint_fast8_t));
#endif

View File

@ -0,0 +1,43 @@
#ifndef CV_SOUND_H
#define CV_SOUND_H 1
#include <stdint.h>
#include <stdbool.h>
enum cv_soundchannel {
CV_SOUNDCHANNEL_0 = 0x0,
CV_SOUNDCHANNEL_1 = 0x2,
CV_SOUNDCHANNEL_2 = 0x4,
CV_SOUNDCHANNEL_NOISE = 0x6
};
enum cv_shift {
CV_NOISE_SHIFT_512 = 0,
CV_NOISE_SHIFT_1024 = 1,
CV_NOISE_SHIFT_2048 = 2,
CV_NOISE_SHIFT_CHAN2 = 3
};
/*
Set attenuation for given sound channel in dezibel. Maximum attenuation is 28 db,
granularity is 2 db.
*/
extern void cv_set_attenuation(enum cv_soundchannel channel, uint8_t dezibel);
/*
Set frequency of a tone generator. The frequency is 3.579/frequency_divider Mhz.
This function is not reentrant. While it is called neither cv_set_attenuation() nor
cv_set_noise() may be called. n should be a multiple of 32. The valid range is [0, 32736].
*/
extern void cv_set_frequency(enum cv_soundchannel channel, uint16_t frequency_divider);
extern void cv_set_noise(bool white, enum cv_shift shift);
#ifdef CV_MSX
static volatile __sfr __at 0xa0 psg_port_register;
static volatile __sfr __at 0xa1 psg_port_write;
static volatile __sfr __at 0xa2 psg_port_read;
#endif
#endif

View File

@ -0,0 +1,19 @@
#ifndef __CV_SUPPORT_H
#define __CV_SUPPORT_H 1
#include <stdint.h>
#include "cv_graphics.h"
extern void cv_init(void); // Initialize Colecovision library.
extern void cv_vdpout(const uint8_t reg, const uint8_t data) __preserves_regs(d, e, iyl, iyh); // Write data to VDP control register reg.
#ifndef CV_MSX
extern void cv_enable_nmi(void);
extern void cv_disable_nmi(void);
#endif
#endif

View File

@ -0,0 +1,32 @@
// (c) 2013 Philipp Klaus Krause
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, 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
// Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#ifndef CVU_H
#define CVU_H 1
#define CVU_LIBVERSION_MAJOR 0
#define CVU_LIBVERSION_MINOR 17
#define CVU_LIBVERSION_STRING "0.17"
#include "cvu_input.h"
#include "cvu_graphics.h"
#include "cvu_sound.h"
#include "cvu_compression.h"
#include "cvu_f.h"
#include "cvu_c.h"
#endif

View File

@ -0,0 +1,37 @@
#ifndef CVU_C_H
#define CVU_C_H 1
#include "cvu_f.h"
// Complex fixed-point type
struct cvu_c
{
cvu_f r;
cvu_f i;
};
// Addition
//extern void cadd(struct c *l, const struct c *r);
#define cvu_cadd(x, y) {(x)->r += (y)->r; (x)->i += (y)->i;}
// Subtraction
//extern void csub(struct c *l, const struct c *r);
#define cvu_csub(x, y) {(x)->r -= (y)->r; (x)->i -= (y)->i;}
// Multiplication
extern void cvu_cmul(struct cvu_c *l, const struct cvu_c *r);
// Very inaccurate approximation
extern cvu_f cvu_cabs(const struct cvu_c *l);
// Dot product: Returns l.r^2 + l.i^2
extern cvu_f cvu_cdot(const struct cvu_c *l);
// Multiplication by fixed-point number.
extern void cvu_cfmul(struct cvu_c *l, cvu_f r);
// Convert from polar to coordinate representation
extern void cvu_c_from_polar(struct cvu_c *c, cvu_f phi, cvu_f d);
#endif

View File

@ -0,0 +1,93 @@
// These decompression routines are rather complicated to allow customization.
// If you only want to decompress some data into graphics memory, you can use
// the functions at the end of this file instead.
#ifndef CVU_COMPRESSION_H
#define CVU_COMPRESSION_H 1
#include <stdint.h>
#include "cvu_graphics.h"
// Huffman decompression
#undef CVU_HUFFMAN_ITERATIVE
#undef CVU_HUFFMAN_RECURSIVE
struct cvu_huffman_node // Changing this struct will affect asm implementation of cvu_get_huffman
{
uint8_t left; // Position of left node in tree or character.
uint8_t right; // Position of right node in tree or character.
};
struct cvu_huffman_state // Changing this struct will affect asm implementation of cvu_get_huffman, _read_from_array
{
uint8_t (*input)(void);
const struct cvu_huffman_node *nodes; // Array of nodes
uint8_t root; // Position of root node among nodes
uint8_t ls, bs, rs;
unsigned char bit; // Position of currently processed bit
uint8_t buffer; // Currently processed input byte
#ifdef CVU_HUFFMAN_RECURSIVE
uint8_t current; // Currently processed node
#endif
};
void cvu_init_huffman(struct cvu_huffman_state *restrict state, uint8_t (* input)(void), const struct cvu_huffman_node *restrict tree, uint8_t root, uint8_t ls, uint8_t bs, uint8_t rs);
uint8_t cvu_get_huffman(struct cvu_huffman_state *state);
// RLE decompression
struct cvu_rle_state // Changing this struct will affect asm implementation of cvu_get_rle, _read_from_array
{
uint8_t (*input)(void);
uint8_t escape;
uint8_t left;
uint8_t buffer;
};
void cvu_init_rle(struct cvu_rle_state *restrict state, uint8_t (* input)(void), uint8_t escape);
uint8_t cvu_get_rle(struct cvu_rle_state *state);
// LZK decompression
struct cvu_lzk_state
{
uint8_t (*input)(void);
uint8_t escape;
uint8_t left;
uint8_t offset;
uint8_t start;
uint8_t buffer[64];
};
void cvu_init_lzk(struct cvu_lzk_state *restrict state, uint8_t (* input)(void), uint8_t escape);
uint8_t cvu_get_lzk(struct cvu_lzk_state *state);
// Decompression routines which will handle all the details for you.
// Just create a cvu_compression_state struct, initialize it and decompress.
struct cvu_compression_state // Changing this struct will affect asm implementation of _read_from_array
{
struct cvu_huffman_state huffman;
struct cvu_rle_state rle;
const uint8_t *data;
};
// Initilization:
// data: compressed data
// state: compression struct to initialize
// tree: huffman tree generated by huffman_analyzer
// root, ls, bs, rs: constants generated by huffman_analyzer
// escape: constant generated by rle_analyzer
void cvu_init_compression(const uint8_t *restrict data, struct cvu_compression_state *restrict state, const struct cvu_huffman_node *restrict tree, uint8_t root, uint8_t ls, uint8_t bs, uint8_t rs, uint8_t escape);
// The functions below can be mixed:
// This function will return a decompressed octet on each invocation.
uint8_t cvu_get_compression(struct cvu_compression_state *state);
// This function will decompress and write n octets to graphics memory at dest.
// It is not reentrant and may not be called why any function from cvu_graphics.h marked as such is called.
void cvu_memtovmemcpy_compression(cv_vmemp dest, struct cvu_compression_state *state, size_t n);
// This function will decompress and write n octets to memory at dest.
void *cvu_memcpy_compression(void *restrict dest, struct cvu_compression_state *state, size_t n);
#endif

View File

@ -0,0 +1,46 @@
// Fixed-point math can be useful where e.g. smooth movement is desired, but
// using float would make the application too slow and big.
// cvu_f is a 10.6 fixed point type. 10.6 has been chosen to ensure that the
// type can represent coordinates on the ColecoVision screen and in some
// "buffer" space surrounding it (to allow calculation of e.g. reflection).
#ifndef CVU_F_H
#define CVU_F_H 1
#include <stdint.h>
#include <limits.h>
typedef int16_t cvu_f; // 10.6 fixed-point type.
#define CVU_F_R 6
#define CVU_F_PI 201
#define CVU_F_PI_2 100
#define CVU_F_SQRT2 90
#define CVU_F_SQRT1_2 45
#define CVU_F_MIN INT16_MIN
#define CVU_F_MAX INT16_MAX
// Convert integer to fixed-point
#define CVU_F2I(l) ((l) >> CVU_F_R)
// Convert fixed-point to integer
#define CVU_I2F(l) ((l) << CVU_F_R)
// Fixed-point multiplication
extern cvu_f cvu_fmul2(cvu_f l, cvu_f r);
// Fixed-point division
extern cvu_f cvu_fdiv2(cvu_f l, cvu_f r);
// Fixed-point sine
extern cvu_f cvu_fsin(cvu_f x);
// Fixed-point cosine
extern cvu_f cvu_fcos(cvu_f x);
// Fixed-point arcus tangens of x / y.
extern cvu_f cvu_fatan2(cvu_f y, cvu_f x);
#endif

View File

@ -0,0 +1,122 @@
#ifndef CVU_GRAPHICS_H
#define CVU_GRAPHICS_H 1
#include <stdint.h>
#include "cv_graphics.h"
#ifdef CV_SMS
/*
Copy n bytes of data from RAM at src to CRAM at dest.
This function is not reentrant!
The speed of this function depends on the active video mode
and if the screen is active.
*/
extern void cvu_memtocmemcpy(cv_cmemp dest, const void * src, size_t n);
#endif
/*
Copy n bytes of data from RAM at src to VRAM at dest.
This function is not reentrant!
The speed of this function depends on the active video mode
and if the screen is active.
*/
extern void cvu_memtovmemcpy(cv_vmemp dest, const void * src, size_t n);
/*
Copy n bytes of data from VRAM at src to RAM at dest.
This function is not reentrant!
The speed of this function depends on the active video mode
and if the screen is active.
*/
extern void cvu_vmemtomemcpy(void *dest, cv_vmemp src, size_t n);
/*
Set n bytes of VRAM at dest to c.
This function is not reentrant!
The speed of this function depends on the active video mode
and if the screen is active.
*/
extern void cvu_vmemset(cv_vmemp dest, int c, size_t n);
/*
Write an octet to graphics memory at dest.
This function is not reentrant!
*/
extern void cvu_voutb(const uint8_t value, const cv_vmemp dest);
/*
Read an octet from graphics memory at src.
This function is not reentrant!
*/
extern uint8_t cvu_vinb(const cv_vmemp src);
struct cvu_sprite
{
uint8_t y;
uint8_t x;
uint8_t name;
uint8_t tag;
};
#ifdef CV_SMS
struct cvu_sprite4
{
uint8_t y;
uint8_t x;
uint8_t name;
};
#endif
// Write sprite to display memory. Use the location of the sprite table as base. number should be in [0, 31].
inline void cvu_set_sprite(const cv_vmemp base, uint_fast8_t number, const struct cvu_sprite *sprite)
{
cv_set_write_vram_address((base) + (number) * 0x4);
cv_memtovmemcpy_slow((sprite), 4);
}
// Write sprite to display memory (in mode 4). Use the location of the sprite table as base. number should be in [0, 63].
#ifdef CV_SMS
inline void cvu_set_sprite4(const cv_vmemp base, uint_fast8_t number, const struct cvu_sprite4 *sprite)
{
cvu_voutb(sprite->y, base + number);
cv_set_write_vram_address(base + 0x80 + number * 2);
cv_voutb(sprite->x);
cv_voutb(sprite->name);
}
#endif
// Todo: is cvu_get_sprite needed?
// Set the x coordinate of the sprite's upper left corner. x will be clamped to [-32, 255]
extern void cvu_set_sprite_x(struct cvu_sprite *sprite, int x) __preserves_regs(d, e);
extern int cvu_get_sprite_x(const struct cvu_sprite *sprite) __preserves_regs(b, c, d, e);
// Set the y coordinate of the sprite's upper left corner. y will be clamped to [-32, 207]
extern void cvu_set_sprite_y(struct cvu_sprite *sprite, int y) __preserves_regs(d, e);
extern int cvu_get_sprite_y(const struct cvu_sprite *sprite) __preserves_regs(d, e);
// Set them both at once.
extern void cvu_set_sprite_xy(struct cvu_sprite *sprite, int x, int y);
// Set the sprite's color.
inline void cvu_set_sprite_color(struct cvu_sprite *sprite, enum cv_color color)
{
sprite->tag = (sprite->tag & 0x80) | color;
}
extern enum cv_color cvu_get_sprite_color(struct cvu_sprite *sprite);
#endif

View File

@ -0,0 +1,15 @@
#ifndef CVU_INPUT_H
#define CVU_INPUT_H 1
#include <stdint.h>
#include "cv_input.h"
// For the super action controllers this gives the spinner movement (total relative movement since last call, negative for left, positive for right)
// For the roller controller this gives the ball movement (total relative as above).
// Using this function will set a libvu-specific spint handler, so it is incompatible with using a custom spint handler.
int_fast8_t cvu_get_spinner(uint_fast8_t controller);
#endif

View File

@ -0,0 +1,45 @@
#ifndef CVU_SOUND_H
#define CVU_SOUND 1
#include <stdint.h>
#include "cv_sound.h"
extern const uint16_t CVU_TUNING_ISO16_EQUAL[15]; // ISO 16 pitch (A at 440 Hz) with equal tuning.
extern const uint16_t CVU_TUNING_SCIENTIFIC_EQUAL[15]; // Scientific pitch (C at 256 Hz) with equal tuning.
extern const uint8_t CVU_VOLUME_DEFAULT[4];
extern const uint16_t CVU_EMPTY_MUSIC;
// channel holds the channel that will be used to play the music.
// volume is a pointer to an array of loudnesses in Dezibel for p, mp, mf, f.
// tuning is a pointer to an arrays of frequency dividers for the halftones of oktave 0.
// sixteenth_notes_per_second should explain itself.
// notes is a pointer to the music in the following format:
// Every note cosists of 16 bits. The most significant four mark the octave, the next 4
// the halftone (0xf means pause) the next 4 bits give the absolute length. The next 2
// give the relative length. the last 2 bits are the loudness.
// The rest of the structure's members are for internal use by cvu_play_music().
struct cvu_music
{
enum cv_soundchannel channel;
const uint8_t *volume;
const uint16_t *tuning;
uint8_t sixteenth_notes_per_second;
const uint16_t *notes;
uint16_t note_ticks_remaining;
uint16_t pause_ticks_remaining;
};
// This will initialize a cvu_music structure with default values for all
// members except notes.
extern void cvu_init_music(struct cvu_music *music);
// This function should be placed inside the vint handler or triggered by the vint handler.
// It will return false once it is finished playing the music.
extern bool cvu_play_music(struct cvu_music *restrict music);
#endif

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,3 @@
%.rel: %.s
sdasz80 -plosgff %<

View File

@ -0,0 +1,75 @@
1 ; crt0.s for Colecovision cart
2
3 .module crt0
4 .globl _main
5 .globl ___sdcc_call_hl
6
7 ; Ordering of segments for the linker - copied from sdcc crt0.s
8 .area _CODE
9 .area _INITIALIZER
10 .area _HOME
11 .area _GSINIT
12 .area _GSFINAL
13 .area _DATA
14 .area _INITIALIZED
15 .area _BSEG
16 .area _BSS
17 .area _HEAP
18
19 .area _CODE
20 ; MSX cartridge header @ 0x4000 - 0x400f
0000 41 42 21 .dw 0x4241
0002r10r00 22 .dw _Start
0004r10r00 23 .dw _Start
0006 00 00 24 .dw 0
0008 00 00 25 .dw 0
000A 00 00 26 .dw 0
000C 00 00 27 .dw 0
000E 00 00 28 .dw 0
29
0010 30 _Start:
0010 F3 [ 4] 31 di
0011 31 00 E0 [10] 32 ld sp, #0xe000 ; Set stack pointer directly above top of memory.
0014 ED 56 [ 8] 33 im 1
34
0016 CDr00r00 [17] 35 call gsinit ; Initialize global and static variables.
0019 CDr00r00 [17] 36 call _main
001C C7 [11] 37 rst 0x0 ; Restart when main() returns.
38
39 .area _GSINIT
0000 40 gsinit::
41
42 ; Implicitly zeroed global and static variables.
0000 01r00r00 [10] 43 ld bc, #l__DATA
0003 78 [ 4] 44 ld a, b
0004 B1 [ 4] 45 or a, c
0005 28 0F [12] 46 jr Z, zeroed_data
0007 21r00r00 [10] 47 ld hl, #s__DATA
000A 36 00 [10] 48 ld (hl), #0x00
000C 0B [ 6] 49 dec bc
000D 78 [ 4] 50 ld a, b
000E B1 [ 4] 51 or a, c
000F 28 05 [12] 52 jr Z, zeroed_data
0011 5D [ 4] 53 ld e, l
0012 54 [ 4] 54 ld d, h
0013 13 [ 6] 55 inc de
0014 ED B0 [21] 56 ldir
0016 57 zeroed_data:
58
59 ; Explicitly initialized global variables.
0016 01r00r00 [10] 60 ld bc, #l__INITIALIZER
0019 78 [ 4] 61 ld a, b
001A B1 [ 4] 62 or a, c
001B 28 08 [12] 63 jr Z, gsinit_static
001D 11r00r00 [10] 64 ld de, #s__INITIALIZED
0020 21r00r00 [10] 65 ld hl, #s__INITIALIZER
0023 ED B0 [21] 66 ldir
67
0025 68 gsinit_static:
69 ; Explicitly initialized static variables inserted by compiler here.
70
71 .area _GSFINAL
0000 C9 [10] 72 ret
73
74 .area _HOME
75

View File

@ -0,0 +1,46 @@
XL2
H A areas 9 global symbols
M crt0
S l__DATA Ref0000
S _main Ref0000
S s__DATA Ref0000
S .__.ABS. Def0000
S s__INITIALIZED Ref0000
S ___sdcc_call_hl Ref0000
S l__INITIALIZER Ref0000
S s__INITIALIZER Ref0000
A _CODE size 1D flags 0 addr 0
A _INITIALIZER size 0 flags 0 addr 0
A _HOME size 0 flags 0 addr 0
A _GSINIT size 25 flags 0 addr 0
S gsinit Def0000
A _GSFINAL size 1 flags 0 addr 0
A _DATA size 0 flags 0 addr 0
A _INITIALIZED size 0 flags 0 addr 0
A _BSEG size 0 flags 0 addr 0
A _BSS size 0 flags 0 addr 0
A _HEAP size 0 flags 0 addr 0
T 00 00 41 42 10 00 10 00 00 00 00 00 00 00 00 00
R 00 00 00 00 00 04 00 00 00 06 00 00
T 0E 00 00 00
R 00 00 00 00
T 10 00
R 00 00 00 00
T 10 00 F3 31 00 E0 ED 56 CD 00 00 CD 00 00 C7
R 00 00 00 00 00 09 03 00 02 0C 01 00
T 00 00
R 00 00 03 00
T 00 00 01 00 00 78 B1 28 0F 21 00 00 36 00 0B 78
R 00 00 03 00 02 03 00 00 02 0A 02 00
T 0E 00 B1 28 05 5D 54 13 ED B0
R 00 00 03 00
T 16 00
R 00 00 03 00
T 16 00 01 00 00 78 B1 28 08 11 00 00 21 00 00 ED
R 00 00 03 00 02 03 06 00 02 0A 04 00 02 0D 07 00
T 24 00 B0
R 00 00 03 00
T 25 00
R 00 00 03 00
T 00 00 C9
R 00 00 04 00

View File

@ -0,0 +1,75 @@
; crt0.s for Colecovision cart
.module crt0
.globl _main
.globl ___sdcc_call_hl
; Ordering of segments for the linker - copied from sdcc crt0.s
.area _CODE
.area _INITIALIZER
.area _HOME
.area _GSINIT
.area _GSFINAL
.area _DATA
.area _INITIALIZED
.area _BSEG
.area _BSS
.area _HEAP
.area _CODE
; MSX cartridge header @ 0x4000 - 0x400f
.dw 0x4241
.dw _Start
.dw _Start
.dw 0
.dw 0
.dw 0
.dw 0
.dw 0
_Start:
di
ld sp, #0xe000 ; Set stack pointer directly above top of memory.
im 1
call gsinit ; Initialize global and static variables.
call _main
rst 0x0 ; Restart when main() returns.
.area _GSINIT
gsinit::
; Implicitly zeroed global and static variables.
ld bc, #l__DATA
ld a, b
or a, c
jr Z, zeroed_data
ld hl, #s__DATA
ld (hl), #0x00
dec bc
ld a, b
or a, c
jr Z, zeroed_data
ld e, l
ld d, h
inc de
ldir
zeroed_data:
; Explicitly initialized global variables.
ld bc, #l__INITIALIZER
ld a, b
or a, c
jr Z, gsinit_static
ld de, #s__INITIALIZED
ld hl, #s__INITIALIZER
ldir
gsinit_static:
; Explicitly initialized static variables inserted by compiler here.
.area _GSFINAL
ret
.area _HOME

View File

@ -0,0 +1,27 @@
ASxxxx Assembler V02.00 + NoICE + SDCC mods (Zilog Z80 / Hitachi HD64180 / ZX-Next / eZ80), page 1.
Hexadecimal [16-Bits]
Symbol Table
.__.$$$.= 2710 L | .__.ABS.= 0000 G | .__.CPU.= 0000 L
.__.H$L.= 0000 L | 0 _Start 0010 R | ___sdcc_ **** GX
_main **** GX | 3 gsinit 0000 GR | 3 gsinit_s 0025 R
l__DATA **** GX | l__INITI **** GX | s__DATA **** GX
s__INITI **** GX | s__INITI **** GX | 3 zeroed_d 0016 R
ASxxxx Assembler V02.00 + NoICE + SDCC mods (Zilog Z80 / Hitachi HD64180 / ZX-Next / eZ80), page 2.
Hexadecimal [16-Bits]
Area Table
0 _CODE size 1D flags 0
1 _INITIAL size 0 flags 0
2 _HOME size 0 flags 0
3 _GSINIT size 25 flags 0
4 _GSFINAL size 1 flags 0
5 _DATA size 0 flags 0
6 _INITIAL size 0 flags 0
7 _BSEG size 0 flags 0
8 _BSS size 0 flags 0
9 _HEAP size 0 flags 0

View File

@ -36,13 +36,14 @@ extern void *cv_get_vint_handler(void);
// Get the vertical retrace frequency in Hz. 50 for PAL, 60 for NTSC.
unsigned char cv_get_vint_frequency(void);
#ifndef CV_SMS
#ifdef CV_CV
enum cv_machine {
CV_COLECOVISION = 0, // Coleco ColecoVision
//CV_ADAM = 1, // Coleco Adam - TODO
//CV_SUPERGAME = 2, // Coleco ColecoVision with super game module
};
#else
#endif
#ifdef CV_SMS
enum cv_machine {
CV_SG1000 = 0, // Sega SG-1000
CV_SC3000 = 1, // Sega SC-3000

View File

@ -12,6 +12,7 @@
*/
typedef uint16_t cv_vmemp; // 14-Bit video memory address type
#ifdef CV_SMS
typedef uint8_t cv_cmemp; // 5-bit color memory address type
#endif
@ -207,7 +208,11 @@ extern void cv_vmemset_slow(int c, size_t n) __preserves_regs(iyl, iyh);
extern void cv_vmemset_fast(int c, size_t n) __preserves_regs(iyl, iyh);
#ifdef CV_MSX
static volatile __sfr __at 0x98 cv_graphics_port;
#else
static volatile __sfr __at 0xbe cv_graphics_port;
#endif
inline void cv_voutb(const uint8_t value)
{

View File

@ -3,7 +3,7 @@
#include <stdint.h>
#ifndef CV_SMS
#ifdef CV_CV
#define CV_FIRE_0 0x40
#define CV_FIRE_1 0x80
@ -14,7 +14,20 @@
#define CV_RIGHT 0x02
#define CV_UP 0x01
#else
#endif
#ifdef CV_SMS
#define CV_UP 0x01
#define CV_DOWN 0x02
#define CV_LEFT 0x04
#define CV_RIGHT 0x08
#define CV_FIRE_0 0x10
#define CV_FIRE_1 0x20
#endif
#ifdef CV_MSX
#define CV_UP 0x01
#define CV_DOWN 0x02

View File

@ -34,4 +34,10 @@ extern void cv_set_frequency(enum cv_soundchannel channel, uint16_t frequency_di
extern void cv_set_noise(bool white, enum cv_shift shift);
#ifdef CV_MSX
static volatile __sfr __at 0xa0 psg_port_register;
static volatile __sfr __at 0xa1 psg_port_write;
static volatile __sfr __at 0xa2 psg_port_read;
#endif
#endif

View File

@ -9,9 +9,11 @@ extern void cv_init(void); // Initialize Colecovision library.
extern void cv_vdpout(const uint8_t reg, const uint8_t data) __preserves_regs(d, e, iyl, iyh); // Write data to VDP control register reg.
#ifndef CV_MSX
extern void cv_enable_nmi(void);
extern void cv_disable_nmi(void);
#endif
#endif

View File

@ -86,8 +86,7 @@ inline void cvu_set_sprite(const cv_vmemp base, uint_fast8_t number, const struc
// Write sprite to display memory (in mode 4). Use the location of the sprite table as base. number should be in [0, 63].
#ifdef CV_SMS
/* TODO: used to be inline, but sdcc barfs */
void cvu_set_sprite4(const cv_vmemp base, uint_fast8_t number, const struct cvu_sprite4 *sprite)
inline void cvu_set_sprite4(const cv_vmemp base, uint_fast8_t number, const struct cvu_sprite4 *sprite)
{
cvu_voutb(sprite->y, base + number);
cv_set_write_vram_address(base + 0x80 + number * 2);

View File

@ -171,13 +171,49 @@ var PLATFORM_PARAMS = {
data_start: 0x7000,
data_size: 0x400,
stack_end: 0x8000,
extra_preproc_args: ['-I', '/share/include/coleco'],
extra_preproc_args: ['-I', '/share/include/coleco', '-D', 'CV_CV'],
extra_link_args: ['-k', '/share/lib/coleco', '-l', 'libcv', '-l', 'libcvu', 'crt0.rel'],
extra_segments:[
{name:'BIOS',start:0x0,size:0x2000,type:'rom'},
{name:'Cartridge Header',start:0x8000,size:0x100,type:'rom'},
],
},
'msx': {
rom_start: 0x4000,
code_start: 0x4000,
rom_size: 0x8000,
data_start: 0xc000,
data_size: 0x3000,
stack_end: 0xffff,
extra_link_args: ['crt0-msx.rel'],
extra_link_files: ['crt0-msx.rel', 'crt0-msx.lst'],
extra_segments:[
{name:'BIOS',start:0x0,size:0x4000,type:'rom'},
//{name:'Cartridge',start:0x4000,size:0x4000,type:'rom'},
{name:'RAM',start:0xc000,size:0x3200,type:'ram'},
{name:'Stack',start:0xf000,size:0x300,type:'ram'},
{name:'BIOS Work RAM',start:0xf300,size:0xd00},
],
},
'msx-libcv': {
rom_start: 0x4000,
code_start: 0x4000,
rom_size: 0x8000,
data_start: 0xc000,
data_size: 0x3000,
stack_end: 0xffff,
extra_preproc_args: ['-I', '.', '-D', 'CV_MSX'],
extra_link_args: ['-k', '.', '-l', 'libcv-msx', '-l', 'libcvu-msx', 'crt0-msx.rel'],
extra_link_files: ['libcv-msx.lib', 'libcvu-msx.lib', 'crt0-msx.rel', 'crt0-msx.lst'],
extra_compile_files: ['cv.h','cv_graphics.h','cv_input.h','cv_sound.h','cv_support.h','cvu.h','cvu_c.h','cvu_compression.h','cvu_f.h','cvu_graphics.h','cvu_input.h','cvu_sound.h'],
extra_segments:[
{name:'BIOS',start:0x0,size:0x4000,type:'rom'},
//{name:'Cartridge',start:0x4000,size:0x4000,type:'rom'},
{name:'RAM',start:0xc000,size:0x3200,type:'ram'},
{name:'Stack',start:0xf000,size:0x300,type:'ram'},
{name:'BIOS Work RAM',start:0xf300,size:0xd00},
],
},
'sms-sg1000-libcv': {
rom_start: 0x0000,
code_start: 0x0100,