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
|
*.sym
|
||||||
*.o
|
*.o
|
||||||
makemap
|
makemap
|
||||||
|
**/.builddir
|
||||||
|
|
||||||
# Crap for CrossOver
|
# Crap for CrossOver
|
||||||
.windows-serial
|
.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(atari2600-3e)
|
||||||
add_subdirectory(atari8-common)
|
add_subdirectory(atari8-common)
|
||||||
add_subdirectory(atari8-dos)
|
add_subdirectory(atari8-dos)
|
||||||
add_subdirectory(atari8-stdcart)
|
add_subdirectory(atari8-cart-std)
|
||||||
add_subdirectory(atari8-xegs)
|
add_subdirectory(atari8-cart-xegs)
|
||||||
add_subdirectory(commodore)
|
add_subdirectory(commodore)
|
||||||
add_subdirectory(c64)
|
add_subdirectory(c64)
|
||||||
add_subdirectory(c128)
|
add_subdirectory(c128)
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ char *_bankName[BLOCK_COUNT]; // Far blocks (8+), shifted down 8.
|
||||||
|
|
||||||
|
|
||||||
void findBank(char *name);
|
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);
|
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 *in;
|
||||||
FILE *out;
|
FILE *out;
|
||||||
int c;
|
int c;
|
||||||
int brackets = 0;
|
|
||||||
int pos = 0;
|
|
||||||
char buffer[BUFFER_SIZE];
|
char buffer[BUFFER_SIZE];
|
||||||
char *temp;
|
char *temp;
|
||||||
char *newCFile;
|
|
||||||
char *start;
|
char *start;
|
||||||
char *b;
|
char *b;
|
||||||
bool found;
|
bool found;
|
||||||
char *segDef = "#define SEGMENT_";
|
|
||||||
int x;
|
int x;
|
||||||
|
int brackets = 0;
|
||||||
|
int crSinceStart = 0;
|
||||||
|
int pos = 0;
|
||||||
|
char *segDef = "#define SEGMENT_";
|
||||||
|
|
||||||
temp = utilGetLastPathComponent(filename);
|
/*
|
||||||
newCFile = utilReplaceExtension(temp, ".tc");
|
* This parser sucks.
|
||||||
free(temp);
|
*
|
||||||
|
* - 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");
|
in = fopen(filename, "rt");
|
||||||
if (in == NULL) {
|
if (in == NULL) {
|
||||||
|
@ -98,47 +107,42 @@ void parseCFile(char *filename, FILE *trampoline, int swapSlot) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
out = fopen(newCFile, "wt");
|
out = fopen(targetFile, "wt");
|
||||||
if (out == NULL) {
|
if (out == NULL) {
|
||||||
fclose(in);
|
fclose(in);
|
||||||
fclose(trampoline);
|
fclose(trampoline);
|
||||||
fprintf(stderr, "Cannot create %s!\n", newCFile);
|
fprintf(stderr, "Cannot create %s!\n", targetFile);
|
||||||
free(newCFile);
|
free(targetFile);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("Processing %s -> %s...\n", filename, targetFile);
|
||||||
|
|
||||||
|
// Add trampoline include automatically.
|
||||||
|
fprintf(out, "#include \"%s\"\n\n", trampolineFile);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// Read next byte from C input file.
|
// Read next byte from C input file.
|
||||||
if ((c = fgetc(in)) == EOF) break;
|
if ((c = fgetc(in)) == EOF) break;
|
||||||
|
|
||||||
// Count brackets so we know if we're inside a function or not.
|
// Count brackets so we know if we're inside a function or not.
|
||||||
if (c == '{') brackets++;
|
if (c == '{') {
|
||||||
|
brackets++;
|
||||||
|
crSinceStart = 0;
|
||||||
|
}
|
||||||
if (c == '}') brackets--;
|
if (c == '}') brackets--;
|
||||||
|
|
||||||
// End of line?
|
// End of line?
|
||||||
if ((c == 13) || (c == 10)) {
|
if ((c == 13) || (c == 10)) {
|
||||||
|
|
||||||
|
crSinceStart++;
|
||||||
|
|
||||||
|
// End the line and trim the tail.
|
||||||
buffer[pos] = 0;
|
buffer[pos] = 0;
|
||||||
trimEnd(buffer);
|
trimEnd(buffer);
|
||||||
if (brackets != 1) {
|
|
||||||
// Is this a segment definition? "#define SEGMENT_<something>"
|
if ((brackets == 1) && (crSinceStart == 1)) {
|
||||||
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 {
|
|
||||||
// Is the last character a '{'? If we're not in a far memory bank, short-circuit this entire mess.
|
// 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] == '{')) {
|
if ((_currentBank > 0) && (buffer[strlen(buffer) - 1] == '{')) {
|
||||||
// Remove it and any spaces.
|
// Remove it and any spaces.
|
||||||
|
@ -175,12 +179,12 @@ void parseCFile(char *filename, FILE *trampoline, int swapSlot) {
|
||||||
// Write out new function definition.
|
// Write out new function definition.
|
||||||
fprintf(out, "%s FAR%d_%s {\n", buffer, 8, start);
|
fprintf(out, "%s FAR%d_%s {\n", buffer, 8, start);
|
||||||
// Create trampoline macro.
|
// Create trampoline macro.
|
||||||
fprintf(trampoline, "#define %s(...) ({\n"
|
fprintf(trampoline, "#define %s(...) ({ \\\n"
|
||||||
"\t\tunsigned char ___mmu = (unsigned char)*(volatile unsigned char *)%#06x;\n"
|
"\t\tunsigned char ___mmu = (unsigned char)*(volatile unsigned char *)%#06x; \\\n"
|
||||||
"\t\t*(volatile unsigned char *)%#06x = %d;\n"
|
"\t\t*(volatile unsigned char *)%#06x = %d; \\\n"
|
||||||
"\t\tFAR%d_%s(__VA_ARGS__);\n"
|
"\t\tFAR%d_%s(__VA_ARGS__); \\\n"
|
||||||
"\t\t*(volatile unsigned char *)%#06x = ___mmu;\n"
|
"\t\t*(volatile unsigned char *)%#06x = ___mmu; \\\n"
|
||||||
"\t})\n\n", temp, swapSlot, swapSlot, _currentBank, _currentBank, temp, swapSlot);
|
"\t})\n\n", temp, swapSlot, swapSlot, _currentBank, _currentBank, temp, swapSlot);
|
||||||
free(temp);
|
free(temp);
|
||||||
} else {
|
} else {
|
||||||
// Not a function. Write as is. (Put the '{' back.)
|
// Not a function. Write as is. (Put the '{' back.)
|
||||||
|
@ -190,20 +194,46 @@ void parseCFile(char *filename, FILE *trampoline, int swapSlot) {
|
||||||
// Didn't find '{'.
|
// Didn't find '{'.
|
||||||
fprintf(out, "%s\n", buffer);
|
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.
|
// Reset buffer for next line.
|
||||||
pos = 0;
|
pos = 0;
|
||||||
} else {
|
|
||||||
|
// Makes debugging nicer.
|
||||||
|
fflush(out);
|
||||||
|
|
||||||
|
} else { // EOL
|
||||||
|
|
||||||
// Add to buffer.
|
// Add to buffer.
|
||||||
buffer[pos++] = c;
|
buffer[pos++] = c;
|
||||||
}
|
|
||||||
|
} // EOL
|
||||||
|
|
||||||
} while (1);
|
} while (1);
|
||||||
|
|
||||||
fclose(in);
|
fclose(in);
|
||||||
|
|
||||||
free(newCFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -224,27 +254,135 @@ void trimEnd(char *string) {
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
FILE *out;
|
FILE *out;
|
||||||
int x;
|
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.
|
// 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) {
|
if (out == NULL) {
|
||||||
fprintf(stderr, "Cannot create trampoline.h!\n");
|
fprintf(stderr, "ERROR! Cannot create %s!\n", trampolineFile);
|
||||||
|
free(trampolineFile);
|
||||||
|
free(targetDir);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
fprintf(out, "// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.\n\n");
|
fprintf(out, "// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.\n\n");
|
||||||
fprintf(out, "#ifndef TRAMPOLINE_H\n");
|
fprintf(out, "#ifndef TRAMPOLINE_H\n");
|
||||||
fprintf(out, "#define TRAMPOLINE_H\n\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.
|
// 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");
|
fprintf(out, "#endif // TRAMPOLINE_H\n");
|
||||||
fclose(out);
|
fclose(out);
|
||||||
|
free(trampolineFile);
|
||||||
|
|
||||||
// Generate linker script data.
|
// Generate linker script data.
|
||||||
out = fopen("output.ld", "wt");
|
linkerFile = utilCreateString("%s%coutput.ld", targetDir, utilGetPathSeparator());
|
||||||
|
out = fopen(linkerFile, "wt");
|
||||||
if (out == NULL) {
|
if (out == NULL) {
|
||||||
fprintf(stderr, "Cannot create output.ld!\n");
|
fprintf(stderr, "ERROR! Cannot create %s!\n", linkerFile);
|
||||||
|
free(targetDir);
|
||||||
|
free(linkerFile);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
for (x=0; x<_totalBanks; x++) {
|
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);
|
fprintf(out, " TRIM(block%d)\n\n", x+8);
|
||||||
}
|
}
|
||||||
fclose(out);
|
fclose(out);
|
||||||
|
free(linkerFile);
|
||||||
|
|
||||||
// Clean up.
|
// Clean up.
|
||||||
for (x=0; x<_totalBanks; x++) {
|
for (x=0; x<_totalBanks; x++) {
|
||||||
free(_bankName[x]);
|
free(_bankName[x]);
|
||||||
}
|
}
|
||||||
|
free(targetDir);
|
||||||
|
|
||||||
return 0;
|
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) {
|
char *utilGetLastPathComponent(char *pathname) {
|
||||||
static char *start;
|
static char *start;
|
||||||
int32_t x;
|
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 *utilReplaceExtension(char *org, char *new_ext) {
|
||||||
char *ext;
|
char *ext;
|
||||||
char *tmp = strdup(org);
|
char *tmp = strdup(org);
|
||||||
|
|
|
@ -26,6 +26,11 @@
|
||||||
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define UTIL_PATH_MAX 1024
|
||||||
|
|
||||||
|
|
||||||
typedef unsigned char byte;
|
typedef unsigned char byte;
|
||||||
|
@ -39,7 +44,11 @@ typedef struct colorS {
|
||||||
|
|
||||||
char *utilCreateString(char *format, ...);
|
char *utilCreateString(char *format, ...);
|
||||||
char *utilCreateStringVArgs(char *format, va_list args);
|
char *utilCreateStringVArgs(char *format, va_list args);
|
||||||
|
void utilFixPathSeparators(char **path, bool slash);
|
||||||
char *utilGetLastPathComponent(char *pathname);
|
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);
|
char *utilReplaceExtension(char *org, char *new_ext);
|
||||||
int utilStricmp(char *a, char *b);
|
int utilStricmp(char *a, char *b);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue