You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
508 lines
17 KiB
508 lines
17 KiB
<html><head><script src="Chapter%202.2%20Reading%20a%20file%20from%20CD-ROM_files/analytics.js" type="text/javascript"></script>
|
|
<script type="text/javascript">window.addEventListener('DOMContentLoaded',function(){var v=archive_analytics.values;v.service='wb';v.server_name='wwwb-app226.us.archive.org';v.server_ms=523;archive_analytics.send_pageview({});});</script>
|
|
<script type="text/javascript" src="Chapter%202.2%20Reading%20a%20file%20from%20CD-ROM_files/bundle-playback.js" charset="utf-8"></script>
|
|
<script type="text/javascript" src="Chapter%202.2%20Reading%20a%20file%20from%20CD-ROM_files/wombat.js" charset="utf-8"></script>
|
|
<script type="text/javascript">
|
|
__wm.init("http://web.archive.org/web");
|
|
__wm.wombat("http://lameguy64.net/tutorials/pstutorials/chapter2-old/2-readfile.html","20220827033533","http://web.archive.org/","web","/_static/",
|
|
"1661571333");
|
|
</script>
|
|
<link rel="stylesheet" type="text/css" href="Chapter%202.2%20Reading%20a%20file%20from%20CD-ROM_files/banner-styles.css">
|
|
<link rel="stylesheet" type="text/css" href="Chapter%202.2%20Reading%20a%20file%20from%20CD-ROM_files/iconochive.css">
|
|
<!-- End Wayback Rewrite JS Include -->
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<link rel="stylesheet" type="text/css" href="Chapter%202.2%20Reading%20a%20file%20from%20CD-ROM_files/style.css">
|
|
<title>Chapter 2.2: Reading a file from CD-ROM</title>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
|
</head>
|
|
<body><!-- BEGIN WAYBACK TOOLBAR INSERT -->
|
|
<style type="text/css">
|
|
body {
|
|
margin-top:0 !important;
|
|
padding-top:0 !important;
|
|
/*min-width:800px !important;*/
|
|
}
|
|
</style>
|
|
<script>__wm.rw(0);</script>
|
|
<div id="wm-ipp-base" style="display: block; direction: ltr;" lang="en">
|
|
</div><div id="wm-ipp-print">The Wayback Machine -
|
|
http://web.archive.org/web/20220827033533/http://lameguy64.net/tutorials/pstutorials/chapter2-old/2-readfile.html</div>
|
|
<script type="text/javascript">//<![CDATA[
|
|
__wm.bt(675,27,25,2,"web","http://lameguy64.net/tutorials/pstutorials/chapter2-old/2-readfile.html","20220827033533",1996,"/_static/",["/_static/css/banner-styles.css?v=fantwOh2","/_static/css/iconochive.css?v=qtvMKcIJ"], false);
|
|
__wm.rw(1);
|
|
//]]></script>
|
|
<!-- END WAYBACK TOOLBAR INSERT -->
|
|
|
|
<header>
|
|
<h1>Chapter 2.2: Reading a file from CD-ROM</h1>
|
|
</header>
|
|
<p>This chapter details how to read a file from the CD-ROM, loading the contents
|
|
into system RAM using the CD-ROM library.</p>
|
|
<p><b>PSn00bSDK Compatible:</b> Yes</p>
|
|
|
|
<h2>Tutorial Index</h2>
|
|
<ul>
|
|
<li><a href="#cdinit">Initializing the CD-ROM</a></li>
|
|
<li><a href="#filelocate">Locating a file in the CD-ROM</a></li>
|
|
<li><a href="#reading">Reading File Contents</a></li>
|
|
<li><a href="#readfunc">Simple File Read Function</a></li>
|
|
<li><a href="#imagedemo">Image Loader Example</a></li>
|
|
<li><a href="#imagebuild">Building the ISO image</a></li>
|
|
<li><a href="#conclusion">Conclusion</a></li>
|
|
</ul>
|
|
|
|
<h2 id="cdinit">Initializing the CD-ROM</h2>
|
|
<p>Initializing the CD-ROM library is accomplished by simply calling
|
|
<b>CdInit()</b>. This function must be called after calling <b>ResetGraph()</b>
|
|
and before any CD library related function. If you intend to use the SPU you
|
|
must call <b>SpuInit()</b> immediately before calling <b>CdInit()</b>. Once the
|
|
CD-ROM library is initialized any other CD-ROM related function can be used.</p>
|
|
<h3>SDK Difference</h3>
|
|
<p>In PsyQ/Programmers' Tool, <b>CdInit()</b> will throw a lot of CD retry
|
|
messages when no disc is inserted and may lock up. In PSn00bSDK the function
|
|
carries on like normal when no disc is inserted.</p>
|
|
|
|
<h2 id="filelocate">Locating a file in the CD-ROM</h2>
|
|
<p>The CD-ROM library does not have a concept of file handles. Instead, files
|
|
are read by locating the start position of a file through the ISO9660 file
|
|
system, seeking to it and issuing a read operation until a set number of
|
|
sectors have been read. This method of loading files from disc should not be
|
|
a problem under any circumstances as files stored in a ISO9660 file system are
|
|
never fragmented. In fact, this method of reading files may have some
|
|
advantages.</p>
|
|
<p>Locating a file on the disc is done through the <b>CdSearchFile()</b>
|
|
function, which parses through the disc's file system to locate the file
|
|
and returns a <b>CdlFILE</b> which describes information about the file found
|
|
including it's position in the disc.</p>
|
|
<pre>CdlFILE file;
|
|
|
|
// Search for the file
|
|
if( !CdSearchFile( &file;, "\\MYDIR\\MYFILE.DAT;1" ) )
|
|
{
|
|
// Return value is NULL, file is not found
|
|
printf( "File not found.\n" );
|
|
return 0;
|
|
}
|
|
|
|
// When file found
|
|
printf( "File found!\n" );
|
|
</pre>
|
|
<p>The file name must be specified as a complete path from root and must use
|
|
backlash characters as directory separators (use \\ in C code). The file name
|
|
must also end with a file version number which is always ';1'. If the file is
|
|
found, it will return the pointer to the specified <b>CdlFILE</b> struct,
|
|
otherwise it would simply return NULL.</p>
|
|
<p>The <b>CdlFILE</b> struct contains a copy of the file name, file size and
|
|
most importantly, the location.</p>
|
|
|
|
<h2 id="reading">Reading File Contents</h2>
|
|
<p>Now for the interesting stuff. Reading sectors is accomplished by using
|
|
<b>CdRead()</b>. But before you start a read operation, you must first set
|
|
the location of where to start reading from. This can be done using
|
|
<b>CdControl()</b> and the <b>CdlSetloc</b> command. Use this to set the
|
|
target location of the file.</p>
|
|
<pre>char *buffer;
|
|
|
|
// Allocate a buffer for the file
|
|
buffer = (char*)malloc( 2048*((file.size+2047)/2048) );
|
|
|
|
// Set seek target (seek actually happens on CdRead())
|
|
CdControl( CdSetloc, &file.loc;, 0 );
|
|
|
|
// Read sectors
|
|
CdRead( (file.size+2047)/2048, (unsigned int*)buffer, CdlModeSpeed );
|
|
|
|
// Wait until read has completed
|
|
CdReadSync( 0, 0 );
|
|
</pre>
|
|
<p>You may have noticed by now that read sizes in this chapter are described in
|
|
sector units rather than byte units. That's because the CD-ROM subsystem can
|
|
only read in sector units and the CD-ROM library is optimized for reading in
|
|
sector units rather than buffering sectors to allow for byte by byte reading
|
|
for performance reasons.</p>
|
|
<p>Data sectors are typically 2048 bytes in size so buffers where data read
|
|
from the CD would be loaded to must be multiples of 2048 bytes. The arithmetic
|
|
to snap byte sizes to the nearest sector unit is described in the pseudo code
|
|
described above.</p>
|
|
<p>Once a read operation has been issued, you must wait until reading has
|
|
completed using <b>CdReadSync()</b>. You can alternatively poll the status
|
|
asynchronously by setting the <i>mode</i> parameter to 1 to perform animations
|
|
while waiting for a long read to complete.</p>
|
|
<p>If you intend to read only a part of a file instead of a whole file in a
|
|
single read operation, be aware that you can't simply call <b>CdRead()</b>
|
|
again to read the following sectors. Instead, you must retrieve the current
|
|
location using <b>CdlGetloc</b>, set it as the seek target with <b>CdlSetloc</b>
|
|
then call <b>CdRead()</b>.</p>
|
|
|
|
|
|
<h2 id="readfunc">Simple File Read Function</h2>
|
|
<p>The examples described above can be consolidated into a single function,
|
|
which can be useful for quickly implementing a file read function for testing
|
|
purposes:</p>
|
|
<pre>u_long *load_file(const char* filename)
|
|
{
|
|
CdlFILE file;
|
|
u_long *buffer;
|
|
|
|
|
|
printf( "Reading file %s... ", filename );
|
|
|
|
// Search for the file
|
|
if( !CdSearchFile( &file;, (char*)filename ) )
|
|
{
|
|
// Return value is NULL, file is not found
|
|
printf( "Not found!\n" );
|
|
return NULL;
|
|
}
|
|
|
|
// Allocate a buffer for the file
|
|
buffer = (u_long*)malloc( 2048*((file.size+2047)/2048) );
|
|
|
|
// Set seek target (seek actually happens on CdRead())
|
|
CdControl( CdlSetloc, (u_char*)&file.pos;, 0 );
|
|
|
|
// Read sectors
|
|
CdRead( (file.size+2047)/2048, buffer, CdlModeSpeed );
|
|
|
|
// Wait until read has completed
|
|
CdReadSync( 0, 0 );
|
|
|
|
printf( "Done.\n" );
|
|
|
|
return buffer;
|
|
}
|
|
</pre>
|
|
<p>If you want to do asynchronous loading to do background animations, you'll
|
|
have to use the CD functions more directly.</p>
|
|
|
|
|
|
<h2 id="imagedemo">Image Loader Example</h2>
|
|
<p>For completedness, this example demonstrates loading a high resolution
|
|
24-bit TIM from CD and displaying it into the framebuffer in 24-bit color mode.
|
|
Take any image file you wish to use, scale it down to 640x480 and convert it
|
|
into a 24-bit TIM with the load position set to (0,0). Name that TIM file
|
|
<i>myimage.tim</i> for this example.</p>
|
|
<p><b>PsyQ/Programmers' Tool Version</b></p>
|
|
<pre>#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <libgte.h>
|
|
#include <libgpu.h>
|
|
#include <libetc.h>
|
|
#include <libcd.h>
|
|
|
|
// Display environment struct
|
|
DISPENV disp;
|
|
|
|
u_long *load_file(const char* filename)
|
|
{
|
|
CdlFILE file;
|
|
u_long *buffer;
|
|
|
|
|
|
printf( "Reading file %s... ", filename );
|
|
|
|
// Search for the file
|
|
if( !CdSearchFile( &file;, (char*)filename ) )
|
|
{
|
|
// Return value is NULL, file is not found
|
|
printf( "Not found!\n" );
|
|
return NULL;
|
|
}
|
|
|
|
// Allocate a buffer for the file
|
|
buffer = (u_long*)malloc( 2048*((file.size+2047)/2048) );
|
|
|
|
// Set seek target (seek actually happens on CdRead())
|
|
CdControl( CdlSetloc, (u_char*)&file.pos;, 0 );
|
|
|
|
// Read sectors
|
|
CdRead( (file.size+2047)/2048, buffer, CdlModeSpeed );
|
|
|
|
// Wait until read has completed
|
|
CdReadSync( 0, 0 );
|
|
|
|
printf( "Done.\n" );
|
|
|
|
return buffer;
|
|
}
|
|
|
|
void display_picture()
|
|
{
|
|
u_long *image;
|
|
TIM_IMAGE tim;
|
|
|
|
// Load the image file
|
|
if( !(image = load_file( "\\MYIMAGE.TIM;1" )) )
|
|
{
|
|
printf( "Could not load image file.\n " );
|
|
return;
|
|
}
|
|
|
|
// Read TIM header
|
|
OpenTIM( image );
|
|
ReadTIM( &tim; );
|
|
|
|
// Load image to VRAM
|
|
LoadImage( tim.prect, tim.paddr );
|
|
DrawSync( 0 );
|
|
|
|
// Enable video display
|
|
VSync( 0 );
|
|
SetDispMask( 1 );
|
|
}
|
|
|
|
void init()
|
|
{
|
|
// Reset GPU (also installs IRQ handlers which are mandatory)
|
|
ResetGraph(0);
|
|
|
|
// Init CD-ROM library
|
|
CdInit();
|
|
|
|
// Set DISPENV for 640x480 24-bit color mode
|
|
SetDefDispEnv( &disp;, 0, 0, 640, 480 );
|
|
disp.isrgb24 = 1; // Enables 24-bit (cannot be used for GPU graphics)
|
|
disp.isinter = 1; // Enable interlace so hi-res will display properly
|
|
|
|
// Set display environment
|
|
PutDispEnv( &disp; );
|
|
}
|
|
|
|
int main(int argc, const char *argv[])
|
|
{
|
|
// Init stuff
|
|
init();
|
|
|
|
// Load and display picture
|
|
display_picture();
|
|
|
|
// Loop for safe idling
|
|
while( 1 )
|
|
{
|
|
VSync( 0 );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
</pre>
|
|
|
|
<p><b>PSn00bSDK Version</b></p>
|
|
<pre>#include <stdio.h>
|
|
#include <malloc.h>
|
|
#include <psxgpu.h>
|
|
#include <psxcd.h>
|
|
|
|
// Display environment struct
|
|
DISPENV disp;
|
|
|
|
|
|
unsigned int *load_file(const char* filename)
|
|
{
|
|
CdlFILE file;
|
|
unsigned int *buffer;
|
|
|
|
|
|
printf( "Reading file %s... ", filename );
|
|
|
|
// Search for the file
|
|
if( !CdSearchFile( &file;, (char*)filename ) )
|
|
{
|
|
// Return value is NULL, file is not found
|
|
printf( "Not found!\n" );
|
|
return NULL;
|
|
}
|
|
|
|
// Allocate a buffer for the file
|
|
buffer = (unsigned int*)malloc( 2048*((file.size+2047)/2048) );
|
|
|
|
// Set seek target (seek actually happens on CdRead())
|
|
CdControl( CdlSetloc, (unsigned char*)&file.pos;, 0 );
|
|
|
|
// Read sectors
|
|
CdRead( (file.size+2047)/2048, buffer, CdlModeSpeed );
|
|
|
|
// Wait until read has completed
|
|
CdReadSync( 0, 0 );
|
|
|
|
printf( "Done.\n" );
|
|
|
|
return buffer;
|
|
}
|
|
|
|
void display_picture()
|
|
{
|
|
unsigned int *image;
|
|
TIM_IMAGE tim;
|
|
|
|
// Load the image file
|
|
if( !(image = load_file( "\\MYIMAGE.TIM;1" )) )
|
|
{
|
|
printf( "Could not load image file.\n " );
|
|
return;
|
|
}
|
|
|
|
// Read TIM header
|
|
GetTimInfo( image, &tim; );
|
|
|
|
// Load image to VRAM
|
|
LoadImage( tim.prect, tim.paddr );
|
|
DrawSync( 0 );
|
|
|
|
// Enable video display
|
|
VSync( 0 );
|
|
SetDispMask( 1 );
|
|
}
|
|
|
|
void init()
|
|
{
|
|
// Reset GPU (also installs IRQ handlers which are mandatory)
|
|
ResetGraph(0);
|
|
|
|
// Init CD-ROM library
|
|
CdInit( 0 );
|
|
|
|
// Set DISPENV for 640x480 24-bit color mode
|
|
SetDefDispEnv( &disp;, 0, 0, 640, 480 );
|
|
disp.isrgb24 = 1; // Enables 24-bit (cannot be used for GPU graphics)
|
|
disp.isinter = 1; // Enable interlace so hi-res will display properly
|
|
|
|
// Set display environment
|
|
PutDispEnv( &disp; );
|
|
}
|
|
|
|
int main(int argc, const char *argv[])
|
|
{
|
|
// Init stuff
|
|
init();
|
|
|
|
// Load and display picture
|
|
display_picture();
|
|
|
|
// Loop for safe idling
|
|
while( 1 )
|
|
{
|
|
VSync( 0 );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
</pre>
|
|
<p>Most notable differences between the PsyQ/Programmers' Tool and PSn00bSDK
|
|
versions is the latter uses type <b>unsigned int</b> instead of <b>u_long</b>
|
|
or <b>unsigned long</b> and for good reason. Modern compilers such as GCC
|
|
7.4.0 tend to assume long to be a 64-bit integer and may cause problems when
|
|
using <b>unsigned long</b>. There's no <b>OpenTIM()</b> and <b>ReadTIM()</b>
|
|
equivalent. Instead, there's <b>GetTimInfo()</b> but this may change in the
|
|
future.</p>
|
|
<p>Make sure you've compiled the example as readfile.exe for coherency with
|
|
the rest of this chapter.</p>
|
|
|
|
<h2 id="imagebuild">Building the ISO image</h2>
|
|
<p>In the past, the only way to create proper ISO images for PS1 games is to
|
|
use a tool called BUILDCD included in leaked copies of the PsyQ SDK. The
|
|
biggest problem of using BUILDCD is it generates an image file of a special
|
|
format not supported by any burner program, so another tool has to be used
|
|
(stripiso) to convert the image file it generates into a usable ISO image.
|
|
Not only that, BUILDCD is a 16-bit DOS executable and is difficult and very
|
|
slow to use on a modern system.</p>
|
|
<p>Instead of using BUILDCD, use
|
|
<a href="http://web.archive.org/web/20220827033533/https://github.com/lameguy64/mkpsxiso">MKPSXISO</a> instead. It
|
|
offers about the same functionality as BUILDCD but better, and is built for
|
|
modern Windows and Linux platforms.</p>
|
|
<p><b>MKPSXISO Project XML</b></p>
|
|
<pre><?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
<!-- Defines the ISO project -->
|
|
<iso_project image_name="readfile.iso">
|
|
|
|
<!-- Defines the data track for this tutorial -->
|
|
<track type="data">
|
|
|
|
<!-- Specifies identifier strings such as volume label -->
|
|
<!-- System and application identifiers must be PLAYSTATION -->
|
|
<identifiers
|
|
system ="PLAYSTATION"
|
|
application ="PLAYSTATION"
|
|
volume ="PSXTUTORIAL"
|
|
volume_set ="PSXTUTORIAL"
|
|
publisher ="MEIDOTEK"
|
|
/>
|
|
|
|
<!-- Defines the directory tree of the data track -->
|
|
<directory_tree>
|
|
|
|
<!-- Specify files in the directory tree -->
|
|
<file name="system.cnf" type="data" source="system.cnf"/>
|
|
<file name="readfile.exe" type="data" source="readfile.exe"/>
|
|
<file name="myimage.tim" type="data" source="myimage.tim"/>
|
|
|
|
<!-- Place dummy sectors at the end -->
|
|
<dummy sectors="1024"/>
|
|
|
|
</directory_tree>
|
|
|
|
</track>
|
|
|
|
</iso_project>
|
|
</pre>
|
|
<p>While on the subject of ISO image creation, you'll also need to create a
|
|
special SYSTEM.CNF file in order to make your disc image bootable. A
|
|
SYSTEM.CNF file is simply a text file that specifies the file name of the
|
|
executable, stack address, number of task and event blocks. The latter three
|
|
wouldn't be discussed in this chapter and the typical values are generally
|
|
good enough.</p>
|
|
<p><b>SYSTEM.CNF Contents</b></p>
|
|
<pre>BOOT=cdrom:\readfile.exe;1
|
|
TCB=4
|
|
EVENT=10
|
|
STACK=801FFFF0
|
|
</pre>
|
|
<p>Once your MKPSXISO project and SYSTEM.CNF files are set, execute MKPSXISO
|
|
like so to create the ISO image:</p>
|
|
<pre>mkpsxiso readfile.xml
|
|
</pre>
|
|
<p>Run the ISO image in an emulator and you should see your 24-bit TIM image
|
|
displayed. It may take awhile for the image to appear as the 24-bit TIM image
|
|
is a pretty big file to load for the PS1.</p>
|
|
<p></p>
|
|
|
|
<h2 id="conclusion">Conclusion</h2>
|
|
<p>This chapter should cover about everything you need to know to load a file
|
|
from CD-ROM. The next chapter will cover common ways to optimize CD-ROM
|
|
accesses to speed up load times in your homebrew.</p>
|
|
|
|
<hr>
|
|
<table class="footer-table" width="100%">
|
|
<tbody><tr>
|
|
<td width="40%" align="left"><a href="http://web.archive.org/web/20220827033533/http://lameguy64.net/tutorials/pstutorials/chapter2-old/1-cdrom.html">Previous</a></td>
|
|
<td width="20%" align="center"><a href="http://web.archive.org/web/20220827033533/http://lameguy64.net/tutorials/pstutorials/index.html">Back to Index</a></td>
|
|
<td width="40%" align="right"><a href="http://web.archive.org/web/20220827033533/http://lameguy64.net/tutorials/pstutorials/chapter2-old/3-optimizing.html">Next</a></td>
|
|
</tr>
|
|
</tbody></table>
|
|
|
|
|
|
|
|
</body></html>
|
|
<!--
|
|
FILE ARCHIVED ON 03:35:33 Aug 27, 2022 AND RETRIEVED FROM THE
|
|
INTERNET ARCHIVE ON 15:40:55 Sep 05, 2022.
|
|
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
|
|
|
|
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
|
|
SECTION 108(a)(3)).
|
|
-->
|
|
<!--
|
|
playback timings (ms):
|
|
captures_list: 170.071
|
|
exclusion.robots: 0.17
|
|
exclusion.robots.policy: 0.163
|
|
RedisCDXSource: 0.884
|
|
esindex: 0.008
|
|
LoadShardBlock: 151.904 (3)
|
|
PetaboxLoader3.datanode: 200.102 (4)
|
|
CDXLines.iter: 14.739 (3)
|
|
load_resource: 348.367
|
|
PetaboxLoader3.resolve: 286.145
|
|
-->
|