sms: added game gear

This commit is contained in:
Steven Hugg 2022-08-28 22:16:17 -05:00
parent 51b6f0025c
commit e4af92927d
8 changed files with 126 additions and 51 deletions

View File

@ -154,6 +154,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
<li><a class="dropdown-item" href="?platform=coleco">ColecoVision</a></li>
<li><a class="dropdown-item" href="?platform=sms-sg1000-libcv">Sega SG-1000</a></li>
<li><a class="dropdown-item" href="?platform=sms-sms-libcv">Sega Master System</a></li>
<li><a class="dropdown-item" href="?platform=sms-gg-libcv">Sega Game Gear</a></li>
<li><a class="dropdown-item" href="?platform=atari7800">Atari 7800</a></li>
<!--
<li><a class="dropdown-item" href="?platform=vectrex">Vectrex</a></li>
@ -323,11 +324,17 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
<span class="control-def"><span class="control-key small">\</span> Select</span>
<span class="control-def"><span class="control-key small">Enter</span> Start</span>
</div>
<div class="emucontrols-msx emucontrols-coleco emucontrols-sms text-center small control-insns" style="display:none">
<div class="emucontrols-msx emucontrols-coleco text-center small control-insns" style="display:none">
<span class="control-def"><span class="control-key">&#x2190;&#x2191;&#x2193;&#x2192;</span> Joypad</span>
<span class="control-def"><span class="control-key small">Space</span> Button A</span>
<span class="control-def"><span class="control-key small">Shift</span> Button B</span>
</div>
<div class="emucontrols-sms text-center small control-insns" style="display:none">
<span class="control-def"><span class="control-key">&#x2190;&#x2191;&#x2193;&#x2192;</span> Joypad</span>
<span class="control-def"><span class="control-key small">Space</span> Button A</span>
<span class="control-def"><span class="control-key small">Shift</span> Button B</span>
<span class="control-def"><span class="control-key small">Enter</span> Start</span>
</div>
<div class="emucontrols-vicdual emucontrols-galaxian emucontrols-vector text-center small control-insns" style="display:none">
<span class="control-def"><span class="control-key">&#x2190;&#x2191;&#x2193;&#x2192;</span> Joystick</span>
<span class="control-def"><span class="control-key small">Space</span> Button 1</span>

1
presets/sms-gg-libcv Symbolic link
View File

@ -0,0 +1 @@
sms-sms-libcv

View File

@ -72,21 +72,23 @@ void music_play(byte index) {
void music_stop() {
}
/*{pal:222,n:16}*/
const char PALETTE0[16] = {
0x30, 0x38, 0x3E, 0x3F,
0x30, 0x38, 0x3E, 0x3F,
0x30, 0x38, 0x3E, 0x3F,
0x30, 0x38, 0x3E, 0x3F,
#ifdef __PLATFORM_SMS_GG_LIBCV__
/*{pal:444,n:32}*/
const short PALETTE[32] = {
0xe00, 0xa60, 0xee3, 0xddd, 0xe00, 0xa60, 0xee3, 0xddd,
0xe00, 0xa60, 0xee3, 0xddd, 0xe00, 0xa60, 0xee3, 0xddd,
0xe00, 0x111, 0xddd, 0x43e, 0xaaaa, 0xcccc, 0xeeee, 0xffff,
0xe00, 0xa60, 0xee3, 0xddd, 0xe00, 0xa60, 0xee3, 0xddd,
};
/*{pal:222,n:16}*/
const char PALETTE1[16] = {
0x30, 0x00, 0x3F, 0x03,
0x30, 0x38, 0x3E, 0x3F,
0x30, 0x38, 0x3E, 0x3F,
0x30, 0x38, 0x3E, 0x3F,
#else
/*{pal:222,n:32}*/
const char PALETTE[32] = {
0x30, 0x38, 0x3E, 0x3F, 0x30, 0x38, 0x3E, 0x3F,
0x30, 0x38, 0x3E, 0x3F, 0x30, 0x38, 0x3E, 0x3F,
0x30, 0x00, 0x3F, 0x03, 0x30, 0x38, 0x3E, 0x3F,
0x30, 0x38, 0x3E, 0x3F, 0x30, 0x38, 0x3E, 0x3F
};
#endif
/// METASPRITES
@ -750,7 +752,7 @@ void pal_bright(byte level) {
byte or = PALBR_OR[level];
byte and = PALBR_AND[level];
for (i=0; i<16; i++) {
pal[i] = PALETTE0[i] & and | or;
pal[i] = PALETTE[i] & and | or;
}
cvu_memtocmemcpy(0xc000, pal, 16);
}
@ -799,8 +801,7 @@ void play_scene() {
void setup_graphics() {
cvu_memtovmemcpy(PATTERN, CHR_GENERIC, sizeof(CHR_GENERIC));
cvu_memtocmemcpy(0xc000, PALETTE0, 16);
cvu_memtocmemcpy(0xc010, PALETTE1, 16);
cvu_memtocmemcpy(0xc000, PALETTE, sizeof(PALETTE));
flip_sprite_patterns(PATTERN+0x80*32, CHR_GENERIC+0xd0*32, 0x30*32);
cv_set_left_column_blank(true);
}

View File

@ -21,17 +21,23 @@ extern uintptr_t font_bitmap_0[];
#define SPRITE_PATTERNS 0x3800 // 32*32 = 1024 bytes
#define SPRITES 0x3c00 // 4*32 = 128 bytes
/*{pal:222,n:16}*/
const char PALETTE0[16] = {
0x10, 0x03, 0x0B, 0x0F, 0x13, 0x17, 0x1B, 0x1F,
0x22, 0x28, 0x2A, 0x2E, 0x30, 0x37, 0x3B, 0x3F,
};
/*{pal:222,n:16}*/
const char PALETTE1[16] = {
#ifdef __PLATFORM_SMS_GG_LIBCV__
/*{pal:444,n:32}*/
const short PALETTE[32] = {
0x2221, 0x4441, 0x6661, 0x8888, 0xaaaa, 0xcccc, 0xeeee, 0xffff,
0x2222, 0x4444, 0x6666, 0x8888, 0xaaaa, 0xcccc, 0xeeee, 0xffff,
0x2222, 0x4444, 0x6666, 0x8888, 0xaaaa, 0xcccc, 0xeeee, 0xffff,
0x2222, 0x4444, 0x6666, 0x8888, 0xaaaa, 0xcccc, 0xeeee, 0xffff,
};
#else
/*{pal:222,n:32}*/
const char PALETTE[32] = {
0x10, 0x03, 0x0B, 0x0F, 0x13, 0x17, 0x1B, 0x1F,
0x22, 0x28, 0x2A, 0x2E, 0x30, 0x37, 0x3B, 0x3F,
0x10, 0x03, 0x0B, 0x0F, 0x13, 0x17, 0x1B, 0x1F,
0x22, 0x28, 0x2A, 0x2E, 0x30, 0x37, 0x3B, 0x3F,
};
#endif
/*{w:8,h:8,bpp:1,count:2,brev:1,np:4,pofs:1,sl:4}*/
const char PATTERNS[64] = {
@ -79,8 +85,7 @@ void setup_graphics() {
// copy sprites to pattern table VRAM
cvu_memtovmemcpy(PATTERN+32, PATTERNS, sizeof(PATTERNS));
// copy palettes to VRAM
cvu_memtocmemcpy(0xc000, PALETTE0, 16);
cvu_memtocmemcpy(0xc010, PALETTE1, 16);
cvu_memtocmemcpy(0xc000, PALETTE, sizeof(PALETTE));
}
// image table has two bytes per cell (name + attribute)

View File

@ -1013,3 +1013,30 @@ export class SMSVDP extends TMS9918A {
}
};
export class GameGearVDP extends SMSVDP {
cram = new Uint8Array(64); // color RAM
cram_latch = 0;
writeData(value: number) {
if (this.writeToCRAM) {
//console.log(hex(this.addressRegister), hex(value), hex(this.cram_latch));
if (this.addressRegister & 1) { // odd address?
let rgb4 = this.cram_latch + (value << 8);
let rgba = RGBA((rgb4&15)*17, ((rgb4>>4)&15)*17, ((rgb4>>8)&15)*17);
let palindex = this.addressRegister & (this.cram.length-1);
this.cram[palindex-1] = this.cram_latch;
this.cram[palindex] = value;
this.cpalette[palindex >> 1] = rgba;
this.prefetchByte = value;
this.addressRegister &= this.ramMask;
this.redrawRequired = true;
} else {
this.cram_latch = value; // even address
}
this.addressRegister++;
} else {
super.writeData(value);
}
this.latch = false;
}
}

View File

@ -1,11 +1,9 @@
import { Z80, Z80State } from "../common/cpu/ZilogZ80";
import { BasicScanlineMachine } from "../common/devices";
import { BaseZ80VDPBasedMachine } from "./vdp_z80";
import { KeyFlags, newAddressDecoder, padBytes, Keys, makeKeycodeMap, newKeyboardHandler } from "../common/emu";
import { hex, lzgmini, stringToByteArray } from "../common/util";
import { TssChannelAdapter, MasterAudio, SN76489_Audio } from "../common/audio";
import { TMS9918A, SMSVDP } from "../common/video/tms9918a";
import { newAddressDecoder, padBytes, Keys, makeKeycodeMap } from "../common/emu";
import { hex } from "../common/util";
import { MasterAudio, SN76489_Audio } from "../common/audio";
import { SMSVDP, GameGearVDP } from "../common/video/tms9918a";
// http://www.smspower.org/Development/Index
// http://www.smspower.org/uploads/Development/sg1000.txt
@ -28,6 +26,7 @@ var SG1000_KEYCODE_MAP = makeKeycodeMap([
[Keys.P2_A, 1, 0x4],
[Keys.P2_B, 1, 0x8],
[Keys.VK_BACK_SLASH, 1, 0x10], // reset
[Keys.VK_ENTER, 1, 0x80], // start/pause
]);
export class SG1000 extends BaseZ80VDPBasedMachine {
@ -61,33 +60,41 @@ export class SG1000 extends BaseZ80VDPBasedMachine {
setMemoryControl(v:number) { }
setIOPortControl(v:number) { }
readIO(addr:number) {
switch (addr & 0xc1) {
case 0x40: return this.getVCounter();
case 0x41: return this.getHCounter();
case 0x80: return this.vdp.readData();
case 0x81: return this.vdp.readStatus();
case 0xc0: return this.inputs[0] ^ 0xff;
case 0xc1: return this.inputs[1] ^ 0xff;
}
return 0;
}
writeIO(addr:number, val:number) {
switch (addr & 0xc1) {
case 0x00: return this.setMemoryControl(val);
case 0x01: return this.setIOPortControl(val);
case 0x40:
case 0x41: return this.psg.setData(val);
case 0x80: return this.vdp.writeData(val);
case 0x81: return this.vdp.writeAddress(val);
}
}
newIOBus() {
return {
read: (addr:number) => {
addr &= 0xff;
//console.log('IO read', hex(addr,4));
switch (addr & 0xc1) {
case 0x40: return this.getVCounter();
case 0x41: return this.getHCounter();
case 0x80: return this.vdp.readData();
case 0x81: return this.vdp.readStatus();
case 0xc0: return this.inputs[0] ^ 0xff;
case 0xc1: return this.inputs[1] ^ 0xff;
}
return 0;
return this.readIO(addr);
},
write: (addr:number, val:number) => {
addr &= 0xff;
val &= 0xff;
//console.log('IO write', hex(addr,4), hex(val,2));
switch (addr & 0xc1) {
case 0x00: return this.setMemoryControl(val);
case 0x01: return this.setIOPortControl(val);
case 0x40:
case 0x41: return this.psg.setData(val);
case 0x80: return this.vdp.writeData(val);
case 0x81: return this.vdp.writeAddress(val);
}
this.writeIO(addr, val);
}
};
}
@ -223,3 +230,17 @@ export class SMS extends SG1000 {
}
}
// https://segaretro.org/images/1/16/Sega_Game_Gear_Hardware_Reference_Manual.pdf
export class GameGear extends SMS {
newVDP(frameData, cru, flicker) {
return new GameGearVDP(frameData, cru, flicker);
}
readIO(addr:number) {
switch (addr & 0xc1) {
case 0x00: return (~this.inputs[1] & 0x80) | 0x40;
case 0xdc: return this.inputs[0] ^ 0xff;
case 0xdd: return this.inputs[1] ^ 0xff;
}
return super.readIO(addr);
}
}

View File

@ -1,5 +1,5 @@
import { SG1000, SMS } from "../machine/sms";
import { GameGear, SG1000, SMS } from "../machine/sms";
import { Platform, BaseZ80MachinePlatform } from "../common/baseplatform";
import { PLATFORMS } from "../common/emu";
@ -46,7 +46,17 @@ class SMSPlatform extends BaseZ80MachinePlatform<SMS> implements Platform {
readVRAMAddress(a) { return this.machine.readVRAMAddress(a); }
}
class GameGearPlatform extends BaseZ80MachinePlatform<GameGear> implements Platform {
newMachine() { return new GameGear(); }
getPresets() { return SMS_PRESETS; }
getDefaultExtension() { return ".c"; };
readAddress(a) { return this.machine.read(a); }
readVRAMAddress(a) { return this.machine.readVRAMAddress(a); }
}
///
PLATFORMS['sms-sg1000-libcv'] = SG1000Platform;
PLATFORMS['sms-sms-libcv'] = SMSPlatform;
PLATFORMS['sms-gg-libcv'] = GameGearPlatform;

View File

@ -388,6 +388,7 @@ var PLATFORM_PARAMS = {
};
PLATFORM_PARAMS['sms-sms-libcv'] = PLATFORM_PARAMS['sms-sg1000-libcv'];
PLATFORM_PARAMS['sms-gg-libcv'] = PLATFORM_PARAMS['sms-sms-libcv'];
var _t1;
export function starttime() { _t1 = new Date(); }
@ -1060,6 +1061,8 @@ export function preprocessMCPP(step:BuildStep, filesys:string) {
if (step.mainfile) {
args.unshift.apply(args, ["-D", "__MAIN__"]);
}
let platform_def = (platform.toUpperCase() as any).replaceAll(/[^a-zA-Z0-9]/g,'_');
args.unshift.apply(args, ["-D", `__PLATFORM_${platform_def}__`]);
if (params.extra_preproc_args) {
args.push.apply(args, params.extra_preproc_args);
}