Overlay work.
This commit is contained in:
parent
a5ef53c7b6
commit
9e95c1fab0
10 changed files with 583 additions and 52 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -15,6 +15,7 @@ software/
|
|||
*.sym
|
||||
*.o
|
||||
makemap
|
||||
**/.builddir
|
||||
|
||||
# Crap for CrossOver
|
||||
.windows-serial
|
||||
|
|
54
examples/overlay/CMakeLists.txt
Normal file
54
examples/overlay/CMakeLists.txt
Normal file
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
# Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
#
|
||||
|
||||
|
||||
# This is only to make my IDE happy.
|
||||
# We can't actually build with it until I get llvm-mos integrated into
|
||||
# toolchains. -- SCD
|
||||
|
||||
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
set(CMAKE_C_STANDARD 17)
|
||||
project(overlay)
|
||||
|
||||
set(DEFINES ${CMAKE_SOURCE_DIR}/../../include)
|
||||
set(F256LIB ${CMAKE_SOURCE_DIR}/../../f256lib)
|
||||
|
||||
set(OVERLAY_SOURCE
|
||||
${F256LIB}/f256.h
|
||||
${F256LIB}/f256.c
|
||||
overlay.c
|
||||
)
|
||||
|
||||
add_executable(${CMAKE_PROJECT_NAME}
|
||||
${OVERLAY_SOURCE}
|
||||
)
|
||||
|
||||
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${DEFINES}
|
||||
${F256LIB}
|
||||
)
|
||||
|
||||
#target_link_libraries(${CMAKE_PROJECT_NAME}
|
||||
# -lm
|
||||
#)
|
46
examples/overlay/build.sh
Executable file
46
examples/overlay/build.sh
Executable file
|
@ -0,0 +1,46 @@
|
|||
#!/bin/bash -ex
|
||||
|
||||
#
|
||||
# Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
#
|
||||
|
||||
|
||||
PROJECT=overlay
|
||||
|
||||
F256=$(pwd)/../..
|
||||
LLVM=${F256}/llvm-mos
|
||||
PATH=${LLVM}/bin:${PATH}
|
||||
|
||||
CLANG="mos-f256k-clang -I${F256}/include -I${F256}/f256lib -Os"
|
||||
|
||||
${CLANG} -c ${PROJECT}.c
|
||||
|
||||
${CLANG} -T f256.ld \
|
||||
-Wl,-Map=overlay.map \
|
||||
-o ${PROJECT} \
|
||||
${PROJECT}.o
|
||||
|
||||
mv ${PROJECT} ${PROJECT}.pgz
|
||||
|
||||
llvm-nm ${PROJECT}.elf > ${PROJECT}.sym
|
||||
llvm-objdump -d --print-imm-hex ${PROJECT}.elf > ${PROJECT}.lst
|
||||
hexdump -C ${PROJECT}.pgz > ${PROJECT}.hex
|
||||
python ${F256}/pgz-thunk.py ${PROJECT}.pgz
|
96
examples/overlay/f256.ld
Normal file
96
examples/overlay/f256.ld
Normal file
|
@ -0,0 +1,96 @@
|
|||
/* fake C Stack */
|
||||
PROVIDE(__stack = 0xA000);
|
||||
/* entry point to my program */
|
||||
PROVIDE(__f256_start = 0x300);
|
||||
/* page size of a block of memory */
|
||||
PROVIDE(__BLOCK_SIZE = 0x2000);
|
||||
/* swappable block address */
|
||||
PROVIDE(__SLOT_ADDR = 0xA000);
|
||||
|
||||
/* f256k uses first 16 bytes of ZP for mmu control? */
|
||||
__rc0 = 0x10;
|
||||
INCLUDE imag-regs.ld
|
||||
ASSERT(__rc0 == 0x10, "Inconsistent zero page map.")
|
||||
ASSERT(__rc31 == 0x2f, "Inconsistent zero page map.")
|
||||
|
||||
MEMORY {
|
||||
/* kernel uses 0xf0-0xff for parameter passing */
|
||||
zp : ORIGIN = __rc31 + 1, LENGTH = 0xF0 - (__rc31 + 1)
|
||||
ram (rw) : ORIGIN = __f256_start, LENGTH = 0xA000-__f256_start
|
||||
}
|
||||
|
||||
/* LMAs */
|
||||
__block8_lma = ( 8<<24)|__SLOT_ADDR;
|
||||
__block9_lma = ( 9<<24)|__SLOT_ADDR;
|
||||
__block10_lma = (10<<24)|__SLOT_ADDR;
|
||||
__block11_lma = (11<<24)|__SLOT_ADDR;
|
||||
__block12_lma = (12<<24)|__SLOT_ADDR;
|
||||
__block13_lma = (13<<24)|__SLOT_ADDR;
|
||||
__block14_lma = (14<<24)|__SLOT_ADDR;
|
||||
__block15_lma = (15<<24)|__SLOT_ADDR;
|
||||
__block16_lma = (16<<24)|__SLOT_ADDR;
|
||||
__block17_lma = (17<<24)|__SLOT_ADDR;
|
||||
__block18_lma = (18<<24)|__SLOT_ADDR;
|
||||
__block19_lma = (19<<24)|__SLOT_ADDR;
|
||||
__block20_lma = (20<<24)|__SLOT_ADDR;
|
||||
__block21_lma = (21<<24)|__SLOT_ADDR;
|
||||
__block22_lma = (22<<24)|__SLOT_ADDR;
|
||||
__block23_lma = (23<<24)|__SLOT_ADDR;
|
||||
|
||||
MEMORY {
|
||||
block8 : ORIGIN = __block8_lma, LENGTH = __BLOCK_SIZE
|
||||
block9 : ORIGIN = __block9_lma, LENGTH = __BLOCK_SIZE
|
||||
block10 : ORIGIN = __block10_lma, LENGTH = __BLOCK_SIZE
|
||||
block11 : ORIGIN = __block11_lma, LENGTH = __BLOCK_SIZE
|
||||
block12 : ORIGIN = __block12_lma, LENGTH = __BLOCK_SIZE
|
||||
block13 : ORIGIN = __block13_lma, LENGTH = __BLOCK_SIZE
|
||||
block14 : ORIGIN = __block14_lma, LENGTH = __BLOCK_SIZE
|
||||
block15 : ORIGIN = __block15_lma, LENGTH = __BLOCK_SIZE
|
||||
block16 : ORIGIN = __block16_lma, LENGTH = __BLOCK_SIZE
|
||||
block17 : ORIGIN = __block17_lma, LENGTH = __BLOCK_SIZE
|
||||
block18 : ORIGIN = __block18_lma, LENGTH = __BLOCK_SIZE
|
||||
block19 : ORIGIN = __block19_lma, LENGTH = __BLOCK_SIZE
|
||||
block20 : ORIGIN = __block20_lma, LENGTH = __BLOCK_SIZE
|
||||
block21 : ORIGIN = __block21_lma, LENGTH = __BLOCK_SIZE
|
||||
block22 : ORIGIN = __block22_lma, LENGTH = __BLOCK_SIZE
|
||||
block23 : ORIGIN = __block23_lma, LENGTH = __BLOCK_SIZE
|
||||
}
|
||||
|
||||
REGION_ALIAS("c_writeable", ram)
|
||||
REGION_ALIAS("c_readonly", ram)
|
||||
|
||||
SECTIONS {
|
||||
INCLUDE c.ld
|
||||
.block8 : { *(.block8 .block8.*) } >block8 end_block8 = .;
|
||||
.block9 : { *(.block9 .block9.*) } >block9 end_block9 = .;
|
||||
.block10 : { *(.block10 .block10.*) } >block10 end_block10 = .;
|
||||
.block11 : { *(.block11 .block11.*) } >block11 end_block11 = .;
|
||||
.block12 : { *(.block12 .block12.*) } >block12 end_block12 = .;
|
||||
.block13 : { *(.block13 .block13.*) } >block13 end_block13 = .;
|
||||
.block14 : { *(.block14 .block14.*) } >block14 end_block14 = .;
|
||||
.block15 : { *(.block15 .block15.*) } >block15 end_block15 = .;
|
||||
.block16 : { *(.block16 .block16.*) } >block16 end_block16 = .;
|
||||
.block17 : { *(.block17 .block17.*) } >block17 end_block17 = .;
|
||||
.block18 : { *(.block18 .block18.*) } >block18 end_block18 = .;
|
||||
.block19 : { *(.block19 .block19.*) } >block19 end_block19 = .;
|
||||
.block20 : { *(.block20 .block20.*) } >block20 end_block20 = .;
|
||||
.block21 : { *(.block21 .block21.*) } >block21 end_block21 = .;
|
||||
.block22 : { *(.block22 .block22.*) } >block22 end_block22 = .;
|
||||
.block23 : { *(.block23 .block23.*) } >block23 end_block23 = .;
|
||||
}
|
||||
|
||||
OUTPUT_FORMAT {
|
||||
BYTE(0x5A) /* pgZ */
|
||||
/* ram segment */
|
||||
SHORT(ORIGIN(ram)) /* where to load it, 24 bits */
|
||||
BYTE(0x00)
|
||||
SHORT(__bss_start-ORIGIN(ram)) /* size to load */
|
||||
BYTE(0x00)
|
||||
TRIM(ram)
|
||||
|
||||
INCLUDE output.ld
|
||||
|
||||
/* Launch the program, at _start */
|
||||
SHORT(_start)
|
||||
LONG(0)
|
||||
}
|
7
examples/overlay/foenixmgr.ini
Normal file
7
examples/overlay/foenixmgr.ini
Normal file
|
@ -0,0 +1,7 @@
|
|||
[DEFAULT]
|
||||
port=/dev/ttyUSB1
|
||||
labels=sample.lbl
|
||||
flash_address=380000
|
||||
chunk_size=1024
|
||||
cpu=65c02
|
||||
data_rate=6000000
|
41
examples/overlay/overlay.c
Normal file
41
examples/overlay/overlay.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include "f256.h"
|
||||
#include "f256.c"
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
#define test(...) ( *(volatile byte *)(0x000D) = 8; REAL_test(__VA_ARGS__); *(volatile byte *)(0x000D) = 5; )
|
||||
|
||||
|
||||
void test(int arg1, int arg2) {
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test(test);
|
||||
return 0;
|
||||
}
|
|
@ -51,8 +51,8 @@ add_subdirectory(atari2600-4k)
|
|||
add_subdirectory(atari2600-3e)
|
||||
add_subdirectory(atari8-common)
|
||||
add_subdirectory(atari8-dos)
|
||||
add_subdirectory(atari8-stdcart)
|
||||
add_subdirectory(atari8-xegs)
|
||||
add_subdirectory(atari8-cart-std)
|
||||
add_subdirectory(atari8-cart-xegs)
|
||||
add_subdirectory(commodore)
|
||||
add_subdirectory(c64)
|
||||
add_subdirectory(c128)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
|
@ -39,7 +40,7 @@ char *_bankName[BLOCK_COUNT]; // Far blocks (8+), shifted down 8.
|
|||
|
||||
|
||||
void findBank(char *name);
|
||||
void parseCFile(char *filename, FILE *trampoline, int swapSlot);
|
||||
void parseCFile(char *filename, char *targetFile, FILE *trampoline, char *trampolineFile, int swapSlot);
|
||||
void trimEnd(char *string);
|
||||
|
||||
|
||||
|
@ -72,24 +73,32 @@ void findBank(char *name) {
|
|||
}
|
||||
|
||||
|
||||
void parseCFile(char *filename, FILE *trampoline, int swapSlot) {
|
||||
void parseCFile(char *filename, char *targetFile, FILE *trampoline, char *trampolineFile, int swapSlot) {
|
||||
FILE *in;
|
||||
FILE *out;
|
||||
int c;
|
||||
int brackets = 0;
|
||||
int pos = 0;
|
||||
char buffer[BUFFER_SIZE];
|
||||
char *temp;
|
||||
char *newCFile;
|
||||
char *start;
|
||||
char *b;
|
||||
bool found;
|
||||
char *segDef = "#define SEGMENT_";
|
||||
int x;
|
||||
int brackets = 0;
|
||||
int crSinceStart = 0;
|
||||
int pos = 0;
|
||||
char *segDef = "#define SEGMENT_";
|
||||
|
||||
temp = utilGetLastPathComponent(filename);
|
||||
newCFile = utilReplaceExtension(temp, ".tc");
|
||||
free(temp);
|
||||
/*
|
||||
* This parser sucks.
|
||||
*
|
||||
* - It only handles C, not C++.
|
||||
* - It should scan for function names backwards from the '(' and not by skipping possible modifiers like 'static' and 'struct'.
|
||||
* - It can only handle single-line function definitions with the opening '{' on the same line as the function.
|
||||
* - It can be borked by comments.
|
||||
* - It always generates trampolines, not just when they're needed.
|
||||
*
|
||||
* Someone should fix it. :-)
|
||||
*/
|
||||
|
||||
in = fopen(filename, "rt");
|
||||
if (in == NULL) {
|
||||
|
@ -98,47 +107,42 @@ void parseCFile(char *filename, FILE *trampoline, int swapSlot) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
out = fopen(newCFile, "wt");
|
||||
out = fopen(targetFile, "wt");
|
||||
if (out == NULL) {
|
||||
fclose(in);
|
||||
fclose(trampoline);
|
||||
fprintf(stderr, "Cannot create %s!\n", newCFile);
|
||||
free(newCFile);
|
||||
fprintf(stderr, "Cannot create %s!\n", targetFile);
|
||||
free(targetFile);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Processing %s -> %s...\n", filename, targetFile);
|
||||
|
||||
// Add trampoline include automatically.
|
||||
fprintf(out, "#include \"%s\"\n\n", trampolineFile);
|
||||
|
||||
do {
|
||||
// Read next byte from C input file.
|
||||
if ((c = fgetc(in)) == EOF) break;
|
||||
|
||||
// Count brackets so we know if we're inside a function or not.
|
||||
if (c == '{') brackets++;
|
||||
if (c == '{') {
|
||||
brackets++;
|
||||
crSinceStart = 0;
|
||||
}
|
||||
if (c == '}') brackets--;
|
||||
|
||||
// End of line?
|
||||
if ((c == 13) || (c == 10)) {
|
||||
|
||||
crSinceStart++;
|
||||
|
||||
// End the line and trim the tail.
|
||||
buffer[pos] = 0;
|
||||
trimEnd(buffer);
|
||||
if (brackets != 1) {
|
||||
// Is this a segment definition? "#define SEGMENT_<something>"
|
||||
found = false;
|
||||
if (pos > strlen(segDef)) {
|
||||
found = true;
|
||||
for (x=0; x<strlen(segDef); x++) {
|
||||
if (buffer[x] != segDef[x]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
// New segment!
|
||||
findBank(&buffer[strlen(segDef)]);
|
||||
} else {
|
||||
// Just barf it out again.
|
||||
fprintf(out, "%s\n", buffer);
|
||||
}
|
||||
} else {
|
||||
|
||||
if ((brackets == 1) && (crSinceStart == 1)) {
|
||||
|
||||
// Is the last character a '{'? If we're not in a far memory bank, short-circuit this entire mess.
|
||||
if ((_currentBank > 0) && (buffer[strlen(buffer) - 1] == '{')) {
|
||||
// Remove it and any spaces.
|
||||
|
@ -175,12 +179,12 @@ void parseCFile(char *filename, FILE *trampoline, int swapSlot) {
|
|||
// Write out new function definition.
|
||||
fprintf(out, "%s FAR%d_%s {\n", buffer, 8, start);
|
||||
// Create trampoline macro.
|
||||
fprintf(trampoline, "#define %s(...) ({\n"
|
||||
"\t\tunsigned char ___mmu = (unsigned char)*(volatile unsigned char *)%#06x;\n"
|
||||
"\t\t*(volatile unsigned char *)%#06x = %d;\n"
|
||||
"\t\tFAR%d_%s(__VA_ARGS__);\n"
|
||||
"\t\t*(volatile unsigned char *)%#06x = ___mmu;\n"
|
||||
"\t})\n\n", temp, swapSlot, swapSlot, _currentBank, _currentBank, temp, swapSlot);
|
||||
fprintf(trampoline, "#define %s(...) ({ \\\n"
|
||||
"\t\tunsigned char ___mmu = (unsigned char)*(volatile unsigned char *)%#06x; \\\n"
|
||||
"\t\t*(volatile unsigned char *)%#06x = %d; \\\n"
|
||||
"\t\tFAR%d_%s(__VA_ARGS__); \\\n"
|
||||
"\t\t*(volatile unsigned char *)%#06x = ___mmu; \\\n"
|
||||
"\t})\n\n", temp, swapSlot, swapSlot, _currentBank, _currentBank, temp, swapSlot);
|
||||
free(temp);
|
||||
} else {
|
||||
// Not a function. Write as is. (Put the '{' back.)
|
||||
|
@ -190,20 +194,46 @@ void parseCFile(char *filename, FILE *trampoline, int swapSlot) {
|
|||
// Didn't find '{'.
|
||||
fprintf(out, "%s\n", buffer);
|
||||
}
|
||||
}
|
||||
fflush(out);
|
||||
|
||||
} else { // Brackets
|
||||
|
||||
// Is this a segment definition? "#define SEGMENT_<something>"
|
||||
found = false;
|
||||
if (pos > strlen(segDef)) {
|
||||
found = true;
|
||||
for (x=0; x<strlen(segDef); x++) {
|
||||
if (buffer[x] != segDef[x]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
// New segment!
|
||||
findBank(&buffer[strlen(segDef)]);
|
||||
}
|
||||
|
||||
// Write to output in case they depend on the define for some odd reason.
|
||||
fprintf(out, "%s\n", buffer);
|
||||
|
||||
} // Brackets.
|
||||
|
||||
// Reset buffer for next line.
|
||||
pos = 0;
|
||||
} else {
|
||||
|
||||
// Makes debugging nicer.
|
||||
fflush(out);
|
||||
|
||||
} else { // EOL
|
||||
|
||||
// Add to buffer.
|
||||
buffer[pos++] = c;
|
||||
}
|
||||
|
||||
} // EOL
|
||||
|
||||
} while (1);
|
||||
|
||||
fclose(in);
|
||||
|
||||
free(newCFile);
|
||||
}
|
||||
|
||||
|
||||
|
@ -224,27 +254,135 @@ void trimEnd(char *string) {
|
|||
int main(int argc, char *argv[]) {
|
||||
FILE *out;
|
||||
int x;
|
||||
int nearSlot;
|
||||
char *targetDir;
|
||||
char *sourceDir;
|
||||
char *trampolineFile;
|
||||
char *linkerFile;
|
||||
char *cFile;
|
||||
char *targetFile;
|
||||
char *thisDir;
|
||||
int sourceDirOffset;
|
||||
int thisOffset;
|
||||
DIR *dir;
|
||||
struct dirent *dirent;
|
||||
|
||||
/*
|
||||
* Command line:
|
||||
*
|
||||
* ./overlay [nearSlot#] [targetDir] [sourceDir1] ... {sourceDirX}
|
||||
*
|
||||
*/
|
||||
|
||||
if (argc < 4) {
|
||||
printf("Usage: %s [nearSlot#] [targetDir] [sourceDir1] ... {sourceDirX}\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Find near memory slot to swap into.
|
||||
nearSlot = atoi(argv[1]);
|
||||
if (nearSlot > 7) {
|
||||
printf("ERROR! Only slots 0-7 are in near memory.\n");
|
||||
return 1;
|
||||
}
|
||||
if (nearSlot == 0) {
|
||||
printf("WARNING! Slot 0 contains the zero page, stack, and MMU!\n");
|
||||
}
|
||||
if ((nearSlot == 6) || (nearSlot == 7)) {
|
||||
printf("WARNING! Slots 6 and 7 contain the microkernel!\n");
|
||||
}
|
||||
|
||||
// Does the target directory exist?
|
||||
targetDir = strdup(argv[2]);
|
||||
utilFixPathSeparators(&targetDir, false);
|
||||
if (!utilMkDirP(targetDir, 0777)) {
|
||||
printf("ERROR! Cannot create target directory %s!\n", targetDir);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create trampoline for all C files.
|
||||
out = fopen("trampoline.h", "wt");
|
||||
trampolineFile = utilCreateString("%s%ctrampoline.h", targetDir, utilGetPathSeparator());
|
||||
out = fopen(trampolineFile, "wt");
|
||||
if (out == NULL) {
|
||||
fprintf(stderr, "Cannot create trampoline.h!\n");
|
||||
fprintf(stderr, "ERROR! Cannot create %s!\n", trampolineFile);
|
||||
free(trampolineFile);
|
||||
free(targetDir);
|
||||
return 1;
|
||||
}
|
||||
fprintf(out, "// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.\n\n");
|
||||
fprintf(out, "#ifndef TRAMPOLINE_H\n");
|
||||
fprintf(out, "#define TRAMPOLINE_H\n\n");
|
||||
|
||||
// Find common inital path so we can remove it later.
|
||||
sourceDir = strdup(argv[x]);
|
||||
utilFixPathSeparators(&sourceDir, true);
|
||||
sourceDirOffset = strlen(sourceDir);
|
||||
if (argc > 4) {
|
||||
for (x=4; x<argc; x++) {
|
||||
thisOffset = 0;
|
||||
thisDir = strdup(argv[x]);
|
||||
utilFixPathSeparators(&thisDir, true);
|
||||
for (thisOffset=0; thisOffset < (strlen(sourceDir) < strlen(thisDir) ? strlen(sourceDir) : strlen(thisDir)); thisOffset++) {
|
||||
if (sourceDir[thisOffset] != thisDir[thisOffset]) break;
|
||||
}
|
||||
if (thisOffset < sourceDirOffset) sourceDirOffset = thisOffset - 1;
|
||||
free(thisDir);
|
||||
}
|
||||
}
|
||||
free(sourceDir);
|
||||
|
||||
// Do all the C files in a project, one at a time.
|
||||
parseCFile("/home/scott/code/f256/tools/overlay/interpreter.c", out, 0x000D);
|
||||
for (x=3; x<argc; x++) {
|
||||
sourceDir = strdup(argv[x]);
|
||||
utilFixPathSeparators(&sourceDir, true);
|
||||
if ((dir = opendir(sourceDir)) == NULL) {
|
||||
fprintf(stderr, "ERROR! Cannot open directory %s!\n", argv[x]);
|
||||
free(trampolineFile);
|
||||
free(targetDir);
|
||||
free(sourceDir);
|
||||
return 1;
|
||||
}
|
||||
for (;;) {
|
||||
if ((dirent = readdir(dir)) == NULL) break;
|
||||
if ((dirent->d_type == DT_LNK) || (dirent->d_type == DT_REG)) {
|
||||
// Is this a C file?
|
||||
if ((dirent->d_name[strlen(dirent->d_name) - 2] == '.') && (dirent->d_name[strlen(dirent->d_name) - 1] == 'c')) {
|
||||
cFile = utilCreateString("%s%s", sourceDir, dirent->d_name);
|
||||
targetFile = utilCreateString("%s%s%s", targetDir, &sourceDir[sourceDirOffset], dirent->d_name);
|
||||
thisDir = utilGetUpToLastPathComponent(targetFile);
|
||||
utilFixPathSeparators(&thisDir, false);
|
||||
if (!utilMkDirP(thisDir, 0777)) {
|
||||
printf("ERROR! Cannot create target directory %s!\n", thisDir);
|
||||
free(thisDir);
|
||||
free(trampolineFile);
|
||||
free(targetDir);
|
||||
free(sourceDir);
|
||||
free(cFile);
|
||||
closedir(dir);
|
||||
return 1;
|
||||
}
|
||||
free(thisDir);
|
||||
parseCFile(cFile, targetFile, out, trampolineFile, nearSlot + 8);
|
||||
free(cFile);
|
||||
free(targetFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
free(sourceDir);
|
||||
}
|
||||
|
||||
fprintf(out, "#endif // TRAMPOLINE_H\n");
|
||||
fclose(out);
|
||||
free(trampolineFile);
|
||||
|
||||
// Generate linker script data.
|
||||
out = fopen("output.ld", "wt");
|
||||
linkerFile = utilCreateString("%s%coutput.ld", targetDir, utilGetPathSeparator());
|
||||
out = fopen(linkerFile, "wt");
|
||||
if (out == NULL) {
|
||||
fprintf(stderr, "Cannot create output.ld!\n");
|
||||
fprintf(stderr, "ERROR! Cannot create %s!\n", linkerFile);
|
||||
free(targetDir);
|
||||
free(linkerFile);
|
||||
return 1;
|
||||
}
|
||||
for (x=0; x<_totalBanks; x++) {
|
||||
|
@ -255,11 +393,13 @@ int main(int argc, char *argv[]) {
|
|||
fprintf(out, " TRIM(block%d)\n\n", x+8);
|
||||
}
|
||||
fclose(out);
|
||||
free(linkerFile);
|
||||
|
||||
// Clean up.
|
||||
for (x=0; x<_totalBanks; x++) {
|
||||
free(_bankName[x]);
|
||||
}
|
||||
free(targetDir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -60,6 +60,52 @@ char *utilCreateStringVArgs(char *format, va_list args) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
void utilFixPathSeparators(char **path, bool slash) {
|
||||
|
||||
int32_t i = 0;
|
||||
int32_t j = 0;
|
||||
char *work = *path;
|
||||
char *temp = NULL;
|
||||
|
||||
// Flip path separators to whatever our OS wants & remove repeated separators.
|
||||
while (work[i] != 0) {
|
||||
// Correct separator
|
||||
if (work[i] == '\\' || work[i] == '/') {
|
||||
// Was the prior character a seprator?
|
||||
if (j == 0) {
|
||||
work[j++] = utilGetPathSeparator();
|
||||
} else {
|
||||
if (work[j - 1] != utilGetPathSeparator()) {
|
||||
// No, accept it.
|
||||
work[j++] = utilGetPathSeparator();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
work[j++] = work[i];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
work[j] = 0;
|
||||
|
||||
if (slash) {
|
||||
// Does this string end with a path separator?
|
||||
if (work[strlen(work) - 1] != utilGetPathSeparator()) {
|
||||
// No - append one.
|
||||
temp = strdup(work);
|
||||
free(work);
|
||||
work = malloc(sizeof(char) * (strlen(temp) + 2));
|
||||
strcpy(work, temp);
|
||||
work[strlen(temp)] = utilGetPathSeparator();
|
||||
work[strlen(temp) + 1] = 0;
|
||||
free(temp);
|
||||
}
|
||||
}
|
||||
|
||||
*path = work;
|
||||
}
|
||||
|
||||
|
||||
char *utilGetLastPathComponent(char *pathname) {
|
||||
static char *start;
|
||||
int32_t x;
|
||||
|
@ -77,6 +123,97 @@ char *utilGetLastPathComponent(char *pathname) {
|
|||
}
|
||||
|
||||
|
||||
char utilGetPathSeparator(void) {
|
||||
#ifdef _WIN32
|
||||
return '\\';
|
||||
#else
|
||||
return '/';
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
char *utilGetUpToLastPathComponent(char *pathname) {
|
||||
static char *copy = NULL;
|
||||
bool dumb = false; // Using (copy == NULL) below didn't work after optimizations, so enter the dummy.
|
||||
int32_t x;
|
||||
|
||||
x = (int32_t)(strlen(pathname) - strlen(utilGetLastPathComponent(pathname))) - 1;
|
||||
if (x < 0) x = 0;
|
||||
if (dumb) {
|
||||
free(copy);
|
||||
copy = NULL;
|
||||
} else {
|
||||
dumb = true;
|
||||
}
|
||||
copy = strdup(pathname);
|
||||
copy[x] = 0;
|
||||
utilFixPathSeparators(©, true);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
bool utilMkDirP(const char *dir, const mode_t mode) {
|
||||
char tmp[UTIL_PATH_MAX];
|
||||
char *p = NULL;
|
||||
struct stat sb;
|
||||
size_t len;
|
||||
|
||||
// Make copy of dir.
|
||||
len = strnlen(dir, UTIL_PATH_MAX);
|
||||
if (len == 0 || len == UTIL_PATH_MAX) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(tmp, dir, len);
|
||||
tmp[len] = '\0';
|
||||
|
||||
// Remove trailing slash.
|
||||
if (tmp[len - 1] == utilGetPathSeparator()) {
|
||||
tmp[len - 1] = '\0';
|
||||
}
|
||||
|
||||
// Does it already exist?
|
||||
if (stat(tmp, &sb) == 0) {
|
||||
if (S_ISDIR (sb.st_mode)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Recursive mkdir.
|
||||
for (p = tmp + 1; *p; p++) {
|
||||
if (*p == utilGetPathSeparator()) {
|
||||
*p = 0;
|
||||
if (stat(tmp, &sb) != 0) {
|
||||
// Does not exist - create it.
|
||||
if (mkdir(tmp, mode) < 0) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!S_ISDIR(sb.st_mode)) {
|
||||
// Not a directory
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*p = utilGetPathSeparator();
|
||||
}
|
||||
}
|
||||
// Check path
|
||||
if (stat(tmp, &sb) != 0) {
|
||||
// Does not exist - create it.
|
||||
if (mkdir(tmp, mode) < 0) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!S_ISDIR(sb.st_mode)) {
|
||||
// Not a directory
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
char *utilReplaceExtension(char *org, char *new_ext) {
|
||||
char *ext;
|
||||
char *tmp = strdup(org);
|
||||
|
|
|
@ -26,6 +26,11 @@
|
|||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
#define UTIL_PATH_MAX 1024
|
||||
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
@ -39,7 +44,11 @@ typedef struct colorS {
|
|||
|
||||
char *utilCreateString(char *format, ...);
|
||||
char *utilCreateStringVArgs(char *format, va_list args);
|
||||
void utilFixPathSeparators(char **path, bool slash);
|
||||
char *utilGetLastPathComponent(char *pathname);
|
||||
char utilGetPathSeparator(void);
|
||||
char *utilGetUpToLastPathComponent(char *pathname);
|
||||
bool utilMkDirP(const char *dir, const mode_t mode);
|
||||
char *utilReplaceExtension(char *org, char *new_ext);
|
||||
int utilStricmp(char *a, char *b);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue