nkeynes@1104 | 1 | /**
|
nkeynes@1104 | 2 | * $Id$
|
nkeynes@1104 | 3 | *
|
nkeynes@1104 | 4 | * mmio register code generator
|
nkeynes@1104 | 5 | *
|
nkeynes@1104 | 6 | * Copyright (c) 2010 Nathan Keynes.
|
nkeynes@1104 | 7 | *
|
nkeynes@1104 | 8 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@1104 | 9 | * it under the terms of the GNU General Public License as published by
|
nkeynes@1104 | 10 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@1104 | 11 | * (at your option) any later version.
|
nkeynes@1104 | 12 | *
|
nkeynes@1104 | 13 | * This program is distributed in the hope that it will be useful,
|
nkeynes@1104 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@1104 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@1104 | 16 | * GNU General Public License for more details.
|
nkeynes@1104 | 17 | */
|
nkeynes@1104 | 18 |
|
nkeynes@1104 | 19 | #include <stdio.h>
|
nkeynes@1104 | 20 | #include <stdlib.h>
|
nkeynes@1104 | 21 | #include <string.h>
|
nkeynes@1104 | 22 | #include <unistd.h>
|
nkeynes@1104 | 23 | #include <getopt.h>
|
nkeynes@1104 | 24 | #include <ctype.h>
|
nkeynes@1104 | 25 | #include <errno.h>
|
nkeynes@1104 | 26 | #include <glib/gstrfuncs.h>
|
nkeynes@1104 | 27 | #include <glib/glist.h>
|
nkeynes@1104 | 28 | #include "gettext.h"
|
nkeynes@1104 | 29 | #include "genmach.h"
|
nkeynes@1104 | 30 |
|
nkeynes@1104 | 31 | #define LXDREAM_PAGE_SIZE 4096
|
nkeynes@1104 | 32 |
|
nkeynes@1104 | 33 | const char *short_options = "cd:ho:v";
|
nkeynes@1104 | 34 | struct option long_options[] = {
|
nkeynes@1104 | 35 | { "output", required_argument, NULL, 'o' },
|
nkeynes@1104 | 36 | { "header", required_argument, NULL, 'd' },
|
nkeynes@1104 | 37 | { "check-only", no_argument, NULL, 'c' },
|
nkeynes@1104 | 38 | { "help", no_argument, NULL, 'h' },
|
nkeynes@1104 | 39 | { "verbose", no_argument, NULL, 'v' },
|
nkeynes@1104 | 40 | { NULL, 0, 0, 0 } };
|
nkeynes@1104 | 41 |
|
nkeynes@1104 | 42 | static void print_version()
|
nkeynes@1104 | 43 | {
|
nkeynes@1104 | 44 | printf( "genmmio 0.1\n" );
|
nkeynes@1104 | 45 | }
|
nkeynes@1104 | 46 |
|
nkeynes@1104 | 47 | static void print_usage()
|
nkeynes@1104 | 48 | {
|
nkeynes@1104 | 49 | print_version();
|
nkeynes@1104 | 50 | printf( "Usage: genmmio [options] <input-register-files>\n" );
|
nkeynes@1104 | 51 | printf( "Options:\n" );
|
nkeynes@1104 | 52 | printf( " -c, --check-only %s\n", _("Check specification files but don't write any output") );
|
nkeynes@1104 | 53 | printf( " -d, --header=FILE %s\n", _("Specify header output file [corresponding .h for .c file]") );
|
nkeynes@1104 | 54 | printf( " -h, --help %s\n", _("Display this usage information") );
|
nkeynes@1104 | 55 | printf( " -o, --output=FILE %s\n", _("Specify main output file [corresponding .c for input file]") );
|
nkeynes@1104 | 56 | printf( " -v, --verbose %s\n", _("Print verbose output") );
|
nkeynes@1104 | 57 | }
|
nkeynes@1104 | 58 |
|
nkeynes@1104 | 59 | /**
|
nkeynes@1104 | 60 | * Given an input baseName of the form "path/file.blah", return
|
nkeynes@1104 | 61 | * a newly allocated string "file<ext>" where <ext> is the second
|
nkeynes@1104 | 62 | * parameter.
|
nkeynes@1104 | 63 | *
|
nkeynes@1104 | 64 | * @param baseName a non-null filename
|
nkeynes@1104 | 65 | * @param ext a file extension including leading '.'
|
nkeynes@1104 | 66 | */
|
nkeynes@1104 | 67 | char *makeFilename( const char *baseName, const char *ext )
|
nkeynes@1104 | 68 | {
|
nkeynes@1104 | 69 | const char *p = strrchr(baseName, '/');
|
nkeynes@1104 | 70 | if( p == NULL )
|
nkeynes@1104 | 71 | p = baseName;
|
nkeynes@1104 | 72 | const char *q = strchr(p, '.');
|
nkeynes@1104 | 73 | if( q == NULL ) {
|
nkeynes@1104 | 74 | return g_strdup_printf("%s%s", p, ext);
|
nkeynes@1104 | 75 | } else {
|
nkeynes@1104 | 76 | return g_strdup_printf("%.*s%s", q-p, p, ext );
|
nkeynes@1104 | 77 | }
|
nkeynes@1104 | 78 | }
|
nkeynes@1104 | 79 |
|
nkeynes@1104 | 80 | /**
|
nkeynes@1104 | 81 | * Process all registers after parsing is complete. This does a few things:
|
nkeynes@1104 | 82 | * 1. Ensures that there are no overlapping registers, so that every operation
|
nkeynes@1104 | 83 | * is well-defined.
|
nkeynes@1104 | 84 | * 2. Replaces transitive mirror groups with a set of equivalent direct
|
nkeynes@1104 | 85 | * mirrors so that later processing doesn't need to check for this case.
|
nkeynes@1104 | 86 | * This also checks for cycles in the graph.
|
nkeynes@1104 | 87 | * 3. Organises the memory map(s) into page-size quantities (combining and
|
nkeynes@1104 | 88 | * splitting groups where necessary).
|
nkeynes@1104 | 89 | */
|
nkeynes@1104 | 90 | GList *postprocess_registers( GList *blocks )
|
nkeynes@1104 | 91 | {
|
nkeynes@1104 | 92 | for( GList *ptr = blocks; ptr != NULL; ptr = ptr->next ) {
|
nkeynes@1104 | 93 | regblock_t block = (regblock_t)ptr->data;
|
nkeynes@1104 | 94 | for( unsigned i=0; i<block->numRegs; i++ ) {
|
nkeynes@1104 | 95 | regdef_t reg = block->regs[i];
|
nkeynes@1104 | 96 | if( reg->mode == REG_MIRROR ) {
|
nkeynes@1104 | 97 | }
|
nkeynes@1104 | 98 | }
|
nkeynes@1104 | 99 | }
|
nkeynes@1104 | 100 | return blocks;
|
nkeynes@1104 | 101 | }
|
nkeynes@1104 | 102 |
|
nkeynes@1104 | 103 | /**
|
nkeynes@1104 | 104 | * Check register definition semantics. Primarily this verifies that there
|
nkeynes@1104 | 105 | * are no overlapping definitions.
|
nkeynes@1104 | 106 | * @return number of errors found.
|
nkeynes@1104 | 107 | */
|
nkeynes@1104 | 108 | int check_registers( GList *registers )
|
nkeynes@1104 | 109 | {
|
nkeynes@1104 | 110 | return 0;
|
nkeynes@1104 | 111 | }
|
nkeynes@1104 | 112 |
|
nkeynes@1104 | 113 | /**
|
nkeynes@1104 | 114 | * Dump the high-level register map to the given file.
|
nkeynes@1104 | 115 | */
|
nkeynes@1104 | 116 | void dump_register_blocks( FILE *f, GList *blocks, gboolean detail )
|
nkeynes@1104 | 117 | {
|
nkeynes@1104 | 118 | const char *mode_names[] = { "--", "RW", "RO", "RW" };
|
nkeynes@1104 | 119 | for( GList *ptr = blocks; ptr != NULL; ptr=ptr->next ) {
|
nkeynes@1104 | 120 | regblock_t block = (regblock_t)ptr->data;
|
nkeynes@1104 | 121 | fprintf( f, "%08X: %s - %s\n", block->address,
|
nkeynes@1104 | 122 | block->name,
|
nkeynes@1104 | 123 | (block->description == NULL ? "<no description>" : block->description) );
|
nkeynes@1104 | 124 | if( detail ) {
|
nkeynes@1104 | 125 | for( unsigned i=0; i<block->numRegs; i++ ) {
|
nkeynes@1104 | 126 | regdef_t reg = block->regs[i];
|
nkeynes@1104 | 127 | fprintf( f, " %04X: %s %s", reg->offset,
|
nkeynes@1104 | 128 | mode_names[reg->mode],
|
nkeynes@1104 | 129 | reg->name == NULL ? "<anon>" : reg->name );
|
nkeynes@1104 | 130 | if( reg->numElements > 1 ) {
|
nkeynes@1104 | 131 | fprintf( f, "[%d]", reg->numElements );
|
nkeynes@1104 | 132 | }
|
nkeynes@1104 | 133 | fprintf( f, " - %s\n",
|
nkeynes@1104 | 134 | (reg->description == NULL ? "<no description>" : reg->description) );
|
nkeynes@1104 | 135 | }
|
nkeynes@1104 | 136 | }
|
nkeynes@1104 | 137 | }
|
nkeynes@1104 | 138 | }
|
nkeynes@1104 | 139 |
|
nkeynes@1104 | 140 | char *build_page_initializer( regblock_t block )
|
nkeynes@1104 | 141 | {
|
nkeynes@1104 | 142 | char *page = g_malloc(LXDREAM_PAGE_SIZE);
|
nkeynes@1104 | 143 |
|
nkeynes@1104 | 144 | /* First, background fill if any */
|
nkeynes@1104 | 145 | if( block->flags.fillSizeBytes == 0 ) {
|
nkeynes@1104 | 146 | memset(page, 0, LXDREAM_PAGE_SIZE);
|
nkeynes@1104 | 147 | } else {
|
nkeynes@1104 | 148 | for( unsigned i=0; i<LXDREAM_PAGE_SIZE; i++ ) {
|
nkeynes@1104 | 149 | page[i] = block->flags.fillValue.a[i%block->flags.fillSizeBytes];
|
nkeynes@1104 | 150 | }
|
nkeynes@1104 | 151 | }
|
nkeynes@1104 | 152 |
|
nkeynes@1104 | 153 | /* Next, set register initializer (except for wo + mirror regs) */
|
nkeynes@1104 | 154 | for( unsigned i=0; i<block->numRegs; i++ ) {
|
nkeynes@1104 | 155 | regdef_t reg = block->regs[i];
|
nkeynes@1104 | 156 | if( reg->mode != REG_WO && reg->mode != REG_MIRROR ) {
|
nkeynes@1104 | 157 | unsigned offset = reg->offset;
|
nkeynes@1104 | 158 | for( unsigned j=0; j<reg->numElements; j++ ) {
|
nkeynes@1104 | 159 | if( reg->type == REG_STRING ) {
|
nkeynes@1104 | 160 | memcpy( &page[offset], reg->initValue.s, reg->numBytes );
|
nkeynes@1104 | 161 | } else {
|
nkeynes@1104 | 162 | memcpy( &page[offset], reg->initValue.a, reg->numBytes );
|
nkeynes@1104 | 163 | }
|
nkeynes@1104 | 164 | offset += reg->numBytes;
|
nkeynes@1104 | 165 | }
|
nkeynes@1104 | 166 | }
|
nkeynes@1104 | 167 | }
|
nkeynes@1104 | 168 |
|
nkeynes@1104 | 169 | /* Finally clone mirror groups */
|
nkeynes@1104 | 170 | for( unsigned i=0; i<block->numRegs; i++ ) {
|
nkeynes@1104 | 171 | regdef_t reg = block->regs[i];
|
nkeynes@1104 | 172 | if( reg->mode == REG_MIRROR ) {
|
nkeynes@1104 | 173 | unsigned offset = reg->offset;
|
nkeynes@1104 | 174 | unsigned target = reg->initValue.i;
|
nkeynes@1104 | 175 | for( unsigned i=0; i<reg->numElements; i++ ) {
|
nkeynes@1104 | 176 | memcpy( &page[offset], &page[target], reg->numBytes );
|
nkeynes@1104 | 177 | offset += reg->stride;
|
nkeynes@1104 | 178 | }
|
nkeynes@1104 | 179 | }
|
nkeynes@1104 | 180 | }
|
nkeynes@1104 | 181 |
|
nkeynes@1104 | 182 | return page;
|
nkeynes@1104 | 183 | }
|
nkeynes@1104 | 184 |
|
nkeynes@1104 | 185 |
|
nkeynes@1104 | 186 | void fwrite_dump( unsigned char *data, unsigned int length, FILE *f )
|
nkeynes@1104 | 187 | {
|
nkeynes@1104 | 188 | unsigned int i, j;
|
nkeynes@1104 | 189 | int skipped = 0;
|
nkeynes@1104 | 190 | for( i =0; i<length; i+=16 ) {
|
nkeynes@1104 | 191 | if( i >= 16 && i < length-16 && memcmp( &data[i], &data[i-16], 16) == 0 ) {
|
nkeynes@1104 | 192 | skipped++;
|
nkeynes@1104 | 193 | continue;
|
nkeynes@1104 | 194 | }
|
nkeynes@1104 | 195 | if( skipped ) {
|
nkeynes@1104 | 196 | fprintf( f, " ** \n" );
|
nkeynes@1104 | 197 | skipped = 0;
|
nkeynes@1104 | 198 | }
|
nkeynes@1104 | 199 | fprintf( f, "%08X:", i);
|
nkeynes@1104 | 200 | for( j=i; j<i+16; j++ ) {
|
nkeynes@1104 | 201 | if( j != i && (j % 4) == 0 )
|
nkeynes@1104 | 202 | fprintf( f, " " );
|
nkeynes@1104 | 203 | if( j < length )
|
nkeynes@1104 | 204 | fprintf( f, " %02X", (unsigned int)(data[j]) );
|
nkeynes@1104 | 205 | else
|
nkeynes@1104 | 206 | fprintf( f, " " );
|
nkeynes@1104 | 207 | }
|
nkeynes@1104 | 208 | fprintf( f, " " );
|
nkeynes@1104 | 209 | for( j=i; j<i+16 && j<length; j++ ) {
|
nkeynes@1104 | 210 | fprintf( f, "%c", isprint(data[j]) ? data[j] : '.' );
|
nkeynes@1104 | 211 | }
|
nkeynes@1104 | 212 | fprintf( f, "\n" );
|
nkeynes@1104 | 213 | }
|
nkeynes@1104 | 214 | }
|
nkeynes@1104 | 215 |
|
nkeynes@1104 | 216 | static const char *file_top = "/**\n"
|
nkeynes@1104 | 217 | " * This file was automatically generated by genmmio, do not edit\n"
|
nkeynes@1104 | 218 | " */\n";
|
nkeynes@1104 | 219 |
|
nkeynes@1104 | 220 | void write_source( FILE *f, GList *blocks, const char *header_filename )
|
nkeynes@1104 | 221 | {
|
nkeynes@1104 | 222 | fputs( file_top, f );
|
nkeynes@1104 | 223 | fprintf( f, "\n#include \"%s\"\n\n", header_filename );
|
nkeynes@1104 | 224 |
|
nkeynes@1104 | 225 | for( GList *ptr = blocks; ptr != NULL; ptr = ptr->next ) {
|
nkeynes@1104 | 226 | regblock_t block = (regblock_t)ptr->data;
|
nkeynes@1104 | 227 | /* Generate the mmio region struct */
|
nkeynes@1104 | 228 | fprintf( f, "void FASTCALL mmio_region_%s_write(uint32_t, uint32_t);\n", block->name );
|
nkeynes@1104 | 229 | fprintf( f, "void FASTCALL mmio_region_%s_write_word(uint32_t, uint32_t);\n", block->name );
|
nkeynes@1104 | 230 | fprintf( f, "void FASTCALL mmio_region_%s_write_byte(uint32_t, uint32_t);\n", block->name );
|
nkeynes@1104 | 231 | fprintf( f, "void FASTCALL mmio_region_%s_write_burst(uint32_t, unsigned char *);\n", block->name );
|
nkeynes@1104 | 232 | fprintf( f, "int32_t FASTCALL mmio_region_%s_read(uint32_t);\n", block->name );
|
nkeynes@1104 | 233 | fprintf( f, "int32_t FASTCALL mmio_region_%s_read_word(uint32_t);\n", block->name );
|
nkeynes@1104 | 234 | fprintf( f, "int32_t FASTCALL mmio_region_%s_read_byte(uint32_t);\n", block->name );
|
nkeynes@1104 | 235 | fprintf( f, "void FASTCALL mmio_region_%s_read_burst(unsigned char *, uint32_t);\n", block->name );
|
nkeynes@1104 | 236 | fprintf( f, "struct mmio_region mmio_region_%s = {\n", block->name );
|
nkeynes@1104 | 237 | fprintf( f, " \"%s\", \"%s\", %08x, {\n", block->name,
|
nkeynes@1104 | 238 | block->description == NULL ? block->name : block->description,
|
nkeynes@1104 | 239 | block->address );
|
nkeynes@1104 | 240 | fprintf( f, " mmio_region_%s_read, mmio_region_%s_write,\n", block->name, block->name );
|
nkeynes@1104 | 241 | fprintf( f, " mmio_region_%s_read_word, mmio_region_%s_write_word,\n", block->name, block->name );
|
nkeynes@1104 | 242 | fprintf( f, " mmio_region_%s_read_byte, mmio_region_%s_write_byte,\n", block->name, block->name );
|
nkeynes@1104 | 243 | fprintf( f, " mmio_region_%s_read_burst, mmio_region_%s_write_burst,\n", block->name, block->name );
|
nkeynes@1104 | 244 | fprintf( f, " unmapped_prefetch, mmio_region_%s_read_byte },\n", block->name, block->name );
|
nkeynes@1104 | 245 | fprintf( f, " NULL, NULL, {\n" );
|
nkeynes@1104 | 246 | for( unsigned i=0; i<block->numRegs; i++ ) {
|
nkeynes@1104 | 247 | regdef_t reg = block->regs[i];
|
nkeynes@1104 | 248 | if( reg->mode != REG_CONST ) {
|
nkeynes@1104 | 249 | char tmp[32];
|
nkeynes@1104 | 250 | const char *regname = reg->name;
|
nkeynes@1104 | 251 | if( regname == NULL ) {
|
nkeynes@1104 | 252 | regname = tmp;
|
nkeynes@1104 | 253 | snprintf( tmp, sizeof(tmp), "%s_%03X", block->name, reg->offset );
|
nkeynes@1104 | 254 | }
|
nkeynes@1104 | 255 |
|
nkeynes@1104 | 256 | fprintf( f, " { \"%s\", \"%s\", %d, 0x%03x, 0x%08x, %s },\n", regname,
|
nkeynes@1104 | 257 | reg->description == NULL ? regname : reg->description,
|
nkeynes@1104 | 258 | reg->numBytes*8, reg->offset, (unsigned)reg->initValue.i,
|
nkeynes@1104 | 259 | (reg->mode == REG_RW ? "PORT_MRW" : (reg->mode == REG_WO ? "PORT_W" : "PORT_R")) );
|
nkeynes@1104 | 260 | }
|
nkeynes@1104 | 261 | }
|
nkeynes@1104 | 262 | fprintf( f, " }, NULL };\n" );
|
nkeynes@1104 | 263 | }
|
nkeynes@1104 | 264 |
|
nkeynes@1104 | 265 | }
|
nkeynes@1104 | 266 |
|
nkeynes@1104 | 267 | void write_header( FILE *f, GList *blocks )
|
nkeynes@1104 | 268 | {
|
nkeynes@1104 | 269 | fputs( file_top, f );
|
nkeynes@1104 | 270 |
|
nkeynes@1104 | 271 | fputs( "\n#include \"mmio.h\"\n\n", f );
|
nkeynes@1104 | 272 |
|
nkeynes@1104 | 273 | for( GList *ptr = blocks; ptr != NULL; ptr = ptr->next ) {
|
nkeynes@1104 | 274 | regblock_t block = (regblock_t)ptr->data;
|
nkeynes@1104 | 275 | fprintf( f, "extern struct mmio_region mmio_region_%s;\n", block->name );
|
nkeynes@1104 | 276 | fprintf( f, "enum mmio_region_%s_port_t {\n", block->name );
|
nkeynes@1104 | 277 | for( unsigned i=0; i<block->numRegs; i++ ) {
|
nkeynes@1104 | 278 | regdef_t reg = block->regs[i];
|
nkeynes@1104 | 279 | if( reg->name != NULL ) {
|
nkeynes@1104 | 280 | fprintf( f, " %s = 0x%03x,\n", reg->name, reg->offset );
|
nkeynes@1104 | 281 | }
|
nkeynes@1104 | 282 | }
|
nkeynes@1104 | 283 | fprintf( f, "};\n" );
|
nkeynes@1104 | 284 | }
|
nkeynes@1104 | 285 | }
|
nkeynes@1104 | 286 |
|
nkeynes@1104 | 287 | void write_test( FILE *f, GList *blocks )
|
nkeynes@1104 | 288 | {
|
nkeynes@1104 | 289 |
|
nkeynes@1104 | 290 |
|
nkeynes@1104 | 291 | }
|
nkeynes@1104 | 292 |
|
nkeynes@1104 | 293 | int main(int argc, char *argv[])
|
nkeynes@1104 | 294 | {
|
nkeynes@1104 | 295 | const char *header = NULL;
|
nkeynes@1104 | 296 | const char *output = NULL;
|
nkeynes@1104 | 297 | gboolean check_only = FALSE;
|
nkeynes@1104 | 298 | int verbose = 0, opt;
|
nkeynes@1104 | 299 | GList *block_list = NULL;
|
nkeynes@1104 | 300 |
|
nkeynes@1104 | 301 | while( (opt = getopt_long( argc, argv, short_options, long_options, NULL )) != -1 ) {
|
nkeynes@1104 | 302 | switch(opt) {
|
nkeynes@1104 | 303 | case 'c':
|
nkeynes@1104 | 304 | check_only = TRUE;
|
nkeynes@1104 | 305 | break;
|
nkeynes@1104 | 306 | case 'd':
|
nkeynes@1104 | 307 | header = optarg;
|
nkeynes@1104 | 308 | break;
|
nkeynes@1104 | 309 | case 'h':
|
nkeynes@1104 | 310 | print_usage();
|
nkeynes@1104 | 311 | exit(0);
|
nkeynes@1104 | 312 | case 'o':
|
nkeynes@1104 | 313 | output = optarg;
|
nkeynes@1104 | 314 | break;
|
nkeynes@1104 | 315 | case 'v':
|
nkeynes@1104 | 316 | verbose++;
|
nkeynes@1104 | 317 | break;
|
nkeynes@1104 | 318 | }
|
nkeynes@1104 | 319 | }
|
nkeynes@1104 | 320 |
|
nkeynes@1104 | 321 | if( optind == argc ) {
|
nkeynes@1104 | 322 | print_usage();
|
nkeynes@1104 | 323 | exit(1);
|
nkeynes@1104 | 324 | }
|
nkeynes@1104 | 325 |
|
nkeynes@1104 | 326 | if( output == NULL ) {
|
nkeynes@1104 | 327 | output = makeFilename(argv[optind],".c");
|
nkeynes@1104 | 328 | }
|
nkeynes@1104 | 329 | if( header == NULL ) {
|
nkeynes@1104 | 330 | header = makeFilename(argv[optind],".h");
|
nkeynes@1104 | 331 | }
|
nkeynes@1104 | 332 |
|
nkeynes@1104 | 333 | for( ; optind < argc; optind++ ) {
|
nkeynes@1104 | 334 | block_list = ioparse(argv[optind], block_list);
|
nkeynes@1104 | 335 | }
|
nkeynes@1104 | 336 |
|
nkeynes@1104 | 337 | if( verbose ) {
|
nkeynes@1104 | 338 | dump_register_blocks(stdout, block_list, verbose>1);
|
nkeynes@1104 | 339 | }
|
nkeynes@1104 | 340 |
|
nkeynes@1104 | 341 | int errors = check_registers(block_list);
|
nkeynes@1104 | 342 | if( errors != 0 ) {
|
nkeynes@1104 | 343 | fprintf( stderr, "Aborting due to validation errors\n" );
|
nkeynes@1104 | 344 | return 2;
|
nkeynes@1104 | 345 | }
|
nkeynes@1104 | 346 |
|
nkeynes@1104 | 347 | if( !check_only ) {
|
nkeynes@1104 | 348 | FILE *f = fopen( output, "wo" );
|
nkeynes@1104 | 349 | if( f == NULL ) {
|
nkeynes@1104 | 350 | fprintf( stderr, "Unable to open output file '%s': %s\n", output, strerror(errno) );
|
nkeynes@1104 | 351 | return 3;
|
nkeynes@1104 | 352 | }
|
nkeynes@1104 | 353 | write_source( f, block_list, header );
|
nkeynes@1104 | 354 | fclose(f);
|
nkeynes@1104 | 355 |
|
nkeynes@1104 | 356 | f = fopen( header, "wo" );
|
nkeynes@1104 | 357 | if( f == NULL ) {
|
nkeynes@1104 | 358 | fprintf( stderr, "Unable to open header file '%s': %s\n", header, strerror(errno) );
|
nkeynes@1104 | 359 | return 4;
|
nkeynes@1104 | 360 | }
|
nkeynes@1104 | 361 | write_header( f, block_list );
|
nkeynes@1104 | 362 | fclose(f);
|
nkeynes@1104 | 363 | }
|
nkeynes@1104 | 364 |
|
nkeynes@1104 | 365 | for( GList *ptr = block_list; ptr != NULL; ptr = ptr->next ) {
|
nkeynes@1104 | 366 | char *data = build_page_initializer((regblock_t)ptr->data);
|
nkeynes@1104 | 367 | fwrite_dump( data, LXDREAM_PAGE_SIZE, stdout );
|
nkeynes@1104 | 368 | g_free(data);
|
nkeynes@1104 | 369 | }
|
nkeynes@1104 | 370 | return 0;
|
nkeynes@1104 | 371 | }
|
nkeynes@1104 | 372 |
|