Snippets
Created by
ScorpionIlluminati
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | /*
* SEGA CD Mode 1 Player
* by Chilly Willy
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "hw_md.h"
#define WHITE_TEXT 0x0000
#define GREEN_TEXT 0x2000
#define RED_TEXT 0x4000
extern uint32_t vblank_vector;
extern uint32_t gen_lvl2;
extern uint32_t Sub_Start;
extern uint32_t Sub_End;
extern void Kos_Decomp(uint8_t *src, uint8_t *dst);
static char wait_cmd_ack(void)
{
char ack = 0;
while (!ack)
ack = read_byte(0xA1200F); // wait for acknowledge byte in sub comm port
return ack;
}
static void wait_do_cmd(char cmd)
{
while (read_byte(0xA1200F)) ; // wait until Sub-CPU is ready to receive command
write_byte(0xA1200E, cmd); // set main comm port to command
}
int main(void)
{
uint16_t buttons = 0, previous = 0, first_track = 0, last_track = 0, curr_track = 0;
uint8_t *bios;
char text[44];
clear_screen();
/*
* Check for CD BIOS
* When a cart is inserted in the MD, the CD hardware is mapped to
* 0x400000 instead of 0x000000. So the BIOS ROM is at 0x400000, the
* Program RAM bank is at 0x420000, and the Word RAM is at 0x600000.
*/
bios = (uint8_t *)0x415800;
if (memcmp(bios + 0x6D, "SEGA", 4))
{
bios = (uint8_t *)0x416000;
if (memcmp(bios + 0x6D, "SEGA", 4))
{
put_str("No CD detected!", RED_TEXT, 20-7, 12);
while (1) ;
}
}
sprintf(text, "CD Sub-CPU BIOS detected at 0x%6X", (uint32_t)bios);
put_str(text, GREEN_TEXT, 2, 2);
/*
* Reset the Sub-CPU, request the bus
*/
write_byte(0xA12001, 0x02);
while (!(read_byte(0xA12001) & 2)) write_byte(0xA12001, 0x02); // wait on bus acknowledge
/*
* Decompress Sub-CPU BIOS to Program RAM at 0x00000
*/
put_str("Decompressing Sub-CPU BIOS", GREEN_TEXT, 2, 3);
write_word(0xA12002, 0x0002); // no write-protection, bank 0, 2M mode, Word RAM assigned to Sub-CPU
Kos_Decomp(bios, (uint8_t *)0x420000);
/*
* Copy Sub-CPU program to Program RAM at 0x06000
*/
put_str("Copying Sub-CPU Program", GREEN_TEXT, 2, 4);
memcpy((void *)0x426000, &Sub_Start, (int)&Sub_End - (int)&Sub_Start);
if (memcmp((void *)0x426000, &Sub_Start, (int)&Sub_End - (int)&Sub_Start))
{
put_str("Failed writing Program RAM!", RED_TEXT, 20-13, 12);
while (1) ;
}
write_byte(0xA1200E, 0x00); // clear main comm port
write_byte(0xA12002, 0x2A); // write-protect up to 0x05400
write_byte(0xA12001, 0x01); // clear bus request, deassert reset - allow CD Sub-CPU to run
while (!(read_byte(0xA12001) & 1)) write_byte(0xA12001, 0x01); // wait on Sub-CPU running
put_str("Sub-CPU started", GREEN_TEXT, 2, 5);
/*
* Set the vertical blank handler to generate Sub-CPU level 2 ints.
* The Sub-CPU BIOS needs these in order to run.
*/
write_long((uint32_t)&vblank_vector, (uint32_t)&gen_lvl2);
set_sr(0x2000); // enable interrupts
/*
* Wait for Sub-CPU program to set sub comm port indicating it is running
*/
while (read_byte(0xA1200F) != 'I')
{
static int timeout = 0;
timeout++;
if (timeout > 20000)
{
put_str("CD failed to start!", RED_TEXT, 20-9, 12);
while (1) ;
}
}
/*
* Wait for Sub-CPU to indicate it is ready to receive commands
*/
while (read_byte(0xA1200F) != 0x00) ;
put_str("CD initialized and ready to go!", WHITE_TEXT, 20-15, 12);
delay(300);
clear_screen();
put_str("Mode 1 CD Player", WHITE_TEXT, 20-8, 2);
put_str("DPAD = Change Track START = Check Disc", WHITE_TEXT, 2, 23);
put_str("A = Play On B = Play Once C = Stop", WHITE_TEXT, 2, 24);
put_str("X = Trk Info Y = Play Repeat Z = Pause", WHITE_TEXT, 2, 25);
while (1)
{
char ack;
/*
* Get Disc Info
*/
wait_do_cmd('D'); // GetDiscInfo command
ack = wait_cmd_ack();
if (ack == 'D')
{
uint16_t bios_stat;
uint8_t first_tno, last_tno, drv_vers, flag;
// command done successfully
bios_stat = read_word(0xA12020);
first_tno = read_byte(0xA12022);
last_tno = read_byte(0xA12023);
drv_vers = read_byte(0xA12024);
flag = read_byte(0xA12025);
first_track = ((int)first_tno & 15) + (int)(first_tno >> 4) * 10;
last_track = ((int)last_tno & 15) + (int)(last_tno >> 4) * 10;
if (curr_track < first_track)
curr_track = first_track;
if (curr_track > last_track)
curr_track = last_track;
put_str("Status:", GREEN_TEXT, 2, 4);
switch (bios_stat >> 8)
{
case 0:
put_str("STOPPED ", WHITE_TEXT, 10, 4);
break;
case 1:
put_str("PLAYING ", WHITE_TEXT, 10, 4);
break;
case 3:
put_str("SCANNING ", WHITE_TEXT, 10, 4);
break;
case 5:
put_str("PAUSED ", WHITE_TEXT, 10, 4);
break;
case 8:
put_str("SEEKING ", WHITE_TEXT, 10, 4);
break;
case 16:
put_str("NO DISC ", WHITE_TEXT, 10, 4);
break;
case 32:
put_str("READING TOC ", WHITE_TEXT, 10, 4);
break;
case 64:
put_str("OPEN ", WHITE_TEXT, 10, 4);
break;
default:
if (bios_stat & 0x8000)
put_str("NOT READY ", WHITE_TEXT, 10, 4);
else
put_str("UNDEFINED ", WHITE_TEXT, 10, 4);
break;
}
sprintf(text, "%d", first_track);
put_str("First Track: ", GREEN_TEXT, 2, 6);
put_str(text, WHITE_TEXT, 15, 6);
sprintf(text, "%d", last_track);
put_str("Last Track: ", GREEN_TEXT, 2, 7);
put_str(text, WHITE_TEXT, 14, 7);
sprintf(text, "%d", curr_track);
put_str("Current Track: ", GREEN_TEXT, 2, 8);
put_str(text, WHITE_TEXT, 17, 8);
sprintf(text, "%s %s", (flag & 4) ? "DATA" : "CDDA", (flag & 2) ? "EMP" : "LIN");
put_str(text, WHITE_TEXT, 2, 10);
sprintf(text, "%d", drv_vers);
put_str("Drive Version: ", GREEN_TEXT, 2, 11);
put_str(text, WHITE_TEXT, 17, 11);
}
write_byte(0xA1200E, 0x00); // acknowledge receipt of command result
delay(2);
buttons = get_pad(0) & SEGA_CTRL_BUTTONS;
if (!(buttons ^ previous))
continue;
if (buttons & SEGA_CTRL_START)
{
/*
* Check Disc
*/
wait_do_cmd('C'); // CheckDisc command
ack = wait_cmd_ack();
write_byte(0xA1200E, 0x00); // acknowledge receipt of command result
}
if (buttons & SEGA_CTRL_A)
{
/*
* Play from Track to End
*/
write_word(0xA12010, curr_track);
write_byte(0xA12012, 0xFF); // play from track to end
wait_do_cmd('P'); // PlayTrack command
ack = wait_cmd_ack();
write_byte(0xA1200E, 0x00); // acknowledge receipt of command result
}
if (buttons & SEGA_CTRL_B)
{
/*
* Play Track Once
*/
write_word(0xA12010, curr_track);
write_byte(0xA12012, 0x00); // play track once
wait_do_cmd('P'); // PlayTrack command
ack = wait_cmd_ack();
write_byte(0xA1200E, 0x00); // acknowledge receipt of command result
}
if (buttons & SEGA_CTRL_C)
{
/*
* Stop Playback
*/
wait_do_cmd('S'); // StopPlaying command
ack = wait_cmd_ack();
write_byte(0xA1200E, 0x00); // acknowledge receipt of command result
}
if (buttons & SEGA_CTRL_X)
{
uint32_t time_tno;
uint8_t type;
/*
* Get Track Info
*/
write_word(0xA12010, curr_track);
wait_do_cmd('T'); // GetTrackInfo command
ack = wait_cmd_ack();
time_tno = read_long(0xA12020); // track time: MMSSFFTN
type = read_byte(0xA12024); // track type: 00 = CDDA, FF = DATA
write_byte(0xA1200E, 0x00); // acknowledge receipt of command result
sprintf(text, "%08X", time_tno);
put_str("Track Time: ", GREEN_TEXT, 2, 13);
put_str(text, WHITE_TEXT, 14, 13);
sprintf(text, "%s", type ? "DATA" : "CDDA");
put_str("Track Type: ", GREEN_TEXT, 2, 14);
put_str(text, WHITE_TEXT, 14, 14);
}
if (buttons & SEGA_CTRL_Y)
{
/*
* Play Track and Repeat
*/
write_word(0xA12010, curr_track);
write_byte(0xA12012, 0x01); // play track and repeat
wait_do_cmd('P'); // PlayTrack command
ack = wait_cmd_ack();
write_byte(0xA1200E, 0x00); // acknowledge receipt of command result
}
if (buttons & SEGA_CTRL_Z)
{
/*
* Pause/Resume
*/
wait_do_cmd('Z'); // PauseResume command
ack = wait_cmd_ack();
write_byte(0xA1200E, 0x00); // acknowledge receipt of command result
}
if (buttons & (SEGA_CTRL_DOWN|SEGA_CTRL_RIGHT))
{
curr_track++;
if (curr_track > last_track)
curr_track = first_track;
}
if (buttons & (SEGA_CTRL_UP|SEGA_CTRL_LEFT))
{
curr_track--;
if (curr_track < first_track)
curr_track = last_track;
}
previous = buttons;
}
/*
* Should never reach here due to while condition
*/
clear_screen ();
return 0;
}
|
Comments (0)
You can clone a snippet to your computer for local editing. Learn more.