@@ -25,20 +25,22 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
2525
2626
2727static struct {
28- bool loaded ;
28+ bool attached ;
2929 bool autostart ;
30+ bool is_raw ;
3031 char * fn ;
3132 char name [0x21 ];
3233 Uint8 mem [0x10000 ];
33- int total_size ;
34- int sections ;
34+ unsigned int total_size ;
35+ unsigned int sections ;
36+ unsigned int min_addr , max_addr ;
3537} cart ;
3638
3739
3840void cart_init ( void )
3941{
4042 memset (cart .mem , 0xFF , sizeof cart .mem );
41- cart .loaded = false;
43+ cart .attached = false;
4244 cart .autostart = false;
4345 cart .name [0 ] = 0 ;
4446 cart .fn = NULL ;
@@ -50,32 +52,33 @@ Uint8 cart_read_byte ( unsigned int addr )
5052 Uint8 data = 0xFF ;
5153 if (addr < sizeof (cart .mem ))
5254 data = cart .mem [addr ];
53- //if (cart.loaded && addr != 0x3FFDF60) // see the comment about OPL at cart_write_byte()
55+ //if (cart.attached && addr != 0x3FFDF60) // see the comment about OPL at cart_write_byte()
5456 // DEBUGPRINT("CART: reading byte ($%02X) at $%X" NL, data, addr + 0x4000000);
5557 return data ;
5658}
5759
5860
5961void cart_write_byte ( unsigned int addr , Uint8 data )
6062{
61- if (!cart .loaded ) {
62- // a hack OPL to be able to work in the "slow device area" [if no cartridge is loaded]
63- static Uint8 opl_reg_sel = 0 ;
64- if (addr == 0x3FFDF40 ) {
65- opl_reg_sel = data ;
66- return ;
67- } else if (addr == 0x3FFDF50 ) {
68- audio65_opl3_write (opl_reg_sel , data );
69- return ;
70- }
63+ // FIXME: do we really care if cartridge is attached to handle OPL3?
64+ if (XEMU_UNLIKELY (!cart .attached ))
65+ return ;
66+ // a hack OPL to be able to work in the "slow device area" [if no cartridge is attached]
67+ static Uint8 opl_reg_sel = 0 ;
68+ if (addr == 0x3FFDF40 ) {
69+ opl_reg_sel = data ;
70+ return ;
71+ } else if (addr == 0x3FFDF50 ) {
72+ audio65_opl3_write (opl_reg_sel , data );
73+ return ;
7174 }
7275 //DEBUGPRINT("CART: writing byte ($%02X) at $%X" NL, data, addr + 0x4000000);
7376}
7477
7578
7679bool cart_is_attached ( void )
7780{
78- return cart .loaded ;
81+ return cart .attached ;
7982}
8083
8184
@@ -85,9 +88,9 @@ void cart_detach ( void )
8588 cart .autostart = false;
8689 free (cart .fn );
8790 cart .fn = NULL ;
88- if (cart .loaded ) {
91+ if (cart .attached ) {
8992 DEBUGPRINT ("CART: cartridge has been detached" NL );
90- cart .loaded = false;
93+ cart .attached = false;
9194 }
9295}
9396
@@ -107,100 +110,127 @@ int cart_attach ( const char *fn )
107110 static const char m65_bytestr [] = { 'M' , '6' , '5' };
108111 static const char mega65_bytestr [] = { 'M' , 'E' , 'G' , 'A' , '6' , '5' };
109112 static const char chip_bytestr [] = { 'C' , 'H' , 'I' , 'P' };
113+ static const char error_head [] = "Cannot attach cartridge" ;
110114 cart_detach ();
111115 if (!fn || !* fn )
112116 return -1 ;
113117 const int fd = xemu_open_file (fn , O_RDONLY , NULL , NULL );
114118 if (fd < 0 ) {
115- ERROR_WINDOW ("Cannot open cartridge file %s\nError: %s" , fn , strerror (errno ));
119+ ERROR_WINDOW ("%s\nCannot open file %s\nError: %s" , error_head , fn , strerror (errno ));
116120 return -1 ;
117121 }
118- cart .fn = xemu_realloc (cart .fn , strlen (fn ) + 1 );
119- strcpy (cart .fn , fn );
122+ xemu_restrdup (& cart .fn , fn );
120123 Uint8 buf [0x40 + 1 ];
121- if (xemu_safe_read (fd , buf , 0x40 ) != 0x40 )
124+ ssize_t rr = xemu_safe_read (fd , buf , 0x40 );
125+ if (rr != 0x40 )
122126 goto read_error ;
123127 if (!_check_cartridge_str (buf )) {
124128 // " CARTRIDGE" (with space) cannot be found in the first 0x10 bytes: not a VICE CRT format
125129 // let's check if it's a "raw ROM" with the "M65" mark
126130 if (memcmp (buf + 7 , m65_bytestr , sizeof m65_bytestr )) {
127- ERROR_WINDOW ("Not a CRT/raw file: %s" , fn ); // not that either -> error
131+ ERROR_WINDOW ("%s\nNot a CRT/raw file: %s" , error_head , fn ); // not that either -> error
128132 goto error ;
129133 }
130134 // Raw binary file, with "M65" mark: the best I can do is loading from $8000
131135 memcpy (cart .mem + 0x8000 , buf , 0x40 ); // copy what we have already
132- const int ret = xemu_safe_read (fd , cart .mem + 0x8000 + 0x40 , 0x10000 - 0x8000 - 0x40 ); // load the rest
133- if (ret < 0 )
136+ rr = xemu_safe_read (fd , cart .mem + 0x8000 + 0x40 , 0x10000 - 0x8000 - 0x40 ); // load the rest (but within memory limits, not above $FFFF)
137+ if (rr < 0 )
134138 goto read_error ;
135- cart .loaded = true;
139+ cart .name [0 ] = 0 ;
140+ cart .attached = true;
136141 cart .sections = 0 ;
137- cart .total_size = ret + 0x40 ;
142+ cart .total_size = (unsigned int )rr + 0x40 ;
143+ cart .min_addr = 0x8000 ;
144+ cart .max_addr = cart .min_addr + cart .total_size - 1 ;
138145 cart .autostart = true; // raw image is always auto start as I detected with 'M65' signature ...
139- DEBUGPRINT ("CART: raw cartridge ROM image \"%s\" has been loaded to $8000-$%X" NL , fn , 0x8000 + cart .total_size - 1 );
146+ cart .is_raw = true;
147+ DEBUGPRINT ("CART: raw cartridge ROM image \"%s\" has been attached at $8000-$%X" NL , fn , 0x8000 + cart .total_size - 1 );
140148 close (fd );
141149 return 1 ;
142150 }
143151 if (memcmp (buf , mega65_bytestr , sizeof mega65_bytestr )) {
144- ERROR_WINDOW ("Non -MEGA65 CRT file: %s" , fn );
152+ ERROR_WINDOW ("%s\nNon -MEGA65 CRT file: %s" , error_head , fn );
145153 goto error ;
146154 }
147155 // VICE-like CRT file (MEGA65-specific though)
148156 DEBUGPRINT ("CART: trying to attach VICE-like CRT file %s" NL , fn );
149157 buf [0x40 ] = 0 ;
150158 strcpy (cart .name , (const char * )buf + 0x20 );
159+ cart .is_raw = false;
151160 cart .sections = 0 ;
152161 cart .total_size = 0 ;
153- for (;;) {
154- const int ret = xemu_safe_read (fd , buf , 0x10 ); // read "CHIP" section header
155- if (!ret )
162+ cart .min_addr = 0xFFFFFFFFU ;
163+ cart .max_addr = 0 ;
164+ for (;;cart .sections ++ ) {
165+ rr = xemu_safe_read (fd , buf , 0x10 ); // read "CHIP" section header
166+ if (!rr ) {
167+ if (!cart .total_size ) {
168+ ERROR_WINDOW ("%s\nNo image data in the CRT file" , error_head );
169+ goto error ;
170+ }
156171 break ;
157- if (ret != 0x10 )
172+ }
173+ if (rr != 0x10 )
158174 goto read_error ;
159175 if (memcmp (buf , chip_bytestr , sizeof chip_bytestr )) {
160- ERROR_WINDOW ("Bad CRT file, missing CHIP section ID" );
176+ ERROR_WINDOW ("%s\nBad CRT file, missing/bad CHIP section ID" , error_head );
161177 goto error ;
162178 }
163179 const unsigned int size = (buf [0xE ] << 8 ) + buf [0xF ];
180+ if (!size ) {
181+ DEBUGPRINT ("CART: ... new CHIP section (#%d), skipping zero length image" , cart .sections );
182+ continue ;
183+ }
164184 const unsigned int addr = (buf [0xC ] << 8 ) + buf [0xD ];
165- DEBUGPRINT ("CART: ... new CHIP section (#%d), $%04X-$%04X (%u bytes)" NL , cart .sections , addr , addr + size - 1 , size );
166- if (size + addr > 0x10000 ) {
167- ERROR_WINDOW ("Bad CRT file, CHIP section overflows memory" );
185+ const unsigned int end_addr = addr + size - 1 ;
186+ DEBUGPRINT ("CART: ... new CHIP section (#%d), $%04X-$%04X (%u bytes)" NL , cart .sections , addr , end_addr , size );
187+ if (end_addr > 0xFFFFU ) {
188+ ERROR_WINDOW ("%s\nBad CRT file, CHIP section overflows memory: $%X-$%X" , error_head , addr , end_addr );
168189 goto error ;
169190 }
170- if (size ) {
171- if (xemu_safe_read (fd , cart .mem + addr , size ) != size )
172- goto read_error ;
173- }
174- cart .sections ++ ;
191+ if (addr < cart .min_addr )
192+ cart .min_addr = addr ;
193+ if (end_addr > cart .max_addr )
194+ cart .max_addr = end_addr ;
195+ rr = xemu_safe_read (fd , cart .mem + addr , size );
196+ if (rr != size )
197+ goto read_error ;
175198 cart .total_size += size ;
176199 }
177- if (!cart .sections ) {
178- ERROR_WINDOW ("No CHIP sections" );
179- goto error ;
180- }
181- cart .loaded = true;
200+ cart .attached = true;
182201 cart .autostart = !memcmp (cart .mem + 0x8007 , m65_bytestr , sizeof m65_bytestr );
183202 DEBUGPRINT ("CART: attached, autostart = %d, name = \"%s\"" NL , (int )cart .autostart , cart .name );
184203 close (fd );
185204 return (int )cart .autostart ;
186205read_error :
187- ERROR_WINDOW ("Cannot read (or truncated/ too small) cartridge file %s" , fn );
206+ ERROR_WINDOW ("%s\nCannot read %s\nError: %s" , error_head , fn , rr < 0 ? strerror ( errno ) : " truncated or too small file" );
188207error :
189208 cart_detach ();
190209 if (fd >= 0 )
191210 close (fd );
211+ DEBUGPRINT ("CART: attaching cartridge failed" NL );
192212 return -1 ;
193213}
194214
195215
196- void cart_info ( char * p , size_t size )
216+ const char * cart_get_fn ( void )
197217{
198- if (!cart .loaded ) {
199- snprintf (p , size , "No cartridge is attached" );
200- return ;
201- }
202- snprintf (p , size , "Filename: %s\nCartridge: %s\nAuto-start: %d\nSections: %d\nTotal binary size: %d\nFormat: %s" ,
203- cart .fn , cart .name , (int )cart .autostart , cart .sections , cart .total_size ,
204- cart .sections ? "CRT" : "RAW"
205- );
218+ return (cart .attached && cart .fn && cart .fn [0 ]) ? cart .fn : "<N/A>" ;
219+ }
220+
221+
222+ int cart_info ( char * p , size_t size )
223+ {
224+ if (cart .attached )
225+ return snprintf (p , size , "Status: attached\nFilename: %s\nCartridge name: %s\nAuto-start: %c\nSections: %d\nTotal binary size: %d\nFormat: %s\nMin...max: $%04X-$%04X" ,
226+ cart .fn ,
227+ cart .name [0 ] ? cart .name : "N/A" ,
228+ cart .autostart ? 'Y' : 'N' ,
229+ cart .sections ,
230+ cart .total_size ,
231+ cart .is_raw ? "RAW" : "CRT" ,
232+ cart .min_addr , cart .max_addr
233+ );
234+ else
235+ return snprintf (p , size , "Status: detached" );
206236}
0 commit comments