filename | src/util.c |
changeset | 768:b2a54f6864eb |
prev | 736:a02d1475ccfd |
next | 1042:0fd066956482 |
author | nkeynes |
date | Mon Jan 26 07:26:24 2009 +0000 (15 years ago) |
permissions | -rw-r--r-- |
last change | Add read_byte_for_write mem function for correct implementation of AND.B and friends with TLB enabled. Add read_byte and read_long MMIO stubs to do correct sign extension of IO reads |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * Miscellaneous utility functions.
5 *
6 * Copyright (c) 2005 Nathan Keynes.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
19 #define HAVE_EXECINFO_H 1
21 #include <assert.h>
22 #include <ctype.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <signal.h>
27 #include <time.h>
28 #include <zlib.h>
29 #include <glib.h>
30 #include <png.h>
31 #include "dream.h"
32 #include "display.h"
33 #include "dreamcast.h"
34 #include "gui.h"
35 #include "sh4/sh4.h"
37 char *msg_levels[] = { "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" };
38 int global_msg_level = EMIT_WARN;
40 static void report_crash( int signo, siginfo_t *info, void *ptr )
41 {
42 char buf[128];
44 fprintf( stderr, "--- Aborting with signal %d ---\n", signo );
45 // Get gdb to print a nice backtrace for us
46 snprintf( buf, 128, "gdb -batch -f --quiet --pid=%d -ex bt", getpid() );
47 system(buf);
49 abort();
50 }
52 void install_crash_handler(void)
53 {
54 struct sigaction sa;
56 sa.sa_sigaction = report_crash;
57 sigemptyset(&sa.sa_mask);
58 sa.sa_flags = SA_RESETHAND|SA_SIGINFO;
59 sigaction( SIGSEGV, &sa, NULL );
60 }
63 void fwrite_string( const char *s, FILE *f )
64 {
65 uint32_t len = 0;
66 if( s == NULL ) {
67 fwrite( &len, sizeof(len), 1, f );
68 } else {
69 len = strlen(s)+1;
70 fwrite( &len, sizeof(len), 1, f );
71 fwrite( s, len, 1, f );
72 }
73 }
75 int fread_string( char *s, int maxlen, FILE *f )
76 {
77 uint32_t len;
78 fread( &len, sizeof(len), 1, f );
79 if( len != 0 ) {
80 fread( s, len > maxlen ? maxlen : len, 1, f );
81 }
82 return len;
83 }
85 void fwrite_gzip( void *p, size_t sz, size_t count, FILE *f )
86 {
87 uLongf size = sz*count;
88 uLongf csize = ((int)(size*1.001))+13;
89 unsigned char *tmp = g_malloc0( csize );
90 int status = compress( tmp, &csize, p, size );
91 assert( status == Z_OK );
92 uint32_t wsize = (uint32_t)csize;
93 fwrite( &wsize, sizeof(wsize), 1, f );
94 fwrite( tmp, csize, 1, f );
95 g_free(tmp);
96 }
98 int fread_gzip( void *p, size_t sz, size_t count, FILE *f )
99 {
100 uLongf size = sz*count;
101 uint32_t csize;
102 unsigned char *tmp;
104 fread( &csize, sizeof(csize), 1, f );
105 assert( csize <= (size*2) );
106 tmp = g_malloc0( csize );
107 fread( tmp, csize, 1, f );
108 int status = uncompress( p, &size, tmp, csize );
109 g_free(tmp);
110 if( status == Z_OK ) {
111 return count;
112 } else {
113 fprintf( stderr, "Error reading compressed data\n" );
114 return 0;
115 }
116 }
118 void fwrite_dump( unsigned char *data, unsigned int length, FILE *f )
119 {
120 unsigned int i, j;
121 for( i =0; i<length; i+=16 ) {
122 fprintf( f, "%08X:", i);
123 for( j=i; j<i+16; j++ ) {
124 if( (j % 4) == 0 )
125 fprintf( f, " " );
126 if( j < length )
127 fprintf( f, " %02X", (unsigned int)(data[j]) );
128 else
129 fprintf( f, " " );
130 }
131 fprintf( f, " " );
132 for( j=i; j<i+16 && j<length; j++ ) {
133 fprintf( f, "%c", isprint(data[j]) ? data[j] : '.' );
134 }
135 fprintf( f, "\n" );
136 }
137 }
139 void fwrite_dump32( unsigned int *data, unsigned int length, FILE *f )
140 {
141 fwrite_dump32v( data, length, 8, f );
142 }
144 void fwrite_dump32v( unsigned int *data, unsigned int length, int wordsPerLine, FILE *f )
145 {
146 unsigned int i, j;
147 for( i =0; i<length>>2; i+=wordsPerLine ) {
148 fprintf( f, "%08X:", i);
149 for( j=i; j<i+wordsPerLine; j++ ) {
150 if( j < length )
151 fprintf( f, " %08X", (unsigned int)(data[j]) );
152 else
153 fprintf( f, " " );
154 }
155 fprintf( f, "\n" );
156 }
157 }
159 gboolean write_png_to_stream( FILE *f, frame_buffer_t buffer )
160 {
161 int coltype, i;
162 png_bytep p;
163 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
164 if (!png_ptr) {
165 return FALSE;
166 }
168 png_infop info_ptr = png_create_info_struct(png_ptr);
169 if (!info_ptr) {
170 png_destroy_write_struct(&png_ptr, NULL);
171 return FALSE;
172 }
174 if( setjmp(png_jmpbuf(png_ptr)) ) {
175 png_destroy_write_struct(&png_ptr, &info_ptr);
176 return FALSE;
177 }
178 png_init_io( png_ptr, f );
179 switch( buffer->colour_format ) {
180 case COLFMT_BGR888:
181 coltype = PNG_COLOR_TYPE_RGB;
182 break;
183 case COLFMT_BGRA8888:
184 coltype = PNG_COLOR_TYPE_RGB_ALPHA;
185 break;
186 case COLFMT_BGR0888:
187 coltype = PNG_COLOR_TYPE_RGB;
188 break;
189 default:
190 coltype = PNG_COLOR_TYPE_RGB;
191 }
192 png_set_IHDR(png_ptr, info_ptr, buffer->width, buffer->height,
193 8, coltype, PNG_INTERLACE_NONE,
194 PNG_COMPRESSION_TYPE_DEFAULT,
195 PNG_FILTER_TYPE_DEFAULT );
196 png_write_info(png_ptr, info_ptr);
197 if( buffer->colour_format == COLFMT_BGR0888 ) {
198 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
199 }
200 png_set_bgr(png_ptr);
201 if( buffer->inverted ) {
202 p = (png_bytep)(buffer->data + (buffer->height*buffer->rowstride) - buffer->rowstride);
203 for(i=0; i<buffer->height; i++ ) {
204 png_write_row(png_ptr, p);
205 p-=buffer->rowstride;
206 }
207 } else {
208 p = (png_bytep)buffer->data;
209 for(i=0; i<buffer->height; i++ ) {
210 png_write_row(png_ptr, p);
211 p+=buffer->rowstride;
212 }
213 }
214 png_write_end(png_ptr, info_ptr);
215 png_destroy_write_struct(&png_ptr, &info_ptr);
216 return TRUE;
217 }
219 frame_buffer_t read_png_from_stream( FILE *f )
220 {
221 png_bytep p;
222 int i;
223 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
224 NULL, NULL, NULL);
225 if (!png_ptr) {
226 return NULL;
227 }
229 png_infop info_ptr = png_create_info_struct(png_ptr);
230 if (!info_ptr) {
231 png_destroy_read_struct(&png_ptr, NULL, NULL);
232 return NULL;
233 }
235 png_infop end_info = png_create_info_struct(png_ptr);
236 if (!end_info) {
237 png_destroy_read_struct(&png_ptr, &info_ptr, NULL );
238 return NULL;
239 }
241 if( setjmp(png_jmpbuf(png_ptr)) ) {
242 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
243 return NULL;
244 }
246 png_init_io(png_ptr, f);
247 png_read_info(png_ptr, info_ptr);
249 png_uint_32 width, height;
250 int bit_depth, color_type, interlace_type,
251 compression_type, filter_method;
252 png_get_IHDR(png_ptr, info_ptr, &width, &height,
253 &bit_depth, &color_type, &interlace_type,
254 &compression_type, &filter_method);
255 assert( interlace_type == PNG_INTERLACE_NONE );
256 int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
257 int channels = png_get_channels(png_ptr, info_ptr);
258 frame_buffer_t buffer = g_malloc( sizeof(struct frame_buffer) + rowbytes*height );
259 buffer->data = (unsigned char *)(buffer+1);
260 buffer->width = width;
261 buffer->height = height;
262 buffer->rowstride = rowbytes;
263 buffer->address = -1;
264 buffer->size = rowbytes*height;
265 buffer->inverted = FALSE;
266 if( channels == 4 ) {
267 buffer->colour_format = COLFMT_BGRA8888;
268 } else if( channels == 3 ) {
269 buffer->colour_format = COLFMT_RGB888;
270 }
272 p = (png_bytep)buffer->data;
273 for( i=0; i<height; i++ ) {
274 png_read_row(png_ptr, p, NULL );
275 p += rowbytes;
276 }
278 png_read_end(png_ptr, end_info);
279 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
280 return buffer;
281 }
283 int get_log_level_from_string( const gchar *str )
284 {
285 switch( tolower(str[0]) ) {
286 case 'd': return EMIT_DEBUG;
287 case 'e': return EMIT_ERR;
288 case 'f': return EMIT_FATAL;
289 case 'i': return EMIT_INFO;
290 case 't': return EMIT_TRACE;
291 case 'w': return EMIT_WARN;
292 default: return -1;
293 }
294 }
296 gboolean set_global_log_level( const gchar *str )
297 {
298 int l = get_log_level_from_string(str);
299 if( l == -1 ) {
300 return FALSE;
301 } else {
302 global_msg_level = l;
303 return TRUE;
304 }
305 }
307 void log_message( void *ptr, int level, const gchar *source, const char *msg, ... )
308 {
309 char buf[20];
310 time_t tm = time(NULL);
311 va_list ap;
313 if( level > global_msg_level ) {
314 return; // ignored
315 }
317 va_start(ap, msg);
318 gchar *text = g_strdup_vprintf( msg, ap );
319 va_end(ap);
321 if( level <= EMIT_ERR ) {
322 if( gui_error_dialog( text ) ) {
323 g_free(text);
324 // If we're running, halt on error to avoid potentially flooding
325 // the user with error messages.
326 if( dreamcast_is_running() ) {
327 dreamcast_stop();
328 }
329 return;
330 }
331 }
334 strftime( buf, sizeof(buf), "%H:%M:%S", localtime(&tm) );
335 fprintf( stderr, "%s %08X %-5s %s\n", buf, sh4r.pc, msg_levels[level], text );
336 g_free(text);
337 }
.