Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'linker2'

Conflicts:
	dtcc/bootstrap.asm
	libdcpu-ci-lang-c/nodes/NDeclarations.cpp
	libdcpu-ci-lang/AsmGenerator.cpp
  • Loading branch information...
commit 28f5300152a1d954a534eac71fa7f923e2bc440b 2 parents 4040b69 + 68abf0c
@hach-que hach-que authored
Showing with 1,450 additions and 657 deletions.
  1. +15 −10 CMakeLists.txt
  2. +13 −7 docs/sources/tools/compiler/targets.rst
  3. +3 −2 dtasm/aerr.c
  4. +1 −0  dtasm/aerr.h
  5. +81 −1 dtasm/aout.c
  6. +4 −0 dtasm/aout.h
  7. +16 −0 dtasm/assem.c
  8. +3 −3 dtasm/lexer.l
  9. +1 −37 dtasm/parser.y
  10. +0 −3  dtcc/CMakeLists.txt
  11. +0 −170 dtcc/bootstrap.asm
  12. +0 −18 dtcc/dist/screen.m
  13. +0 −85 dtcc/dist/test.c
  14. +2 −9 dtcc/main.cpp
  15. +1 −0  dtld/CMakeLists.txt
  16. +337 −0 dtld/ldbin.c
  17. +48 −0 dtld/ldbin.h
  18. +524 −0 dtld/ldbins.c
  19. +33 −0 dtld/ldbins.h
  20. +91 −0 dtld/ldconv.c
  21. +32 −0 dtld/ldconv.h
  22. +19 −207 dtld/main.c
  23. +67 −74 libdcpu-ci-lang-c/nodes/NDeclarations.cpp
  24. +1 −18 libdcpu-ci-lang/AsmGenerator.cpp
  25. +1 −4 libdcpu-ci-lang/AsmGenerator.h
  26. +1 −1  libdcpu-ci-lang/Assembler.cpp
  27. +4 −4 libdcpu-ci-lang/Assembler.h
  28. +2 −0  libdcpu-ci-objfmt/ldata.h
  29. +52 −2 libdcpu-ci-objfmt/objfile.c
  30. +2 −2 libdcpu-ci-objfmt/objfile.h
  31. +55 −0 libdcpu/debug.c
  32. +34 −0 libdcpu/debug.h
  33. +7 −0 libdcpu/version.c
View
25 CMakeLists.txt
@@ -13,6 +13,11 @@ else("${git_hash}" STREQUAL "")
add_definitions(-DVERSION_STAGE=${VERSION_STAGE} -DVERSION_GIT=${VERSION_GIT})
endif("${git_hash}" STREQUAL "")
+# Set up options.
+option(BUILD_EMULATOR "Build the emulator and debugger." ON)
+option(BUILD_DOCUMENTATION "Build the documentation with Sphinx." ON)
+option(BUILD_DCPU "Build the kernel and standard libraries." ON)
+
# Set up some basics.
set(IS_ROOT 1)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMakeScripts")
@@ -32,9 +37,6 @@ if(MSVC)
# directory in this case.
set(FLEX_UNISTD_INCLUDE "${ROOT_DIR}/third-party/flex")
endif(MSVC)
-if(NOT DEFINED BUILD_EMULATOR)
- set(BUILD_EMULATOR true)
-endif(NOT DEFINED BUILD_EMULATOR)
if(NOT DEFINED FLEX_EXECUTABLE)
find_program(FLEX_EXECUTABLE NAMES flex.exe flex)
endif(NOT DEFINED FLEX_EXECUTABLE)
@@ -336,19 +338,22 @@ add_subdirectory(dtpp)
add_subdirectory(dtcc)
add_subdirectory(dtasm)
add_subdirectory(dtld)
-add_subdirectory(dtdb)
-
-if("${BUILD_EMULATOR}" MATCHES true)
+if(${BUILD_EMULATOR})
+ add_subdirectory(dtdb)
add_subdirectory(dtemu)
-endif("${BUILD_EMULATOR}" MATCHES true)
+endif(${BUILD_EMULATOR})
# Add documentation.
-add_subdirectory(docs)
+if(${BUILD_DOCUMENTATION})
+ add_subdirectory(docs)
+endif(${BUILD_DOCUMENTATION})
# Add scripts.
add_subdirectory(scripts)
# Add kernel and standard libraries.
-add_subdirectory(kernel)
-add_subdirectory(stdlib-c)
+if(${BUILD_DCPU})
+ add_subdirectory(kernel)
+ add_subdirectory(stdlib-c)
+endif(${BUILD_DCPU})
View
20 docs/sources/tools/compiler/targets.rst
@@ -12,9 +12,9 @@ under the specified target assembler.
The following assembler targets are supported (as well as the known list of features they support):
+-----------------------+-----------+----------------+------------------+---------------------+--------------------+-------------------+-------------------+
-| Type | .BOUNDARY | .DATA sections | .DAT instruction | Reordered addresses | Character literals | .IMPORT directive | .EXPORT directive |
+| Type | .BOUNDARY | .SECTION | .DAT instruction | Reordered addresses | Character literals | .IMPORT directive | .EXPORT directive |
+=======================+===========+================+==================+=====================+====================+===================+===================+
-| toolchain | Yes | `-` | Yes | Yes | Yes | Yes | Yes |
+| toolchain | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
+-----------------------+-----------+----------------+------------------+---------------------+--------------------+-------------------+-------------------+
| studio | `-` | `-` | Yes | `-` | `-` | `-` | `-` |
+-----------------------+-----------+----------------+------------------+---------------------+--------------------+-------------------+-------------------+
@@ -46,20 +46,26 @@ Provides a safety boundary for debugging purposes.
**Affected functionality:** The compiler will fall back to using the .DAT directive to replicate this
functionality if it is not available.
-.DATA section
+.SECTION
~~~~~~~~~~~~~~~~~
-Provides a contigious block of data declarations.
+Provides seperated sections of code and data which can then be
+reinserted later on at link stage.
.. code-block:: nasm
- .DATA
+ .SECTION DATA
myString "something that I want to embed"
myNumber 45
- .CODE
+ .SECTION CODE
SET A, 5
-**Affected functionality:** No current effect.
+.. code-block:: nasm
+
+ .OUTPUT DATA
+ .OUTPUT CODE
+
+**Affected functionality:** You will be unable to declare initializers on global variable expressions.
DAT instruction
~~~~~~~~~~~~~~~~~
View
5 dtasm/aerr.c
@@ -19,7 +19,7 @@
#include "aerr.h"
// Error strings
-const char* err_strings[19] =
+const char* err_strings[20] =
{
"assembler: generic assembling error.\n",
"assembler: label '%s' not found.\n",
@@ -39,7 +39,8 @@ const char* err_strings[19] =
"assembler: operation not defined for label resolution.\n",
"assembler: unable to resolve '%s' as label resolution is not permitted at this time.\n",
"assembler: the imported label '%s' may not be used as a component of an expression.\n",
- "assembler: expression '%s' evaluates to zero while being used as a divisor.\n"
+ "assembler: expression '%s' evaluates to zero while being used as a divisor.\n",
+ "assembler: .OUTPUT is not permitted prior to .SECTION.\n"
};
// Error definition
View
1  dtasm/aerr.h
@@ -40,6 +40,7 @@
#define ERR_LABEL_RESOLUTION_NOT_PERMITTED 16
#define ERR_EXPRESSION_NOT_PERMITTED 17
#define ERR_EXPRESSION_DIVIDE_BY_ZERO 18
+#define ERR_OUTPUT_BEFORE_SECTION 19
// Variables
extern const char* err_strings[];
View
82 dtasm/aout.c
@@ -227,6 +227,48 @@ struct aout_byte* aout_create_metadata_import(char* name)
return byte;
}
+struct aout_byte* aout_create_metadata_section(char* name)
+{
+ struct aout_byte* byte = malloc(sizeof(struct aout_byte));
+ byte->type = AOUT_TYPE_METADATA_SECTION;
+ byte->opcode = 0;
+ byte->a = 0;
+ byte->b = 0;
+ byte->next = NULL;
+ byte->prev = NULL;
+ byte->expr = NULL;
+ byte->label = name;
+ byte->raw_used = false;
+ byte->raw = 0x0;
+ byte->symbols[0] = NULL;
+ byte->symbols[1] = NULL;
+ byte->symbols[2] = NULL;
+ byte->symbols[3] = NULL;
+ byte->symbols_count = 0;
+ return byte;
+}
+
+struct aout_byte* aout_create_metadata_output(char* name)
+{
+ struct aout_byte* byte = malloc(sizeof(struct aout_byte));
+ byte->type = AOUT_TYPE_METADATA_OUTPUT;
+ byte->opcode = 0;
+ byte->a = 0;
+ byte->b = 0;
+ byte->next = NULL;
+ byte->prev = NULL;
+ byte->expr = NULL;
+ byte->label = name;
+ byte->raw_used = false;
+ byte->raw = 0x0;
+ byte->symbols[0] = NULL;
+ byte->symbols[1] = NULL;
+ byte->symbols[2] = NULL;
+ byte->symbols[3] = NULL;
+ byte->symbols_count = 0;
+ return byte;
+}
+
struct aout_byte* aout_emit(struct aout_byte* byte)
{
if (start == NULL && end == NULL)
@@ -307,6 +349,8 @@ void aout_write(FILE* out, bool relocatable, bool intermediate)
struct lprov_entry* linker_provided = NULL;
struct lprov_entry* linker_required = NULL;
struct lprov_entry* linker_adjustment = NULL;
+ struct lprov_entry* linker_section = NULL;
+ struct lprov_entry* linker_output = NULL;
struct lprov_entry* linker_temp = NULL;
uint32_t mem_index, out_index;
uint16_t inst;
@@ -315,6 +359,7 @@ void aout_write(FILE* out, bool relocatable, bool intermediate)
uint16_t eaddr;
bool did_find;
bool shown_expr_warning = false;
+ bool has_output = false;
// Initialize out our extension table.
code_offset += textn_init(start);
@@ -333,6 +378,41 @@ void aout_write(FILE* out, bool relocatable, bool intermediate)
// Adjust memory address.
out_index = current_outer->opcode;
}
+ else if (current_outer->type == AOUT_TYPE_METADATA_SECTION)
+ {
+ assert(current_outer->label != NULL);
+
+ // We're exporting the current address as the beginning
+ // of a section.
+ if (!intermediate)
+ ahalt(ERR_NOT_GENERATING_INTERMEDIATE_CODE, NULL);
+
+ // Check to make sure outputs haven't previously been emitted.
+ if (has_output)
+ ahalt(ERR_OUTPUT_BEFORE_SECTION, NULL);
+
+ // Create linker entry.
+ linker_temp = lprov_create(current_outer->label, out_index);
+ linker_temp->next = linker_section;
+ linker_section = linker_temp;
+ fprintf(stderr, "LINK SECTION %s -> 0x%04X\n", current_outer->label, out_index);
+ }
+ else if (current_outer->type == AOUT_TYPE_METADATA_OUTPUT)
+ {
+ assert(current_outer->label != NULL);
+
+ // We're exporting the current address as the beginning
+ // of a section.
+ if (!intermediate)
+ ahalt(ERR_NOT_GENERATING_INTERMEDIATE_CODE, NULL);
+
+ // Create linker entry.
+ has_output = true;
+ linker_temp = lprov_create(current_outer->label, out_index);
+ linker_temp->next = linker_output;
+ linker_output = linker_temp;
+ fprintf(stderr, "LINK OUTPUT 0x%04X -> %s\n", out_index, current_outer->label);
+ }
else if (current_outer->type == AOUT_TYPE_METADATA_EXPORT)
{
assert(current_outer->label != NULL);
@@ -449,7 +529,7 @@ void aout_write(FILE* out, bool relocatable, bool intermediate)
if (intermediate)
{
fwrite(ldata_objfmt, 1, strlen(ldata_objfmt) + 1, out);
- objfile_save(out, linker_provided, linker_required, linker_adjustment);
+ objfile_save(out, linker_provided, linker_required, linker_adjustment, linker_section, linker_output);
// Adjust the "true origin" for .ORIGIN directivies because
// the linker table won't exist in the final result when
View
4 dtasm/aout.h
@@ -27,6 +27,8 @@
#define AOUT_TYPE_METADATA_ORIGIN 3
#define AOUT_TYPE_METADATA_EXPORT 4
#define AOUT_TYPE_METADATA_IMPORT 5
+#define AOUT_TYPE_METADATA_SECTION 6
+#define AOUT_TYPE_METADATA_OUTPUT 7
struct aout_byte
{
@@ -56,6 +58,8 @@ struct aout_byte* aout_create_metadata_incbin(char* path);
struct aout_byte* aout_create_metadata_origin(uint16_t address);
struct aout_byte* aout_create_metadata_export(char* name);
struct aout_byte* aout_create_metadata_import(char* name);
+struct aout_byte* aout_create_metadata_section(char* name);
+struct aout_byte* aout_create_metadata_output(char* name);
struct aout_byte* aout_emit(struct aout_byte* byte);
void aout_write(FILE* out, bool relocatable, bool intermediate);
View
16 dtasm/assem.c
@@ -306,6 +306,22 @@ void process_line(struct ast_node_line* line)
case type_keyword:
switch (line->keyword)
{
+ case SECTION:
+ fprintf(stderr, ".SECTION %s", bstr2cstr(line->keyword_data_string, '0'));
+
+ // Emit section metadata.
+ aout_emit(aout_create_metadata_section(bstr2cstr(line->keyword_data_string, '0')));
+
+ break;
+
+ case OUTPUT:
+ fprintf(stderr, ".OUTPUT %s", bstr2cstr(line->keyword_data_string, '0'));
+
+ // Emit output metadata.
+ aout_emit(aout_create_metadata_output(bstr2cstr(line->keyword_data_string, '0')));
+
+ break;
+
case BOUNDARY:
fprintf(stderr, ".BOUNDARY");
View
6 dtasm/lexer.l
@@ -44,6 +44,7 @@ bstring yyfilename = NULL;
%x IN_NXT
%x IN_CHAR
%x IN_STRING
+%x IN_SECTION
%%
@@ -62,9 +63,8 @@ bstring yyfilename = NULL;
\.[Ee][Xx][Pp][Oo][Rr][Tt] yylval.number = EXPORT; return KEYWORD;
\.[Ii][Mm][Pp][Oo][Rr][Tt] yylval.number = IMPORT; return KEYWORD;
\.[Ff][Ii][Ll][Ll] yylval.number = FILL; return FILL;
-\.[Ee][Qq][Uu][Aa][Tt][Ee] return EQUATE;
-\.[Ee][Qq][Uu] return EQUATE;
-\.[Dd][Ee][Ff][Ii][Nn][Ee] return EQUATE;
+\.[Ss][Ee][Cc][Tt][Ii][Oo][Nn] yylval.number = SECTION; return KEYWORD;
+\.[Oo][Uu][Tt][Pp][Uu][Tt] yylval.number = OUTPUT; return KEYWORD;
/* Opcodes as numbers support */
View
38 dtasm/parser.y
@@ -72,7 +72,7 @@ extern bstring yyufilename;
%token <token> COMMA BRACKET_OPEN BRACKET_CLOSE COLON SEMICOLON NEWLINE COMMENT
%token <token> ADD SUBTRACT MULTIPLY DIVIDE MODULUS EQUALS NOT_EQUALS LESS_THAN LESS_EQUALS GREATER_THAN GREATER_EQUALS
%token <token> PAREN_OPEN PAREN_CLOSE BITWISE_AND BITWISE_BOR BITWISE_XOR BITWISE_NOT BOOLEAN_OR BOOLEAN_AND BINARY_LEFT_SHIFT BINARY_RIGHT_SHIFT
-%token <token> KEYWORD BOUNDARY EXTENSION ORIGIN INCLUDE INCBIN EXPORT IMPORT ERROR EQUATE FILL
+%token <token> KEYWORD BOUNDARY EXTENSION ORIGIN INCLUDE INCBIN EXPORT IMPORT ERROR EQUATE FILL SECTION OUTPUT
%token <word> WORD
%token <string> STRING CHARACTER
%token <number> ADDRESS
@@ -148,42 +148,6 @@ line:
{
$$ = NULL;
} |
- EQUATE WORD parameters NEWLINE
- {
- // Ugh, this is such an ugly hack and really needs to be better.
- struct ast_node_instruction* linst = malloc(sizeof(struct ast_node_instruction));
- struct ast_node_line* lnode = malloc(sizeof(struct ast_node_line));
- struct ast_node_label* lbl = malloc(sizeof(struct ast_node_label));
-
- // Initialize DAT instruction.
- linst->instruction = "DAT";
- linst->parameters = $3;
-
- // Initialize label.
- lbl->name = $2;
-
- // Initialize instruction.
- lnode->type = type_label;
- lnode->keyword = 0;
- lnode->instruction = NULL;
- lnode->label = lbl;
- lnode->prev = NULL;
- lnode->keyword_data_string = NULL;
- lnode->keyword_data_expr_1 = NULL;
- lnode->keyword_data_expr_2 = NULL;
- NODE_SET_GLOBALS(lnode);
-
- $$ = malloc(sizeof(struct ast_node_line));
- $$->type = type_instruction;
- $$->keyword = 0;
- $$->instruction = linst;
- $$->label = NULL;
- $$->prev = lnode;
- $$->keyword_data_string = NULL;
- $$->keyword_data_expr_1 = NULL;
- $$->keyword_data_expr_2 = NULL;
- NODE_SET_GLOBALS($$);
- } |
FILL expr expr NEWLINE
{
$$ = malloc(sizeof(struct ast_node_line));
View
3  dtcc/CMakeLists.txt
@@ -16,6 +16,3 @@ dt_needs(libdcpu-pp)
dt_needs(libdcpu-ci-lang)
dt_needs(libdcpu-ci-lang-c)
-# Copy required data files.
-file(COPY ./bootstrap.asm DESTINATION "${ROOT_DIR}/Debug" USE_SOURCE_PERMISSIONS)
-
View
170 dtcc/bootstrap.asm
@@ -1,170 +0,0 @@
-.ULINE 2 "bootstrap.asm"
-
-; Immediately jump to _setup.
-SET PC, _setup
-
-.BOUNDARY
-
-; Sets up the stack to hold data of the size
-; specified in the X register + 2. It copies
-; the value of Z register (which should be the
-; return point) into the new stack location, the
-; address of the last stack frame into [SP-1] and
-; sets the Y position 2 words ahead of where the
-; return value was stored. You should call this
-; by using the JSR operation. After this returns
-; you then need to insert all of the arguments
-; into the stack (don't use PUSH; use [Y+OFFSET])
-; and then SET PC, _target.
-;
-;
-; Stack Layout:
-;
-; ---------------------
-; | RETURN ADDRESS | <- SP (after init)
-; ---------------------
-; | NEXT STACK FRAME | -> points to old Y in higher memory
-; ---------------------
-; | | <- Y (after init)
-; | STACK DATA |
-; | |
-; ---------------------
-
-.EXPORT _stack_caller_init
-:_stack_caller_init
- SET I, POP
- SET J, SP
- SUB SP, X
- SET PUSH, Y ; we have to save the beginning of the old stack frame
- SET PUSH, Z
- SET Y, SP
- ADD Y, 2
- IFE X, 0
- SET PC, _stack_init_loop_end
- :_stack_init_loop
- SET [Y], 0
- ADD Y, 1
- IFN Y, J
- SET PC, _stack_init_loop
- :_stack_init_loop_end
- SET PEEK, Z
- SET Y, SP
- ADD Y, 2
- SET PC, I
-
-.BOUNDARY
-
-; Stack caller Init with _Overlap_
-; same as stack_caller_init, but loads parameter stack as overlap
-; this means, it is assumed that the parameter stack is allready
-; initialized with X words
-.EXPORT _stack_caller_init_overlap
-:_stack_caller_init_overlap
- SET I, POP
- SET J, SP
- SET PUSH, Y ; we have to save the beginning of the old stack frame
- SET PUSH, Z
- SET Y, SP
- ADD Y, 2
- SET PC, I
-
-.BOUNDARY
-
-; Frees the stack of the size specified in the
-; X register, placing the position of the next
-; stack frame into Y. It then jumps to the
-; return address that was specified in the just
-; free'd stack frame by using the Z register.
-.EXPORT _stack_callee_return
-:_stack_callee_return
- SET Z, PEEK ; [return] [stack frame] Z -> return value, Y -> stack frame
- SET PEEK, 0
- ADD SP, 1
- SET I, PEEK ; I -> address of next lower stack frame
- SET J, Y ; J -> address of stack frame
- ADD J, X ; J -> address of stack frame + stack size (excluding return value)
- :_stack_return_loop
- SET PEEK, 0
- ADD SP, 1 ; First iteration pops return value, then pops through the stack
- IFN SP, J ; Is the return value + stack frame cleared? (remember that the + size
- ; means it's the address beyond end-of-stack).
- SET PC, _stack_return_loop ; If not, repeat until it is.
- SET Y, I ; SP is now at its old position after stack_init
- ; I points to old Y, which is set to its old value
- ; return value. Set Y to the value of that.
- SET PC, Z ; Jump to the address of the original return value.
-
-.BOUNDARY
-
-; Halts the CPU.
-.EXPORT _halt
-:_halt
- SET PC, _halt
-
-.BOUNDARY
-
-; Halts the CPU clearing all registers except for
-; the A register.
-.EXPORT _halt_debug
-:_halt_debug
- SET B, 0
- SET C, 0
- SET X, 0
- SET Y, 0
- SET Z, 0
- SET I, 0
- SET J, 0
- SET SP, 0
- SET EX, 0
- SET PC, _halt
-
-; Locates a hardware device based on the specified
-; ID loaded into registers A and B. The resulting
-; message ID is loaded into register A.
-:_locate_device
- SET PUSH, A
- SET PUSH, B
- SET I, 0 ; I is the hardware number being checke
- :_locate_enum
- IFE I, 0xFFFF
- SET PC, _locate_none_found
- SET J, SP
- :_hw_searchloop ; Compare the hwq'd information to the requested device
- HWQ I ; Get hardware info for this device
- IFN A, [J] ; compare it to the current driver's ID
- SET PC, _hw_searchloop_continue
- :_hw_searchloop_a_e
- IFE B, [J + 1]
- SET PC, _locate_found
- SET PC, _hw_searchloop_continue
- :_hw_searchloop_continue
- ADD I, 1
- SET PC, _hw_searchloop
- :_locate_none_found
- SET A, 0
- SET PC, POP
- :_locate_found
- ADD SP, 2
- SET A, I
- SET PC, POP
-
-; Safety boundary
-.BOUNDARY
-
-; Handles initially jumping into the main function
-; that the user has provided.
-:_setup
-
- ; Initialize the screen.
- SET A, 0x7349
- SET B, 0xf615
- JSR _locate_device
- SET PUSH, A
- SET A, 0x0
- SET B, 0x8000
- HWI POP
-
-; THE COMPILER MUST GENERATE THE CONTENTS
-; OF _setup SO THAT THE STACK IS CORRECTLY
-; INITIALIZED FOR THE main FUNCTION.
-; BEGIN CODE APPEND HERE.
View
18 dtcc/dist/screen.m
@@ -1,18 +0,0 @@
-//
-// DCPU-16 Libraries
-//
-// Screen utilities.
-//
-
-void scrn_setc(char chr, int x, int y)
-{
- int mem = 0x8000 + x + y * 32;
- *mem = chr;
-}
-
-void scrn_sets(char* msg, int x, int y)
-{
- int i = 0;
- for (i = 0; *(msg + i) != '\0'; i += 1)
- scrn_setc(*(msg + i) + 0xF000, x + i, y);
-}
View
85 dtcc/dist/test.c
@@ -1,85 +0,0 @@
-//
-// Test file for the DCPU-16 compiler.
-//
-
-#include "screen.m"
-
-int globalInt;
-int anotherInt;
-int thirdInt;
-
-void (*func)(char* msg, int x, int y) = &scrn_sets;
-
-struct container_t
-{
- char* string;
- int test;
-};
-
-void print_in_red(char* msg, int x, int y)
-{
- int i = 0;
- for (i = 0; * (msg + i) != '\0'; i += 1)
- scrn_setc((*(msg + i) + 0xC000), x + i, y);
-}
-
-void print_in_yellow(char* msg, int x, int y)
-{
- int i = 0;
- for (i = 0; * (msg + i) != '\0'; i += 1)
- scrn_setc((*(msg + i) + 0xE000), x + i, y);
-}
-
-int get_input()
-{
- // Assumes legacy mode enabled in the emulator.
- return *0x9000;
-}
-
-void set_input(int val)
-{
- // Assumes legacy mode enabled in the emulator.
- * 0x9000 = val;
-}
-
-void main()
-{
- struct container_t data;
- int five;
- void (*local)(char * msg, int x, int y) = &scrn_sets;
- int test;
-
- // Set a global variable.
- globalInt = 2;
- anotherInt = 3;
- thirdInt = 0;
-
- // Set a local variable to the value of a global variable.
- five = globalInt + anotherInt;
-
- // Set string data.
- data.string = "This is my string!";
- data.test = 5;
-
- // Print
- scrn_sets("Hello 0x10c!", 0, 0);
- func("How do you like", 0, 1);
- func("my C compiler? :D", 0, 2);
- func(data.string, data.test, 3);
- func("Is it on line 6?", 0, five);
-
- // Change colour by changing the function pointer!
- func = &print_in_red;
- local = &print_in_yellow;
- func("Now with extra red!", 0, 6);
- local("Local function pointers work to!", 0, 7);
-
- while (true)
- {
- // Continually get input and set 0, 0 to it.
- test = get_input();
- set_input(0);
- if (test != 0)
- scrn_setc(test + 0xF000, 0, 0);
- }
-}
View
11 dtcc/main.cpp
@@ -41,9 +41,8 @@ int main(int argc, char* argv[])
struct arg_str* type_assembler = arg_str0("t", NULL, "<type>", "The type of assembler to output for.");
struct arg_file* input_file = arg_file1(NULL, NULL, "<file>", "The input file (or - to read from standard input).");
struct arg_file* output_file = arg_file1("o", "output", "<file>", "The output file (or - to send to standard output).");
- struct arg_lit* gen_entrypoint = arg_lit0("e", "entry-point", "Generate assembly to be used as the entry-point object.");
struct arg_end* end = arg_end(20);
- void* argtable[] = { output_file, gen_entrypoint, show_help, type_assembler, input_file, end };
+ void* argtable[] = { output_file, show_help, type_assembler, input_file, end };
// Parse arguments.
int nerrors = arg_parse(argc, argv, argtable);
@@ -113,21 +112,15 @@ int main(int argc, char* argv[])
// Generate assembly using the AST.
try
{
- AsmGenerator generator(asmtype, gen_entrypoint->count > 0);
+ AsmGenerator generator(asmtype);
AsmBlock* block = program->compile(generator);
if (strcmp(output_file->filename[0], "-") == 0)
- {
- std::cout << generator.m_Preassembly << std::endl;
std::cout << *block << std::endl;
- std::cout << generator.m_Postassembly << std::endl;
- }
else
{
std::ofstream output(output_file->filename[0], std::ios::out | std::ios::trunc);
- output << generator.m_Preassembly << std::endl;
output << *block << std::endl;
- output << generator.m_Postassembly << std::endl;
output.close();
}
View
1  dtld/CMakeLists.txt
@@ -10,6 +10,7 @@ endif(NOT DEFINED IS_ROOT)
# Define the linker project.
dt_project(executable)
dt_needs(bstring)
+dt_needs(simclist)
dt_needs(argtable2)
dt_needs(libdcpu)
dt_needs(libdcpu-ci-objfmt)
View
337 dtld/ldbin.c
@@ -0,0 +1,337 @@
+/**
+
+ File: ldbin.c
+
+ Project: DCPU-16 Toolchain
+ Component: Linker
+
+ Authors: James Rhodes
+
+ Description: Provides section bins for storing code in while
+ section and output dependencies are resolved.
+
+**/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "ldbin.h"
+#include "ldconv.h"
+
+///
+/// Creates a new linker bin.
+///
+/// @param name The name of the linker bin.
+/// @return The new linker bin.
+///
+struct ldbin* bin_create(freed_bstring name, bool initLists)
+{
+ struct ldbin* bin = malloc(sizeof(struct ldbin));
+ memset(bin, 0, sizeof(struct ldbin));
+ bin->name = bfromcstr("");
+ bassign(bin->name, name.ref);
+ bautodestroy(name);
+ list_init(&bin->words);
+ list_attributes_copy(&bin->words, &list_meter_uint16_t, 1);
+ list_attributes_comparator(&bin->words, &list_comparator_uint16_t);
+ list_attributes_hash_computer(&bin->words, &list_hashcomputer_uint16_t);
+ if (initLists)
+ {
+ bin->provided = list_create();
+ bin->required = list_create();
+ bin->adjustment = list_create();
+ bin->section = list_create();
+ bin->output = list_create();
+ }
+ else
+ {
+ bin->provided = NULL;
+ bin->required = NULL;
+ bin->adjustment = NULL;
+ bin->section = NULL;
+ bin->output = NULL;
+ }
+ return bin;
+}
+
+///
+/// Destroys a linker bin.
+///
+/// @param bin The linker bin to destroy.
+///
+void bin_destroy(struct ldbin* bin)
+{
+ if (bin->provided != NULL) list_destroy(bin->provided);
+ if (bin->required != NULL) list_destroy(bin->required);
+ if (bin->adjustment != NULL) list_destroy(bin->adjustment);
+ if (bin->section != NULL) list_destroy(bin->section);
+ if (bin->output != NULL) list_destroy(bin->output);
+ bdestroy(bin->name);
+ free(bin);
+}
+
+///
+/// Writes a word out to the linker bin.
+///
+/// @param bin The linker bin to store the word in.
+///
+///
+void bin_write(struct ldbin* bin, uint16_t word)
+{
+ // Append a word to the list (this will copy the value of
+ // word after receiving it's reference, so there's no
+ // danger of corrupting the list with stack addresses).
+ list_append(&bin->words, &word);
+}
+
+///
+/// Moves words from one bin to another, adjusting as needed.
+///
+/// Moves words from one bin to another, starting at the specified
+/// offset and transferring up to count words. Linker information
+/// is automatically adjusted as part of this process.
+///
+/// @param to The target bin to write the words into.
+/// @param from The source bin to read words from.
+/// @param at The address in the target bin where writing should occur.
+/// @param offset The address in the source bin where reading should occur.
+/// @param count The number of words to be moved.
+///
+void bin_move(struct ldbin* to, struct ldbin* from, size_t at, size_t offset, size_t count)
+{
+ bin_insert(to, from, at, offset, count);
+ bin_remove(from, offset, count);
+}
+
+///
+/// Replaces words in one bin with another, adjusting as needed.
+///
+/// Replaces words in one bin with another, starting at the specified
+/// offset and transferring up to count words. Linker information
+/// is automatically adjusted as part of this process.
+///
+/// @param to The target bin to write the words into.
+/// @param from The source bin to read words from.
+/// @param at The address in the target bin where writing should occur.
+/// @param erase The number of words to be discarded before writing.
+/// @param offset The address in the source bin where reading should occur.
+/// @param count The number of words to be written.
+///
+void bin_replace(struct ldbin* to, struct ldbin* from, size_t at, size_t erase, size_t offset, size_t count)
+{
+ bin_remove(to, at, erase);
+ bin_insert(to, from, at, offset, count);
+}
+
+///
+/// Appends words from one bin to another, adjusting as needed.
+///
+/// Appends words from one bin to another, starting at the specified
+/// offset and transferring up to count words. Linker information
+/// is automatically adjusted as part of this process.
+///
+/// @param to The target bin to write the words into.
+/// @param from The source bin to read words from.
+/// @param offset The address in the source bin where reading should occur.
+/// @param count The number of words to be written.
+///
+void bin_append(struct ldbin* to, struct ldbin* from, size_t offset, size_t count)
+{
+ bin_insert(to, from, list_size(&to->words), offset, count);
+}
+
+///
+/// Inserts words from one bin to another, adjusting as needed.
+///
+/// Inserts words from one bin to another, starting at the specified
+/// offset and transferring up to count words. Linker information
+/// is automatically adjusted as part of this process.
+///
+/// @param to The target bin to write the words into.
+/// @param from The source bin to read words from.
+/// @param at The address in the target bin where writing should occur.
+/// @param offset The address in the source bin where reading should occur.
+/// @param count The number of words to be written.
+///
+void bin_insert(struct ldbin* to, struct ldbin* from, size_t at, size_t offset, size_t count)
+{
+ size_t i;
+
+ assert(to != NULL);
+ assert(from != NULL);
+ assert(at >= 0 && at <= list_size(&to->words));
+ assert(offset >= 0 && offset <= list_size(&from->words));
+ assert(offset + count >= 0 && offset + count <= list_size(&from->words));
+
+ for (i = 0; i < count; i++)
+ {
+ // Copy the word.
+ list_insert_at(&to->words, list_get_at(&from->words, offset + i), at + i);
+ }
+
+ // Perform linker information updates.
+ bin_info_insert(to, to->provided, from, from->provided, false, false, at, offset, count);
+ bin_info_insert(to, to->required, from, from->required, false, false, at, offset, count);
+ bin_info_insert(to, to->adjustment, from, from->adjustment, true, false, at, offset, count);
+ bin_info_insert(to, to->output, from, from->output, false, true, at, offset, count);
+}
+
+///
+/// Removes words in a bin.
+///
+/// Removed words in a bin, starting at the specified
+/// offset and transferring up to count words. Linker information
+/// is automatically removed as part of this process.
+///
+/// @param bin The bin to remove words from.
+/// @param offset The address to start removal from.
+/// @param count The number of words to be removed.
+///
+void bin_remove(struct ldbin* bin, size_t offset, size_t count)
+{
+ size_t i;
+
+ assert(bin != NULL);
+ assert(offset >= 0 && offset <= list_size(&bin->words));
+ assert(offset + count >= 0 && offset + count <= list_size(&bin->words));
+
+ for (i = 0; i < count; i++)
+ {
+ // Delete the word.
+ list_delete_at(&bin->words, offset);
+ }
+
+ // Perform linker information updates.
+ bin_info_remove(bin, bin->provided, offset, count);
+ bin_info_remove(bin, bin->required, offset, count);
+ bin_info_remove(bin, bin->adjustment, offset, count);
+ bin_info_remove(bin, bin->output, offset, count);
+}
+
+///
+/// Copies references from the specified linker information list to another linker information list.
+///
+/// @param to The target bin that words were inserted into.
+/// @param tolist The target linker information list to adjust.
+/// @param from The source bin that words were read from.
+/// @param fromlist The source linker information list to adjust.
+/// @param at The address in the target bin where the insert occurred.
+/// @param offset The address in the source bin where words were copied from.
+/// @param count The number of words that were inserted.
+///
+void bin_info_insert(struct ldbin* to, list_t* tolist, struct ldbin* from, list_t* fromlist, bool isAdjustment, bool isOutput, size_t at, size_t offset, size_t count)
+{
+ struct lconv_entry* entry;
+ struct lconv_entry* copy;
+ size_t k;
+ uint16_t* word;
+
+ // Skip if the from list is NULL.
+ if (fromlist == NULL) return;
+ assert(tolist != NULL);
+
+ // Sort the list by addresses.
+ list_sort(fromlist, 1);
+
+ // Skip shifting if this is the output linker info list because
+ // that causes the output addresses to be shifted up when we're
+ // flattening bins.
+ if (!isOutput)
+ {
+ // Adjust all of the memory addresses for linker entries in the
+ // bin that was written to and shift them up.
+ for (k = 0; k < list_size(tolist); k++)
+ {
+ entry = (struct lconv_entry*)list_get_at(tolist, k);
+
+ if (entry->address >= offset + count)
+ {
+ // Shift the address up.
+ entry->address += count;
+
+ // If this is an adjustment entry, we need to adjust it
+ // immediately (since we have no label to keep track of).
+ if (isAdjustment)
+ {
+ word = (uint16_t*)list_get_at(&to->words, entry->address);
+ if (*word >= offset)
+ *word = *word + count;
+ }
+ }
+ }
+ }
+
+ // Copy all of the new linker information entries
+ // across into the correct place.
+ for (k = 0; k < list_size(fromlist); k++)
+ {
+ entry = (struct lconv_entry*)list_get_at(fromlist, k);
+
+ if (entry->address >= offset && entry->address < offset + count)
+ {
+ // Copy this linker information entry.
+ copy = malloc(sizeof(struct lconv_entry));
+ copy->address = entry->address;
+ copy->label = bfromcstr("");
+ bassign(copy->label, entry->label);
+
+ // Adjust the copy.
+ copy->address = at + (entry->address - offset);
+ list_append(tolist, copy);
+
+ // If this is an adjustment entry, we need to adjust it
+ // immediately (since we have no label to keep track of).
+ if (isAdjustment)
+ {
+ word = (uint16_t*)list_get_at(&to->words, copy->address);
+ // TODO: Proper error message for when adjustment values are
+ // currently outside the code that's being copied across.
+ assert(*word >= offset && *word < offset + count);
+ *word = *word + (copy->address - entry->address);
+ }
+ }
+ }
+}
+
+///
+/// Removes references in the specified linker information list.
+///
+/// @param bin The bin that this linker information list belongs to.
+/// @param list The linker information list to adjust.
+/// @param isAdjustment Whether the linker information list is an adjustment list.
+/// @param offset The address that words were removed from.
+/// @param count The number of words that were removed.
+///
+void bin_info_remove(struct ldbin* bin, list_t* list, size_t offset, size_t count)
+{
+ struct lconv_entry* entry;
+ size_t k;
+
+ // Skip if the list is NULL.
+ if (list == NULL) return;
+
+ // Sort the list by addresses.
+ list_sort(list, 1);
+
+ // Go through all of the information entries in the list.
+ for (k = 0; k < list_size(list); k++)
+ {
+ entry = (struct lconv_entry*)list_get_at(list, k);
+
+ if (entry->address < offset)
+ // Prior to the current address, so don't touch it.
+ continue;
+ else if (entry->address >= offset && entry->address < offset + count)
+ {
+ // Remove this linker information entry.
+ list_delete_at(list, k);
+ k--;
+ }
+ else if (entry->address >= offset + count)
+ {
+ // Adjust the address stored in the entry down
+ // by the amount of words that were removed.
+ entry->address -= count;
+ }
+ }
+}
View
48 dtld/ldbin.h
@@ -0,0 +1,48 @@
+/**
+
+ File: ldbin.h
+
+ Project: DCPU-16 Toolchain
+ Component: Linker
+
+ Authors: James Rhodes
+
+ Description: Provides section bins for storing code in while
+ section and output dependencies are resolved.
+
+**/
+
+#ifndef __DCPU_LD_BIN_H
+#define __DCPU_LD_BIN_H
+
+#include <stdint.h>
+#include <bstring.h>
+#include <simclist.h>
+#include <lprov.h>
+#include <dcpu.h>
+
+struct ldbin
+{
+ bstring name;
+ list_t* provided;
+ list_t* required;
+ list_t* adjustment;
+ list_t* section;
+ list_t* output;
+ list_t words;
+};
+
+struct ldbin* bin_create(freed_bstring name, bool initLists);
+void bin_destroy(struct ldbin* bin);
+void bin_write(struct ldbin* bin, uint16_t word);
+
+void bin_move(struct ldbin* to, struct ldbin* from, size_t at, size_t offset, size_t count);
+void bin_replace(struct ldbin* to, struct ldbin* from, size_t at, size_t erase, size_t offset, size_t count);
+void bin_append(struct ldbin* to, struct ldbin* from, size_t offset, size_t count);
+void bin_insert(struct ldbin* to, struct ldbin* from, size_t at, size_t offset, size_t count);
+void bin_remove(struct ldbin* bin, size_t offset, size_t count);
+
+void bin_info_insert(struct ldbin* to, list_t* tolist, struct ldbin* from, list_t* fromlist, bool isAdjustment, bool isOutput, size_t at, size_t offset, size_t count);
+void bin_info_remove(struct ldbin* bin, list_t* list, size_t offset, size_t count);
+
+#endif
View
524 dtld/ldbins.c
@@ -0,0 +1,524 @@
+/**
+
+ File: ldbins.c
+
+ Project: DCPU-16 Toolchain
+ Component: Linker
+
+ Authors: James Rhodes
+
+ Description: Provides section bins for storing code in while
+ section and output dependencies are resolved.
+
+**/
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <simclist.h>
+#include <ldata.h>
+#include <objfile.h>
+#include <assert.h>
+#include <debug.h>
+#include "ldbins.h"
+#include "ldbin.h"
+#include "ldconv.h"
+
+///
+/// The global bin storage.
+///
+struct
+{
+ list_t bins;
+} ldbins;
+
+///
+/// Finds a bin in the bin list by it's name.
+///
+int bin_seeker(const void* el, const void* indicator)
+{
+ if (el == NULL || indicator == NULL) return 0;
+ if (biseq(((struct ldbin*)el)->name, (bstring)indicator))
+ return 1;
+ else
+ return 0;
+}
+
+///
+/// Initializes the linker bin system.
+///
+void bins_init()
+{
+ list_init(&ldbins.bins);
+ list_attributes_seeker(&ldbins.bins, &bin_seeker);
+}
+
+///
+/// Adds a new bin to the system with the specified name.
+///
+/// Adds a new bin to the system with the specified name and link
+/// information.
+///
+/// @param name The bin name.
+/// @param provided A linked list of provided labels.
+/// @param required A linked list of required labels.
+/// @param adjustment A linked list of addresses that need adjusting.
+/// @param section A linked list of defined sections.
+/// @param output A linked list of defined output areas.
+///
+struct ldbin* bins_add(freed_bstring name, struct lprov_entry* provided, struct lprov_entry* required, struct lprov_entry* adjustment, struct lprov_entry* section, struct lprov_entry* output)
+{
+ struct ldbin* bin = bin_create(name, false);
+ bin->provided = list_convert(provided);
+ bin->required = list_convert(required);
+ bin->adjustment = list_convert(adjustment);
+ bin->section = list_convert(section);
+ bin->output = list_convert(output);
+ list_append(&ldbins.bins, bin);
+ return bin;
+}
+
+///
+/// Loads a new bin by reading a linker object from file.
+///
+/// Adds a new bin by reading in a linker object stored on disk and
+/// automatically handling loading bytes and linker information into
+/// the bin.
+///
+/// @param path The path to load.
+/// @return Whether the bin was loaded successfully.
+///
+bool bins_load(freed_bstring path)
+{
+ uint16_t offset = 0, store;
+ struct lprov_entry* required = NULL;
+ struct lprov_entry* provided = NULL;
+ struct lprov_entry* adjustment = NULL;
+ struct lprov_entry* section = NULL;
+ struct lprov_entry* output = NULL;
+ struct ldbin* bin;
+ FILE* in;
+ char* test;
+
+ // Open the input file.
+ in = fopen(path.ref->data, "rb");
+
+ if (in == NULL)
+ {
+ // Handle the error.
+ return false;
+ }
+
+ // Is this the object format?
+ test = malloc(strlen(ldata_objfmt) + 1);
+ memset(test, 0, strlen(ldata_objfmt) + 1);
+ fread(test, 1, strlen(ldata_objfmt), in);
+ fseek(in, 1, SEEK_CUR);
+
+ if (strcmp(test, ldata_objfmt) != 0)
+ {
+ // Handle the error.
+ return false;
+ }
+
+ free(test);
+
+ // Load only the provided label entries into memory.
+ objfile_load(path.ref->data, in, &offset, &provided, &required, &adjustment, &section, &output);
+
+ // Add the new bin.
+ bin = bins_add(path, provided, required, adjustment, section, output);
+
+ // Copy all of the input file's data into the output
+ // file, word by word.
+ while (true)
+ {
+ // Read a word into the bin. The reason that
+ // we break inside the loop is that we are reading
+ // two bytes at a time and thus the EOF flag doesn't
+ // get set until we actually attempt to read past
+ // the end-of-file. If we don't do this, we get a
+ // double read of the same data.
+ fread(&store, sizeof(uint16_t), 1, in);
+ if (feof(in))
+ break;
+ bin_write(bin, store);
+ }
+
+ // Close the file.
+ fclose(in);
+
+ // TODO: Free the list data in the struct lprov_entry
+ // pointers (since it's cloned by the bin system).
+
+ return true;
+}
+
+///
+/// Saves the bin with the specified name to the specified path.
+///
+/// @param name The name of the bin to save.
+/// @param path The path to save the bin to.
+///
+void bins_save(freed_bstring name, freed_bstring path)
+{
+ FILE* out;
+ struct ldbin* bin = list_seek(&ldbins.bins, name.ref);
+ assert(bin != NULL);
+
+ // Open the output file.
+ out = fopen(path.ref->data, "wb");
+
+ // Write each byte from the bin.
+ list_iterator_start(&bin->words);
+ while (list_iterator_hasnext(&bin->words))
+ fwrite(list_iterator_next(&bin->words), sizeof(uint16_t), 1, out);
+ list_iterator_stop(&bin->words);
+
+ // Close the output file.
+ fclose(out);
+
+ // Free strings.
+ bautodestroy(name);
+ bautodestroy(path);
+}
+
+///
+/// Writes a word of data into the specified bin.
+///
+/// @param path The path to load.
+/// @return Whether the bin was loaded successfully.
+///
+bool bins_write(freed_bstring name, uint16_t word)
+{
+ struct ldbin* bin = list_seek(&ldbins.bins, name.ref);
+ if (bin == NULL)
+ {
+ bautodestroy(name);
+ return false;
+ }
+ bin_write(bin, word);
+ return true;
+}
+
+///
+/// Splits the currently loaded bins into sectioned bins.
+///
+void bins_sectionize()
+{
+ struct lconv_entry* entry;
+ struct ldbin* bin;
+ struct ldbin* target;
+ list_t create;
+ size_t i;
+ int steal, stolen, index, base;
+ bstring name;
+
+ list_init(&create);
+ list_attributes_seeker(&create, &bin_seeker);
+
+ // Print result information.
+ for (i = 0; i < list_size(&ldbins.bins); i++)
+ {
+ bin = list_get_at(&ldbins.bins, i);
+ printd(LEVEL_VERBOSE, "start bin: %s\n", bin->name->data);
+ bin->provided != NULL ? printd(LEVEL_VERBOSE, " total provided: %u\n", list_size(bin->provided)) : false;
+ bin->required != NULL ? printd(LEVEL_VERBOSE, " total required: %u\n", list_size(bin->required)) : false;
+ bin->adjustment != NULL ? printd(LEVEL_VERBOSE, " total adjustment: %u\n", list_size(bin->adjustment)) : false;
+ bin->section != NULL ? printd(LEVEL_VERBOSE, " total sections: %u\n", list_size(bin->section)) : false;
+ bin->output != NULL ? printd(LEVEL_VERBOSE, " total outputs: %u\n", list_size(bin->output)) : false;
+ printd(LEVEL_VERBOSE, " total words: 0x%04X\n", list_size(&bin->words));
+ list_iterator_start(&bin->words);
+ while (list_iterator_hasnext(&bin->words))
+ printd(LEVEL_VERBOSE, " 0x%04X\n", *(uint16_t*)list_iterator_next(&bin->words));
+ list_iterator_stop(&bin->words);
+ printd(LEVEL_VERBOSE, " \n");
+ }
+
+ // Copy words into appropriate bins.
+ list_iterator_start(&ldbins.bins);
+ while (list_iterator_hasnext(&ldbins.bins))
+ {
+ bin = list_iterator_next(&ldbins.bins);
+
+ // Search all of the sections in this bin.
+ assert(bin->section != NULL);
+ list_iterator_start(bin->section);
+ while (list_iterator_hasnext(bin->section))
+ {
+ entry = list_iterator_next(bin->section);
+
+ // Create target section bin if it doesn't
+ // already exist.
+ name = bfromcstr("SECTION ");
+ bconcat(name, entry->label);
+ if (list_seek(&create, name) == NULL)
+ {
+ target = bin_create(bautofree(name), false);
+ target->provided = list_create();
+ target->required = list_create();
+ target->adjustment = list_create();
+ target->output = list_create();
+ list_append(&create, target);
+ }
+ else
+ bdestroy(name);
+ }
+ list_iterator_stop(bin->section);
+ }
+ list_iterator_stop(&ldbins.bins);
+
+ // For each of the file bins, move the code that they
+ // have in sections into the section bins.
+ list_iterator_start(&ldbins.bins);
+ while (list_iterator_hasnext(&ldbins.bins))
+ {
+ bin = list_iterator_next(&ldbins.bins);
+
+ // Search all of the sections in this bin.
+ stolen = 0;
+ assert(bin->section != NULL);
+ list_sort(bin->section, 1);
+ for (i = 0; i < list_size(bin->section); i++)
+ {
+ // Work out the target bin.
+ name = bfromcstr("SECTION ");
+ bconcat(name, ((struct lconv_entry*)list_get_at(bin->section, i))->label);
+ target = list_seek(&create, name);
+ assert(target != NULL);
+ bdestroy(name);
+
+ // Calculate how many bytes to steal from this section.
+ if (i == list_size(bin->section) - 1)
+ {
+ // Steal until end-of-bin.
+ steal = list_size(&bin->words) -
+ (((struct lconv_entry*)list_get_at(bin->section, i))->address - stolen);
+ }
+ else
+ {
+ // Steal up to the next section.
+ steal = (((struct lconv_entry*)list_get_at(bin->section, i + 1))->address - stolen) -
+ (((struct lconv_entry*)list_get_at(bin->section, i))->address - stolen);
+ }
+
+ // Get the index from which to extract.
+ index = ((struct lconv_entry*)list_get_at(bin->section, i))->address - stolen;
+ base = list_size(&target->words);
+
+ bin_move(target, bin, base, index, steal);
+ stolen += steal;
+ }
+ }
+ list_iterator_stop(&ldbins.bins);
+
+ // Append new bins to the bin list and free
+ // memory of old list.
+ list_iterator_start(&create);
+ while (list_iterator_hasnext(&create))
+ list_append(&ldbins.bins, list_iterator_next(&create));
+ list_iterator_stop(&create);
+ list_destroy(&create);
+
+ // Print result information.
+ for (i = 0; i < list_size(&ldbins.bins); i++)
+ {
+ bin = list_get_at(&ldbins.bins, i);
+ printd(LEVEL_VERBOSE, "end bin: %s\n", bin->name->data);
+ bin->provided != NULL ? printd(LEVEL_VERBOSE, " total provided: %u\n", list_size(bin->provided)) : false;
+ bin->required != NULL ? printd(LEVEL_VERBOSE, " total required: %u\n", list_size(bin->required)) : false;
+ bin->adjustment != NULL ? printd(LEVEL_VERBOSE, " total adjustment: %u\n", list_size(bin->adjustment)) : false;
+ bin->section != NULL ? printd(LEVEL_VERBOSE, " total sections: %u\n", list_size(bin->section)) : false;
+ bin->output != NULL ? printd(LEVEL_VERBOSE, " total outputs: %u\n", list_size(bin->output)) : false;
+ printd(LEVEL_VERBOSE, " total words: 0x%04X\n", list_size(&bin->words));
+ list_iterator_start(&bin->words);
+ while (list_iterator_hasnext(&bin->words))
+ printd(LEVEL_VERBOSE, " 0x%04X\n", *(uint16_t*)list_iterator_next(&bin->words));
+ list_iterator_stop(&bin->words);
+ printd(LEVEL_VERBOSE, " \n");
+ }
+}
+
+///
+/// Flattens all of the current bins into a single contigious
+/// bin.
+///
+void bins_flatten(freed_bstring name)
+{
+ struct lconv_entry* entry;
+ struct ldbin* target;
+ struct ldbin* bin;
+ bstring start, desired;
+ size_t i;
+
+ // Create the output bin.
+ target = bin_create(name, false);
+ target->provided = list_create();
+ target->required = list_create();
+ target->adjustment = list_create();
+ target->output = list_create();
+
+ // Loop through all of the current bins and evaluate them.
+ list_iterator_start(&ldbins.bins);
+ while (list_iterator_hasnext(&ldbins.bins))
+ {
+ bin = list_iterator_next(&ldbins.bins);
+
+ list_iterator_start(bin->output);
+ while (list_iterator_hasnext(bin->output))
+ {
+ entry = list_iterator_next(bin->output);
+
+ printd(LEVEL_DEBUG, "%s: will output %s at 0x%4X\n", bin->name->data, entry->label->data, entry->address);
+ }
+ list_iterator_stop(bin->output);
+
+ // Skip if the name begins with SECTION.
+ start = bmidstr(bin->name, 0, 8);
+ if (biseqcstr(start, "SECTION "))
+ {
+ bdestroy(start);
+ continue;
+ }
+ bdestroy(start);
+
+ // Move all of the code from this bin into the
+ // created bin.
+ bin_move(target, bin, list_size(&target->words), 0, list_size(&bin->words));
+
+ }
+ list_iterator_stop(&ldbins.bins);
+
+ // Sort the output bins in *reverse* order since we want
+ // to insert the last output first.
+ list_sort(target->output, -1);
+
+ // Search for all of the output entries in the flattened
+ // output bin.
+ list_iterator_start(target->output);
+ while (list_iterator_hasnext(target->output))
+ {
+ entry = list_iterator_next(target->output);
+
+ // Find the section that matches.
+ desired = bfromcstr("SECTION ");
+ bconcat(desired, entry->label);
+ bin = list_seek(&ldbins.bins, desired);
+
+ // TODO: Throw a proper error.
+ assert(bin != NULL);
+
+ // Insert the required code.
+ bin_insert(target, bin, entry->address, 0, list_size(&bin->words));
+ }
+ list_iterator_stop(target->output);
+
+ // Delete all of the bins.
+ // TODO: Free data stored in the list before clearing.
+ //for (i = list_size(&ldbins.bins) - 1; i >= 0; i--)
+ // bin_destroy(list_get_at(&ldbins.bins, i));
+ list_clear(&ldbins.bins);
+
+ // Add the flattened bin to the list of bins.
+ list_append(&ldbins.bins, target);
+
+ // Print result information.
+ for (i = 0; i < list_size(&ldbins.bins); i++)
+ {
+ bin = list_get_at(&ldbins.bins, i);
+ printd(LEVEL_VERBOSE, "flattened bin: %s\n", bin->name->data);
+ bin->provided != NULL ? printd(LEVEL_VERBOSE, " total provided: %u\n", list_size(bin->provided)) : false;
+ bin->required != NULL ? printd(LEVEL_VERBOSE, " total required: %u\n", list_size(bin->required)) : false;
+ bin->adjustment != NULL ? printd(LEVEL_VERBOSE, " total adjustment: %u\n", list_size(bin->adjustment)) : false;
+ bin->section != NULL ? printd(LEVEL_VERBOSE, " total sections: %u\n", list_size(bin->section)) : false;
+ bin->output != NULL ? printd(LEVEL_VERBOSE, " total outputs: %u\n", list_size(bin->output)) : false;
+ printd(LEVEL_VERBOSE, " total words: 0x%04X\n", list_size(&bin->words));
+ list_iterator_start(&bin->words);
+ while (list_iterator_hasnext(&bin->words))
+ printd(LEVEL_VERBOSE, " 0x%04X\n", *(uint16_t*)list_iterator_next(&bin->words));
+ list_iterator_stop(&bin->words);
+ printd(LEVEL_VERBOSE, " \n");
+ }
+}
+
+///
+/// Resolves all of the required and provided labels in a program. The bins
+/// must be flattened at this point.
+///
+/// @param Whether the provided label entries should be kept in the flattened
+/// bin for re-exporting (for example in static libraries).
+///
+void bins_resolve(bool keepProvided)
+{
+ struct lconv_entry* required;
+ struct lconv_entry* provided;
+ struct ldbin* bin;
+ uint16_t* word;
+ size_t i;
+
+ // Get the first bin.
+ assert(list_size(&ldbins.bins) == 1);
+ bin = list_get_at(&ldbins.bins, 0);
+
+ // Iterator over all required values.
+ list_iterator_start(bin->required);
+ while (list_iterator_hasnext(bin->required))
+ {
+ // Get the required / provided matching labels.
+ required = list_iterator_next(bin->required);
+ provided = list_seek(bin->provided, required->label);
+
+ // TODO: Throw a proper error.
+ assert(required != NULL);
+ if (provided == NULL)
+ {
+ printd(LEVEL_ERROR, "could not find label %s.\n", required->label->data);
+ exit(1);
+ }
+
+ // Insert the required code.
+ word = list_get_at(&bin->words, required->address);
+ *word = provided->address;
+
+ printd(LEVEL_DEBUG, "resolve: %s (0x%4X) -> 0x%4X\n", required->label->data, required->address, provided->address);
+ }
+ list_iterator_stop(bin->required);
+
+ // Delete all of the required entries.
+ while (list_size(bin->required) > 0)
+ {
+ required = list_extract_at(bin->required, 0);
+ bdestroy(required->label);
+ free(required);
+ }
+
+ if (!keepProvided)
+ {
+ // Delete all of the provided entries.
+ while (list_size(bin->provided) > 0)
+ {
+ provided = list_extract_at(bin->provided, 0);
+ bdestroy(provided->label);
+ free(provided);
+ }
+ }
+
+ // Print result information.
+ for (i = 0; i < list_size(&ldbins.bins); i++)
+ {
+ bin = list_get_at(&ldbins.bins, i);
+ printd(LEVEL_VERBOSE, "resolved bin: %s\n", bin->name->data);
+ bin->provided != NULL ? printd(LEVEL_VERBOSE, " total provided: %u\n", list_size(bin->provided)) : false;
+ bin->required != NULL ? printd(LEVEL_VERBOSE, " total required: %u\n", list_size(bin->required)) : false;
+ bin->adjustment != NULL ? printd(LEVEL_VERBOSE, " total adjustment: %u\n", list_size(bin->adjustment)) : false;
+ bin->section != NULL ? printd(LEVEL_VERBOSE, " total sections: %u\n", list_size(bin->section)) : false;
+ bin->output != NULL ? printd(LEVEL_VERBOSE, " total outputs: %u\n", list_size(bin->output)) : false;
+ printd(LEVEL_VERBOSE, " total words: 0x%04X\n", list_size(&bin->words));
+ list_iterator_start(&bin->words);
+ while (list_iterator_hasnext(&bin->words))
+ printd(LEVEL_VERBOSE, " 0x%04X\n", *(uint16_t*)list_iterator_next(&bin->words));
+ list_iterator_stop(&bin->words);
+ printd(LEVEL_VERBOSE, " \n");
+ }
+}
View
33 dtld/ldbins.h
@@ -0,0 +1,33 @@
+/**
+
+ File: ldbins.h
+
+ Project: DCPU-16 Toolchain
+ Component: Linker
+
+ Authors: James Rhodes
+
+ Description: Provides a section bin list upon which operations
+ can then be performed.
+
+**/
+
+#ifndef __DCPU_LD_BINS_H
+#define __DCPU_LD_BINS_H
+
+#include <stdint.h>
+#include <bstring.h>
+#include <lprov.h>
+#include <dcpu.h>
+#include "ldbin.h"
+
+void bins_init();
+struct ldbin* bins_add(freed_bstring name, struct lprov_entry* provided, struct lprov_entry* required, struct lprov_entry* adjustment, struct lprov_entry* section, struct lprov_entry* output);
+bool bins_load(freed_bstring path);
+void bins_save(freed_bstring name, freed_bstring path);
+bool bins_write(freed_bstring name, uint16_t word);
+void bins_sectionize();
+void bins_flatten(freed_bstring name);
+void bins_resolve(bool keepProvided);
+
+#endif
View
91 dtld/ldconv.c
@@ -0,0 +1,91 @@
+/**
+
+ File: ldconv.c
+
+ Project: DCPU-16 Toolchain
+ Component: Linker
+
+ Authors: James Rhodes
+
+ Description: Converts object format structures to linked lists
+ so that they can be easily modified and cloned.
+
+**/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <bstring.h>
+#include <simclist.h>
+#include <lprov.h>
+#include "ldconv.h"
+
+size_t lconv_entry_meter(const void* el)
+{
+ return sizeof(struct lconv_entry);
+}
+
+int lconv_entry_comparator(const void* a, const void* b)
+{
+ struct lconv_entry* ea = (struct lconv_entry*)a;
+ struct lconv_entry* eb = (struct lconv_entry*)b;
+ if (ea->address > eb->address)
+ return -1;
+ else if (ea->address == eb->address)
+ return 0;
+ else
+ return 1;
+}
+
+int lconv_entry_seeker(const void* e, const void* name)
+{
+ struct lconv_entry* el = (struct lconv_entry*)e;
+ if (el->label == NULL) return 0;
+ if (biseq(el->label, (bstring)name))
+ return 1;
+ else
+ return 0;
+}
+
+list_t* list_create()
+{
+ list_t* list = malloc(sizeof(list_t));
+ list_init(list);
+ list_attributes_copy(list, &lconv_entry_meter, 1);
+ list_attributes_comparator(list, &lconv_entry_comparator);
+ list_attributes_seeker(list, &lconv_entry_seeker);
+ return list;
+}
+
+list_t* list_convert(struct lprov_entry* first)
+{
+ struct lconv_entry* entry;
+ list_t* list = malloc(sizeof(list_t));
+ list_init(list);
+ list_attributes_copy(list, &lconv_entry_meter, 1);
+ list_attributes_comparator(list, &lconv_entry_comparator);
+ list_attributes_seeker(list, &lconv_entry_seeker);
+ while (first != NULL)
+ {
+ entry = malloc(sizeof(struct lconv_entry));
+ entry->address = first->address;
+ entry->label = bfromcstr(first->label);
+ list_append(list, entry);
+ free(entry);
+ first = first->next;
+ }
+ return list;
+}
+
+list_t* list_clone(list_t* original)
+{
+ list_t* list = malloc(sizeof(list_t));
+ list_init(list);
+ list_attributes_copy(list, &lconv_entry_meter, 1);
+ list_attributes_comparator(list, &lconv_entry_comparator);
+ list_attributes_seeker(list, &lconv_entry_seeker);
+ list_iterator_start(original);
+ while (list_iterator_hasnext(original))
+ list_append(list, list_iterator_next(original));
+ list_iterator_stop(original);
+ return list;
+}
View
32 dtld/ldconv.h
@@ -0,0 +1,32 @@
+/**
+
+ File: ldconv.h
+
+ Project: DCPU-16 Toolchain
+ Component: Linker
+
+ Authors: James Rhodes
+
+ Description: Converts object format structures to linked lists
+ so that they can be easily modified and cloned.
+
+**/
+
+#ifndef __DCPU_LD_CONV_H
+#define __DCPU_LD_CONV_H
+
+#include <bstring.h>
+#include <simclist.h>
+#include <lprov.h>
+
+struct lconv_entry
+{
+ bstring label;
+ uint16_t address;
+};
+
+list_t* list_create();
+list_t* list_convert(struct lprov_entry* first);
+list_t* list_clone(list_t* original);
+
+#endif
View
226 dtld/main.c
@@ -16,22 +16,16 @@
#include <string.h>
#include <argtable2.h>
#include <version.h>
+#include <debug.h>
#include "objfile.h"
#include "lprov.h"
#include "ldata.h"
+#include "ldbins.h"
int main(int argc, char* argv[])
{
// Define our variables.
- FILE* in;
- FILE* out;
int nerrors, i;
- char* test;
- uint16_t offset, current, store, mem_index;
- struct lprov_entry* required = NULL;
- struct lprov_entry* provided = NULL;
- struct lprov_entry* adjustment = NULL;
- struct lprov_entry* temp = NULL;
bstring target;
// Define arguments.
@@ -51,14 +45,14 @@ int main(int argc, char* argv[])
if (show_help->count != 0)
arg_print_errors(stdout, end, "linker");
- printf("syntax:\n dtld");
- arg_print_syntax(stdout, argtable, "\n");
- printf("options:\n");
- arg_print_glossary(stdout, argtable, " %-25s %s\n");
+ printd(LEVEL_DEFAULT, "syntax:\n dtld");
+ arg_print_syntax(stderr, argtable, "\n");
+ printd(LEVEL_DEFAULT, "options:\n");
+ arg_print_glossary(stderr, argtable, " %-25s %s\n");
arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
return 1;
}
-
+
// Check to make sure target is correct.
if (target_arg->count == 0)
target = bfromcstr("image");
@@ -68,209 +62,27 @@ int main(int argc, char* argv[])
target = bfromcstr("image");
else if (strcmp(target_arg->sval[0], "static") == 0)
target = bfromcstr("static");
- else
+ else
{
// Invalid option.
- fprintf(stderr, "linker: invalid target type, must be 'image' or 'static'.\n");
+ printd(LEVEL_ERROR, "linker: invalid target type, must be 'image' or 'static'.\n");
arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
return 1;
}
}
- // Open the output file for writing.
- out = fopen(output_file->filename[0], "wb");
-
- if (out == NULL)
- {
- // Handle the error.
- fprintf(stderr, "linker: unable to write to output file.\n");
- arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
- return 1;
- }
-
- // We initially need to get a list of ALL provided
- // labels before we can start replacing them.
- offset = 0;
-
- for (i = 0; i < input_files->count; i++)
- {
- // Open the input file.
- in = fopen(input_files->filename[i], "rb");
-
- if (in == NULL)
- {
- // Handle the error.
- fprintf(stderr, "linker: unable to read input file '%s'.\n", input_files->filename[i]);
- fclose(out);
- arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
- return 1;
- }
-
- // Is this the object format?
- test = malloc(strlen(ldata_objfmt) + 1);
- memset(test, 0, strlen(ldata_objfmt) + 1);
- fread(test, 1, strlen(ldata_objfmt), in);
- fseek(in, 1, SEEK_CUR);
-
- if (strcmp(test, ldata_objfmt) != 0)
- {
- // Handle the error.
- fprintf(stderr, "linker: input file '%s' is not in object format 1.0.\n", input_files->filename[i]);
- fclose(in);
- fclose(out);
- arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
- return 1;
- }
-
- free(test);
-
- // Load only the provided label entries into memory.
- objfile_load(input_files->filename[i], in, &offset, &provided, NULL, NULL);
-
- // Close the file.
- fclose(in);
- }
-
- // Now we can load in all of the adjustment and required
- // labels.
- offset = 0;
-
+ // Load all passed objects and use linker bin system to
+ // produce result.
+ bins_init();
for (i = 0; i < input_files->count; i++)
- {
- // Open the input file.
- in = fopen(input_files->filename[i], "rb");
-
- if (in == NULL)
- {
- // Handle the error.
- fprintf(stderr, "linker: unable to read input file '%s'.\n", input_files->filename[i]);
- fclose(out);
- arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
- return 1;
- }
-
- // Skip over the object format label; we already tested
- // for this in phase 1.
- fseek(in, strlen(ldata_objfmt) + 1, SEEK_CUR);
-
- // Load the required and adjustment entries into memory.
- objfile_load(input_files->filename[i], in, &offset, NULL, &required, &adjustment);
-
- // Close the file.
- fclose(in);
- }
-
- // If we are generating a static library, we want to generate our linker
- // table for the static library (so it becomes it's own object file).
- if (biseqcstr(target, "static"))
- {
- // Write linker table (except for required values since these
- // will have already been provided).
- fwrite(ldata_objfmt, 1, strlen(ldata_objfmt) + 1, out);
- objfile_save(out, provided, NULL, adjustment);
- }
-
- // Now we can start replacing the labels with the provided values
- // since we have ALL of the provided labels available.
- offset = 0;
-
- for (i = 0; i < input_files->count; i++)
- {
- // Open the input file.
- in = fopen(input_files->filename[i], "rb");
-
- if (in == NULL)
- {
- // Handle the error.
- fprintf(stderr, "linker: unable to read input file '%s'.\n", input_files->filename[i]);
- fclose(out);
- arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
- return 1;
- }
-
- // Skip over the object format label; we already tested
- // for this in phase 1.
- fseek(in, strlen(ldata_objfmt) + 1, SEEK_CUR);
-
- // Skip over the linker table.
- current = offset;
- objfile_load(input_files->filename[i], in, &offset, NULL, NULL, NULL);
-
- // Copy all of the input file's data into the output
- // file, word by word.
- mem_index = 0;
- fprintf(stderr, "BEGIN %s\n", input_files->filename[i]);
-
- while (!feof(in))
- {
- // Read a word.
- fread(&store, sizeof(uint16_t), 1, in);
-
- // For some strange reason, the last two bytes get
- // written twice, as if it's only EOF after you
- // attempt to read past the end again. I'm not sure
- // why the semantics are like this, but checking again
- // for EOF here prevents us writing double.
- if (feof(in))
- break;
-
- // Check to see if we need to do something with this
- // word, such as adjusting it.
- if (lprov_find_by_address(adjustment, mem_index) != NULL)
- {
- // We need to adjust this word by the offset.
- store += current;
- fprintf(stderr, "ADJUSTED 0x%04X: 0x%04X -> 0x%04X\n", mem_index, store - current, store);
- }
-
- // Check to see if we need to resolve this word into
- // an actual address because it was imported.
- temp = lprov_find_by_address(required, mem_index);
-
- if (temp != NULL)
- {
- // Find the position we should change this to.
- temp = lprov_find_by_label(provided, temp->label);
-
- // Ensure that temp is not NULL, if it is, then we couldn't
- // resolve this entry.
- if (temp == NULL)
- {
- temp = lprov_find_by_address(required, mem_index);
- fprintf(stderr, "NOT FOUND! 0x%04X: 0x%04X -> %s ???\n", mem_index, store, temp->label);
- fclose(out);
- arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
- return 1;
- }
-
- // We need to set this word to the proper location.
- fprintf(stderr, "RESOLVED 0x%04X: 0x%04X -> 0x%04X\n", mem_index, store, temp->address);
- store = temp->address;
- }
-
- // Now write the (potentially modified) word to the
- // output.
- fprintf(stderr, " >> WRITE 0x%04X\n", store);
- fwrite(&store, sizeof(uint16_t), 1, out);
-
- // Increment memory position.
- mem_index++;
- }
-
- // Close the file.
- fclose(in);
-
- // Reset and free the required and adjustment linked list.
- // FIXME: Actually free the lists!
- required = NULL;
- adjustment = NULL;
- }
-
- // Close file.
- fprintf(stderr, "linker: completed successfully.\n", input_files->filename[i]);
- fclose(out);
+ bins_load(bautofree(bfromcstr(input_files->filename[i])));
+ bins_sectionize();
+ bins_flatten(bautofree(bfromcstr("output")));
+ // TODO: This is where we would perform short literal optimizations
+ // with bins_compress(); when it's implemented.
+ bins_resolve(biseqcstr(target, "static") == true);
+ bins_save(bautofree(bfromcstr("output")), bautofree(bfromcstr(output_file->filename[0])));
- arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0]));
return 0;
}
View
141 libdcpu-ci-lang-c/nodes/NDeclarations.cpp 100644 → 100755
@@ -20,66 +20,63 @@ AsmBlock* NDeclarations::compile(AsmGenerator& context)
{
AsmBlock* block = new AsmBlock();
+ // Import bootstrap data.
+ *block << ".IMPORT _stack_caller_init" << std::endl;
+ *block << ".IMPORT _stack_callee_return" << std::endl;
+ *block << ".IMPORT _halt" << std::endl;
+ *block << ".IMPORT _halt_debug" << std::endl;
+
// Add file and line information.
*block << this->getFileAndLineState();
// Tell the generator that we are the root.
context.m_RootNode = this;
- if (context.m_IsEntryPointMode)
- {
- // First deal with the main setup.
- NFunctionDeclaration* main = (NFunctionDeclaration*)context.getFunction("main");
-
- if (main == NULL)
- throw new CompilerException(this->line, this->file, "Called function was not found 'main'.");
-
-
- // Output assembly for calling global data initializer.
- *block << " SET PC, _data_init" << std::endl;
+ // Create the global data frame.
+ StackMap* map = new StackMap();
- // Create the global data frame.
- StackMap* map = new StackMap();
-
- for (DeclarationList::iterator i = this->definitions.begin(); i != this->definitions.end(); i++)
- {
- if ((*i)->cType != "statement-declaration-variable")
- continue;
-
- map->insert(map->end(), StackPair(((NVariableDeclaration*)(*i))->id.name, ((NVariableDeclaration*)(*i))->type));
- }
+ for (DeclarationList::iterator i = this->definitions.begin(); i != this->definitions.end(); i++)
+ {
+ if ((*i)->cType != "statement-declaration-variable")
+ continue;
- context.m_GlobalFrame = new StackFrame(context, *map);
+ map->insert(map->end(), StackPair(((NVariableDeclaration*)(*i))->id.name, ((NVariableDeclaration*)(*i))->type));
+ }
- // Output the global data storage area.
- *block << std::endl;
- *block << ":_DATA" << std::endl;
+ context.m_GlobalFrame = new StackFrame(context, *map);
- for (DeclarationList::iterator i = this->definitions.begin(); i != this->definitions.end(); i++)
- {
- if ((*i)->cType != "statement-declaration-variable")
- continue;
+ // Output the global data storage area.
+ *block << std::endl;
+ *block << ":_DATA" << std::endl;
- // Calculate size.
- unsigned int size = ((NVariableDeclaration*)(*i))->type->getWordSize(context);
+ for (DeclarationList::iterator i = this->definitions.begin(); i != this->definitions.end(); i++)
+ {
+ if ((*i)->cType != "statement-declaration-variable")
+ continue;
- // We can't have types with 0 word storage in the global scope.
- if (size <= 0)
- throw new CompilerException(this->line, this->file, "Unable to store global variable with a type that has size of 0 words.");
+ // Calculate size.
+ unsigned int size = ((NVariableDeclaration*)(*i))->type.getWordSize(context);
- // Output zero'd data sections.
- *block << " DAT 0";
+ // We can't have types with 0 word storage in the global scope.
+ if (size <= 0)
+ throw new CompilerException(this->line, this->file, "Unable to store global variable with a type that has size of 0 words.");
- for (unsigned int b = 1; b < size; b++)
- *block << ", 0";
+ // Output zero'd data sections.
+ *block << " DAT 0";
- *block << std::endl;
- }
+ for (unsigned int b = 1; b < size; b++)
+ *block << ", 0";
*block << std::endl;
+ }
+ *block << std::endl;
+
+ // If the assembler supports sections...
+ if (context.getAssembler().supportsSections)
+ {
// Output the block for initializing global data storage.
- *block << ":_data_init" << std::endl;
+ *block << ".SECTION INIT" << std::endl;
context.m_CurrentFrame = context.m_GlobalFrame; // So that the NVariableDeclaration compiles successfully.
for (DeclarationList::iterator i = this->definitions.begin(); i != this->definitions.end(); i++)
@@ -95,6 +92,26 @@ AsmBlock* NDeclarations::compile(AsmGenerator& context)
delete inner;
}
+ // Output the code section.
+ *block << ".SECTION CODE" << std::endl;
+ }
+ else
+ {
+ // Ensure we don't have any global variable initializers declared here.
+ for (DeclarationList::iterator i = this->definitions.begin(); i != this->definitions.end(); i++)
+ {
+ if ((*i)->cType != "statement-declaration-variable")
+ continue;
+
+ if (((NVariableDeclaration*)(*i))->initExpr != NULL)
+ throw new CompilerException(this->line, this->file, "Initializers not permitted on global variables for assemblers that don't support sections.");
+ }
+ }
+
+ // Deal with the main setup.
+ NFunctionDeclaration* main = (NFunctionDeclaration*)context.getFunction("main");
+ if (main != NULL)
+ {
// Get the stack table of main.
StackFrame* frame = context.generateStackFrame(main, false);
@@ -106,43 +123,19 @@ AsmBlock* NDeclarations::compile(AsmGenerator& context)
// Clean up frame.
context.finishStackFrame(frame);
-
- // Handle function definitions.
- for (DeclarationList::iterator i = this->definitions.begin(); i != this->definitions.end(); i++)
- {
- if ((*i)->cType == "statement-declaration-variable")
- continue;
-
- AsmBlock* inner = (*i)->compile(context);
- *block << *inner;
-
- if (inner != NULL)
- delete inner;
- }
}
- else
- {
- // Ensure we don't have any global variables declared here.
- for (DeclarationList::iterator i = this->definitions.begin(); i != this->definitions.end(); i++)
- {
- if ((*i)->cType != "statement-declaration-variable")
- continue;
- throw new CompilerException(this->line, this->file, "You can't currently define global variables in non-entry-point compilation units.");
- }
-
- // Handle function definitions.
- for (DeclarationList::iterator i = this->definitions.begin(); i != this->definitions.end(); i++)
- {
- if ((*i)->cType == "statement-declaration-variable")
- continue;
+ // Handle function definitions.
+ for (DeclarationList::iterator i = this->definitions.begin(); i != this->definitions.end(); i++)
+ {
+ if ((*i)->cType == "statement-declaration-variable")
+ continue;
- AsmBlock* inner = (*i)->compile(context);
- *block << *inner;
+ AsmBlock* inner = (*i)->compile(context);
+ *block << *inner;
- if (inner != NULL)
- delete inner;
- }
+ if (inner != NULL)
+ delete inner;
}
return block;
View
19 libdcpu-ci-lang/AsmGenerator.cpp 100644 → 100755
@@ -18,33 +18,16 @@
#include "AsmGenerator.h"
// Sets up the assembly generator.
-AsmGenerator::AsmGenerator(std::string target, bool entryPointMode)
+AsmGenerator::AsmGenerator(std::string target)
: m_CurrentFrame(NULL), m_RootNode(NULL)
{
// Get a references to the assembler.
Assembler::loadAll();
this->m_AssemblerTarget = Assembler::getAssembler(target);
- this->m_IsEntryPointMode = entryPointMode;
// Set the global frame to NULL as it doesn't
// exist until the NDeclarations root node is processed.
this->m_GlobalFrame = NULL;
-
- // Load bootstrap data.
- if (this->m_IsEntryPointMode)
- {
- std::ifstream bootstrap("bootstrap.asm");
- this->m_Preassembly << bootstrap;
- bootstrap.close();
- }
- else
- {
- this->m_Preassembly << ".IMPORT _stack_caller_init" << std::endl;
- this->m_Preassembly << ".IMPORT _stack_caller_init_overlap" << std::endl;
- this->m_Preassembly << ".IMPORT _stack_callee_return" << std::endl;
- this->m_Preassembly << ".IMPORT _halt" << std::endl;
- this->m_Preassembly << ".IMPORT _halt_debug" << std::endl;
- }
}
// Return the specified function or NULL if none is defined.
View
5 libdcpu-ci-lang/AsmGenerator.h
@@ -34,15 +34,12 @@ class AsmGenerator
static std::string getRandomString(std::string::size_type sz);
public:
- AsmBlock m_Preassembly;
- AsmBlock m_Postassembly;
StackFrame* m_CurrentFrame;
StackFrame* m_GlobalFrame;
IDeclarations* m_RootNode;
- bool m_IsEntryPointMode;
public:
- AsmGenerator(std::string asmtarget, bool entryPointMode);
+ AsmGenerator(std::string asmtarget);
IFunctionDeclaration* getFunction(std::string name);
StackFrame* generateStackFrame(IFunctionDeclaration* function, bool referenceOnly = true);
View
2  libdcpu-ci-lang/Assembler.cpp
@@ -29,7 +29,7 @@ void Assembler::loadAll()
else m_HasLoaded = true;
// Define assemblers.
- m_Assemblers.insert(entry("toolchain", new Assembler(true, false, true, true, true, true, true)));
+ m_Assemblers.insert(entry("toolchain", new Assembler(true, true, true, true, true, true, true)));
m_Assemblers.insert(entry("studio", new Assembler(false, false, true, false, false, false, false)));
m_Assemblers.insert(entry("organic", new Assembler(false, false, true, true, true, false, false)));
}
View
8 libdcpu-ci-lang/Assembler.h
@@ -33,8 +33,8 @@ class Assembler
// Whether the assembler supports the .BOUNDARY directive.
bool supportsSafetyBoundary;
- // Whether the assembler supports .DATA and .CODE sections.
- bool supportsDataSections;
+ // Whether the assembler supports .SECTION and .OUTPUT directives.
+ bool supportsSections;
// Whether the assembler supports the DAT instruction.
bool supportsDataInstruction;
@@ -63,14 +63,14 @@ class Assembler
static std::map<std::string, const Assembler*> m_Assemblers;
Assembler(
bool supportsSafetyBoundary,
- bool supportsDataSections,
+ bool supportsSections,
bool supportsDataIn