mirror of
https://github.com/uffejakobsen/acme.git
synced 2025-04-14 14:37:10 +00:00
Release 0.95.2: Changed "save labels" to "symbol list" in a lot of code, error messages and docs.
Added "!symbollist" alias for "!sl" pseudo opcode. Change in undocumented ("illegal") opcodes: ANC #8 now generates 0x0b instead of 0x2b (both opcodes do the same thing). Added experimental support for generating a report listing. Thanks to Johann Klasek for writing this extension patch. git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@40 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
parent
2a30237ac4
commit
af1bd69455
contrib
docs
examples/me
src
@ -3,6 +3,7 @@
|
||||
# new in version 4: added !warn, !error, !serious
|
||||
# new in version 5: changed mnemo colors
|
||||
# new in version 6: added !ifndef, !addr
|
||||
# new in version 7: added !symbollist
|
||||
|
||||
# define colors
|
||||
#
|
||||
@ -133,6 +134,7 @@
|
||||
"!zn" pseudo
|
||||
"!zone" pseudo
|
||||
"!sl" pseudo
|
||||
"!symbollist" pseudo
|
||||
"!src" pseudo
|
||||
"!source" pseudo
|
||||
"!bin" pseudo
|
||||
|
@ -89,7 +89,7 @@ WAI
|
||||
!to
|
||||
!source !src
|
||||
!binary !bin
|
||||
!sl
|
||||
!symbollist !sl
|
||||
!zone !zn
|
||||
!if
|
||||
!ifdef
|
||||
|
@ -73,12 +73,8 @@ Parameters: ANDVALUE: Any formula the value parser accepts, but it
|
||||
FILLVALUE: Any formula the value parser accepts. If it
|
||||
is omitted, a default value is used (currently 234,
|
||||
that's the 6502 CPU's NOP command).
|
||||
Examples: ; eliminate the 6502's JMP($xxff)-Bug:
|
||||
!align 1, 0 ; wait for even address
|
||||
Label !word Pointer
|
||||
|
||||
; align code to page border for speed increase
|
||||
!align 255, 0
|
||||
Examples: !align 255, 0 ; align to page (256 bytes)
|
||||
!align 63, 0 ; align to C64 sprite block (64 bytes)
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
@ -282,14 +278,15 @@ Examples: .backgroundcolor = 0 ; some local symbol
|
||||
.backgroundcolor = 3 ; => "Symbol already defined."
|
||||
|
||||
|
||||
Call: !sl FILENAME
|
||||
Purpose: Save all the global symbols to the given file after
|
||||
the assembly is finished. This table could be loaded
|
||||
during another assembly session using the "!source"
|
||||
pseudo opcode.
|
||||
Call: !symbollist FILENAME
|
||||
Purpose: Write a symbol list to the given file after assembly
|
||||
is finished. The list will contain all global symbols.
|
||||
This table could be loaded during another assembly
|
||||
session using the "!source" pseudo opcode.
|
||||
Parameters: FILENAME: A file name given in "..." quoting.
|
||||
Examples: !sl "Symbols.a" ; produce symbol dump after assembly
|
||||
!sl "global" ; produce symbol dump after assembly
|
||||
Aliases: "!sl"
|
||||
Examples: !sl "Symbols.a" ; produce symbol list after assembly
|
||||
!sl "global" ; produce symbol list after assembly
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
@ -12,6 +12,19 @@ platform used. There should be another help file in this archive
|
||||
outlining the platform specific changes.
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Section: New in release 0.95.2
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Changed "save labels" to "symbol list" in a lot of code, error
|
||||
messages and docs.
|
||||
Added "!symbollist" alias for "!sl" pseudo opcode.
|
||||
Change in undocumented ("illegal") opcodes: ANC #8 now generates 0x0b
|
||||
instead of 0x2b (both opcodes do the same thing).
|
||||
Added experimental support for generating a report listing. Thanks to
|
||||
Johann Klasek for writing this extension patch.
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Section: New in release 0.95.1
|
||||
----------------------------------------------------------------------
|
||||
|
@ -71,10 +71,6 @@ Found new "!for" syntax.
|
||||
When using the "-Wno-old-for" switch to disable the warning about
|
||||
the older syntax, the new syntax will trigger this warning.
|
||||
|
||||
Label dump file already chosen.
|
||||
The "!sl" command was given more than once (or in addition to the
|
||||
"--labeldump" command line option). Only use it once.
|
||||
|
||||
Label name not in leftmost column.
|
||||
A label definition has blanks before the label name.
|
||||
Imagine this source code:
|
||||
@ -118,6 +114,10 @@ Segment starts inside another one, overwriting it.
|
||||
Future versions of ACME might throw an error instead of a warning
|
||||
in this case.
|
||||
|
||||
Symbol list file name already chosen.
|
||||
The "!sl" command was given more than once (or in addition to the
|
||||
"--symbollist" command line option). Only use it once.
|
||||
|
||||
Used "!to" without file format indicator. Defaulting to "cbm".
|
||||
Now that "!to" can be given a file format keyword (either "plain"
|
||||
or "cbm"), using "cbm" as default seems inappropriate. It still
|
||||
@ -362,7 +362,7 @@ Value not yet defined.
|
||||
Section: Errors on closedown
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Cannot open label dump file "FILENAME".
|
||||
Cannot open symbol list file "FILENAME".
|
||||
Cannot open output file "FILENAME".
|
||||
Make sure the name doesn't contain wildcard characters and you
|
||||
have write access to the directory.
|
||||
|
@ -27,27 +27,31 @@ In release 0.89, more were added; and in 0.94.8, another one (lxa):
|
||||
| addressing mode |
|
||||
Mnemo | implied #8 8 8,x 16 16,x | performs:
|
||||
------+-------------------------------------+------------------------
|
||||
anc | -- 2b -- -- -- -- | A = A & arg, then C=N
|
||||
anc | -- 0b* -- -- -- -- | A = A & arg, then C=N
|
||||
asr | -- 4b -- -- -- -- | A = A & arg, then lsr
|
||||
arr | -- 6b -- -- -- -- | A = A & arg, then ror
|
||||
sbx | -- cb -- -- -- -- | X = (A & X) - arg
|
||||
dop | 80* 80 04 14 -- -- | skips next byte
|
||||
top | 0c* -- -- -- 0c 1c | skips next two bytes
|
||||
dop | 80** 80 04 14 -- -- | skips next byte
|
||||
top | 0c** -- -- -- 0c 1c | skips next two bytes
|
||||
jam | 02 -- -- -- -- -- | crash (wait for reset)
|
||||
lxa | -- ab** -- -- -- -- | A/X = (A | ??) & arg
|
||||
lxa | -- ab*** -- -- -- -- | A/X = (A | ??) & arg
|
||||
|
||||
Example:
|
||||
!cpu 6510 ; activate additional mnemonics...
|
||||
lax (some_zp_label,x) ; ...and use them. No, this
|
||||
dcp (other_zp_label),y ; example does not make sense.
|
||||
|
||||
*) Note that "dop" and "top" can be used with implied addressing, but
|
||||
*) Up until ACME version 0.95.1, anc#8 generated opcode 0x2b. Since
|
||||
ACME version 0.95.2, anc#8 generates opcode 0x0b. Both opcodes work
|
||||
the same way.
|
||||
|
||||
**) Note that "dop" and "top" can be used with implied addressing, but
|
||||
the generated opcodes are those for immediate and 16-bit absolute
|
||||
addressing, respectively. Using dop/top with x-indexed addressing
|
||||
might have its uses when timing is critical (crossing a page border
|
||||
adds a penalty cycle).
|
||||
|
||||
**) This opcode is said to first perform an ORA with an arbitrary(!)
|
||||
***) This opcode is said to first perform an ORA with an arbitrary(!)
|
||||
value, then do an AND with the given argument, then do a TAX.
|
||||
This means it is unstable and therefore useless - unless the given
|
||||
argument is zero, in which case it reliably clears both A and X.
|
||||
@ -70,10 +74,10 @@ Just for the sake of completeness: Here are all the remaining opcodes
|
||||
|
||||
Opcode| Description
|
||||
------+--------------------------------------------------------------
|
||||
0b | same as 2b anc #8
|
||||
12 | same as 02 and others jam CRASH
|
||||
1a | same as (*legal*) ea nop
|
||||
22 | same as 02 and others jam CRASH
|
||||
2b | same as 0b anc #8
|
||||
32 | same as 02 and others jam CRASH
|
||||
34 | same as 14 and others dop 8,x
|
||||
3a | same as (*legal*) ea nop
|
||||
|
@ -143,7 +143,7 @@ found in the file "AllPOs.txt". Here's just a short overview:
|
||||
!byte !word !24 !32 !fill !align
|
||||
...for directly placing values into the output file.
|
||||
|
||||
!zone !sl
|
||||
!zone !symbollist
|
||||
...for defining the scope of local symbols and saving global symbols.
|
||||
|
||||
!convtab !pet !raw !scr !scrxor !text
|
||||
@ -187,14 +187,16 @@ Available options are:
|
||||
This is more or less useless, because the help is also shown
|
||||
if ACME is run without any arguments at all.
|
||||
|
||||
-f, --format FORMAT select output format ("plain", "cbm" or "apple")
|
||||
-o, --outfile FILE select output file
|
||||
Output filename and format can also be given using the "!to"
|
||||
-f, --format FORMAT set output file format ("plain", "cbm" or "apple")
|
||||
-o, --outfile FILE set output file name
|
||||
Output file name and format can also be given using the "!to"
|
||||
pseudo opcode. If the format is not specified, "!to" defaults
|
||||
to "cbm", while the command line option defaults to "plain".
|
||||
|
||||
-l, --labeldump FILE select label dump file
|
||||
This can also be given using the "!sl" pseudo opcode.
|
||||
-l, --symbollist FILE set symbol list file name
|
||||
This can also be given using the "!symbollist"/"!sl" pseudo
|
||||
opcode. The switch was called "--labeldump" in older versions,
|
||||
that name still works, too.
|
||||
|
||||
--setpc NUMBER set program counter
|
||||
This can also be given in the source code using "* = NUMBER".
|
||||
|
@ -1,4 +1,4 @@
|
||||
;ACME 0.95
|
||||
;ACME 0.95.1
|
||||
|
||||
; Konstanten:
|
||||
FALSE = 0 ; Das Programm verläßt sich an etlichen Stellen
|
||||
@ -76,15 +76,15 @@
|
||||
texttop = $1210 ; Basic-Ende+1
|
||||
maxmem0 = $1212 ; Ende Bank 0
|
||||
basic = $12fd ; Basic-IRQ
|
||||
kernel_copyfont = $c027 ; Systemroutine, kopiert Font in VDC-RAM
|
||||
kernel_cls = $c142 ; Systemroutine, löscht Screen
|
||||
kernel_switchmode = $cd2e ; Systemroutine, switcht aktiven Monitor
|
||||
e_copyfont = $c027 ; Systemroutine, kopiert Font in VDC-RAM
|
||||
e_cls = $c142 ; Systemroutine, löscht Screen
|
||||
e_switchmode = $cd2e ; Systemroutine, switcht aktiven Monitor
|
||||
takt = $d030 ; 2 MHz ; register (**mark**)
|
||||
vdc = $d600 ; VDC
|
||||
reg = $d601
|
||||
conreg = $ff00 ; MMU-CR
|
||||
nmiend = $ff33 ; NMI-Ende
|
||||
primm = $ff7d ; Kernel
|
||||
primm = $ff7d ; Kernal
|
||||
open = $ffc0
|
||||
close = $ffc3
|
||||
chkin = $ffc6
|
||||
|
@ -512,12 +512,12 @@ init ldx repeatedtry ; first start ?
|
||||
stx addr($11e7)
|
||||
lda mode ; which mode ?
|
||||
bmi + ; if 40 then
|
||||
jsr kernel_switchmode ; switch mode
|
||||
jsr e_switchmode ; switch mode
|
||||
+ lda #111 ; DIN on
|
||||
sta D8502
|
||||
lda #%..##..##
|
||||
sta R8502
|
||||
jsr kernel_copyfont
|
||||
jsr e_copyfont
|
||||
lda #47 ; DIN off
|
||||
sta D8502
|
||||
lda #<addfont1_start ; adjust font...
|
||||
@ -744,7 +744,7 @@ gonot rts ; fixme - could save a byte here
|
||||
F_goout jsr willblost ; changes saved ?
|
||||
beq gonot
|
||||
F_gosys +bank15
|
||||
jsr kernel_cls ; CLS
|
||||
jsr e_cls ; CLS
|
||||
lda #0 ; '0' for
|
||||
sta locks ; 'CBM-Shift' on
|
||||
sta addr($0ac5) ; 'ASC/DIN' on
|
||||
|
@ -1,4 +1,4 @@
|
||||
CFLAGS = -O3 -Wall
|
||||
CFLAGS = -O3 -Wall -Wstrict-prototypes
|
||||
LIBS = -lm
|
||||
CC = gcc
|
||||
RM = rm
|
||||
|
@ -1,4 +1,4 @@
|
||||
CFLAGS = -Wall -s
|
||||
CFLAGS = -Wall -s -Wstrict-prototypes
|
||||
LIBS = -lm
|
||||
CC = gcc
|
||||
RM = rm
|
||||
|
@ -2,7 +2,7 @@
|
||||
# makefile for MingW
|
||||
#
|
||||
|
||||
CFLAGS = -O3 -Wall
|
||||
CFLAGS = -O3 -Wall -Wstrict-prototypes
|
||||
LIBS = -lm
|
||||
CC = gcc
|
||||
RM = rm
|
||||
|
@ -1,4 +1,4 @@
|
||||
CFLAGS = -O3 -mthrowback -mlibscl -Wall
|
||||
CFLAGS = -O3 -mthrowback -mlibscl -Wall -Wstrict-prototypes
|
||||
LIBS = -lm
|
||||
CC = gcc
|
||||
RM = rm
|
||||
|
121
src/acme.c
121
src/acme.c
@ -15,9 +15,9 @@
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#define RELEASE "0.95.1" // update before release (FIXME)
|
||||
#define RELEASE "0.95.2" // update before release (FIXME)
|
||||
#define CODENAME "Fenchurch" // update before release
|
||||
#define CHANGE_DATE "7 Jun" // update before release
|
||||
#define CHANGE_DATE "22 Nov" // update before release
|
||||
#define CHANGE_YEAR "2014" // update before release
|
||||
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/" // FIXME
|
||||
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME
|
||||
@ -49,12 +49,15 @@ static const char FILE_WRITETEXT[] = "w";
|
||||
static const char FILE_WRITEBINARY[] = "wb";
|
||||
// names for error messages
|
||||
static const char name_outfile[] = "output filename";
|
||||
static const char name_dumpfile[] = "label dump filename";
|
||||
static const char arg_symbollist[] = "symbol list filename";
|
||||
static const char arg_reportfile[] = "report filename";
|
||||
// long options
|
||||
#define OPTION_HELP "help"
|
||||
#define OPTION_FORMAT "format"
|
||||
#define OPTION_OUTFILE "outfile"
|
||||
#define OPTION_LABELDUMP "labeldump"
|
||||
#define OPTION_LABELDUMP "labeldump" // old
|
||||
#define OPTION_SYMBOLLIST "symbollist" // new
|
||||
#define OPTION_REPORT "report"
|
||||
#define OPTION_SETPC "setpc"
|
||||
#define OPTION_CPU "cpu"
|
||||
#define OPTION_INITMEM "initmem"
|
||||
@ -75,8 +78,9 @@ static int toplevel_src_count = 0;
|
||||
static signed long start_address = ILLEGAL_START_ADDRESS;
|
||||
static signed long fill_value = MEMINIT_USE_DEFAULT;
|
||||
static const struct cpu_type *default_cpu = NULL;
|
||||
const char *symboldump_filename = NULL;
|
||||
const char *symbollist_filename = NULL;
|
||||
const char *output_filename = NULL;
|
||||
const char *report_filename = NULL;
|
||||
// maximum recursion depth for macro calls and "!source"
|
||||
signed long macro_recursions_left = MAX_NESTING;
|
||||
signed long source_recursions_left = MAX_NESTING;
|
||||
@ -115,11 +119,13 @@ static void show_help_and_exit(void)
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h, --" OPTION_HELP " show this help and exit\n"
|
||||
" -f, --" OPTION_FORMAT " FORMAT select output format\n"
|
||||
" -o, --" OPTION_OUTFILE " FILE select output file\n"
|
||||
" -l, --" OPTION_LABELDUMP " FILE select label dump file\n"
|
||||
" -f, --" OPTION_FORMAT " FORMAT set output file format\n"
|
||||
" -o, --" OPTION_OUTFILE " FILE set output file name\n"
|
||||
" -r, --" OPTION_REPORT " FILE set report file name\n"
|
||||
" -l, --" OPTION_SYMBOLLIST " FILE set symbol list file name\n"
|
||||
" --" OPTION_LABELDUMP " (old name for --" OPTION_SYMBOLLIST ")\n"
|
||||
" --" OPTION_SETPC " NUMBER set program counter\n"
|
||||
" --" OPTION_CPU " CPU select target processor\n"
|
||||
" --" OPTION_CPU " CPU set target processor\n"
|
||||
" --" OPTION_INITMEM " NUMBER define 'empty' memory\n"
|
||||
" --" OPTION_MAXERRORS " NUMBER set number of errors before exiting\n"
|
||||
" --" OPTION_MAXDEPTH " NUMBER set recursion depth for macro calls and !src\n"
|
||||
@ -139,22 +145,49 @@ PLATFORM_OPTION_HELP
|
||||
}
|
||||
|
||||
|
||||
// initialise report struct
|
||||
static void report_init(struct report *report)
|
||||
{
|
||||
report->fd = NULL;
|
||||
report->asc_used = 0;
|
||||
report->bin_used = 0;
|
||||
report->last_input = NULL;
|
||||
}
|
||||
// open report file
|
||||
static int report_open(struct report *report, const char *filename)
|
||||
{
|
||||
report->fd = fopen(filename, FILE_WRITETEXT);
|
||||
if (report->fd == NULL) {
|
||||
fprintf(stderr, "Error: Cannot open report file \"%s\".\n", filename);
|
||||
return 1;
|
||||
}
|
||||
return 0; // success
|
||||
}
|
||||
// close report file
|
||||
static void report_close(struct report *report)
|
||||
{
|
||||
if (report->fd) {
|
||||
fclose(report->fd);
|
||||
report->fd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// error handling
|
||||
|
||||
// tidy up before exiting by saving symbol dump
|
||||
// tidy up before exiting by saving symbol list and close other output files
|
||||
int ACME_finalize(int exit_code)
|
||||
{
|
||||
FILE *fd;
|
||||
|
||||
if (symboldump_filename) {
|
||||
fd = fopen(symboldump_filename, FILE_WRITETEXT);
|
||||
report_close(report);
|
||||
if (symbollist_filename) {
|
||||
fd = fopen(symbollist_filename, FILE_WRITETEXT);
|
||||
if (fd) {
|
||||
symbols_dump_all(fd);
|
||||
symbols_list(fd);
|
||||
fclose(fd);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Error: Cannot open label dump file \"%s\".\n",
|
||||
symboldump_filename);
|
||||
fprintf(stderr, "Error: Cannot open symbol list file \"%s\".\n", symbollist_filename);
|
||||
exit_code = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
@ -221,9 +254,12 @@ static int perform_pass(void)
|
||||
// do passes until done (or errors occured). Return whether output is ready.
|
||||
static int do_actual_work(void)
|
||||
{
|
||||
int undefined_prev, // "NeedValue" errors of previous pass
|
||||
undefined_curr; // "NeedValue" errors of current pass
|
||||
struct report my_report;
|
||||
int undefined_prev, // "NeedValue" errors of previous pass
|
||||
undefined_curr; // "NeedValue" errors of current pass
|
||||
|
||||
report = &my_report; // let global pointer point to something
|
||||
report_init(report); // we must init struct before doing passes
|
||||
if (Process_verbosity > 1)
|
||||
puts("First pass.");
|
||||
pass_count = 0;
|
||||
@ -233,20 +269,33 @@ static int do_actual_work(void)
|
||||
// As long as the number of "NeedValue" errors is decreasing but
|
||||
// non-zero, keep doing passes.
|
||||
while (undefined_curr && (undefined_curr < undefined_prev)) {
|
||||
pass_count++;
|
||||
++pass_count;
|
||||
undefined_prev = undefined_curr;
|
||||
if (Process_verbosity > 1)
|
||||
puts("Further pass.");
|
||||
undefined_curr = perform_pass();
|
||||
}
|
||||
// If still errors (unsolvable by doing further passes),
|
||||
// perform additional pass to find and show them
|
||||
if (undefined_curr == 0)
|
||||
// any errors left?
|
||||
if (undefined_curr == 0) {
|
||||
// if listing report is wanted and there were no errors,
|
||||
// do another pass to generate listing report
|
||||
if (report_filename) {
|
||||
if (Process_verbosity > 1)
|
||||
puts("Extra pass to generate listing report.");
|
||||
if (report_open(report, report_filename) == 0) {
|
||||
++pass_count;
|
||||
perform_pass();
|
||||
report_close(report);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// There are still errors (unsolvable by doing further passes),
|
||||
// so perform additional pass to find and show them.
|
||||
if (Process_verbosity > 1)
|
||||
puts("Further pass needed to find error.");
|
||||
puts("Extra pass needed to find error.");
|
||||
ALU_throw_errors(); // activate error output (CAUTION - one-way!)
|
||||
pass_count++;
|
||||
++pass_count;
|
||||
perform_pass(); // perform pass, but now show "value undefined"
|
||||
return 0;
|
||||
}
|
||||
@ -372,8 +421,12 @@ static const char *long_option(const char *string)
|
||||
set_output_format();
|
||||
else if (strcmp(string, OPTION_OUTFILE) == 0)
|
||||
output_filename = cliargs_safe_get_next(name_outfile);
|
||||
else if (strcmp(string, OPTION_LABELDUMP) == 0)
|
||||
symboldump_filename = cliargs_safe_get_next(name_dumpfile);
|
||||
else if (strcmp(string, OPTION_LABELDUMP) == 0) // old
|
||||
symbollist_filename = cliargs_safe_get_next(arg_symbollist);
|
||||
else if (strcmp(string, OPTION_SYMBOLLIST) == 0) // new
|
||||
symbollist_filename = cliargs_safe_get_next(arg_symbollist);
|
||||
else if (strcmp(string, OPTION_REPORT) == 0)
|
||||
report_filename = cliargs_safe_get_next(arg_reportfile);
|
||||
else if (strcmp(string, OPTION_SETPC) == 0)
|
||||
set_starting_pc();
|
||||
else if (strcmp(string, OPTION_CPU) == 0)
|
||||
@ -383,8 +436,7 @@ static const char *long_option(const char *string)
|
||||
else if (strcmp(string, OPTION_MAXERRORS) == 0)
|
||||
max_errors = string_to_number(cliargs_safe_get_next("maximum error count"));
|
||||
else if (strcmp(string, OPTION_MAXDEPTH) == 0)
|
||||
macro_recursions_left = (source_recursions_left =
|
||||
string_to_number(cliargs_safe_get_next("recursion depth")));
|
||||
macro_recursions_left = (source_recursions_left = string_to_number(cliargs_safe_get_next("recursion depth")));
|
||||
// else if (strcmp(string, "strictsyntax") == 0)
|
||||
// strict_syntax = TRUE;
|
||||
else if (strcmp(string, OPTION_USE_STDOUT) == 0)
|
||||
@ -392,7 +444,8 @@ static const char *long_option(const char *string)
|
||||
PLATFORM_LONGOPTION_CODE
|
||||
else if (strcmp(string, OPTION_VERSION) == 0)
|
||||
show_version(TRUE);
|
||||
else return string;
|
||||
else
|
||||
return string;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -413,8 +466,11 @@ static char short_option(const char *argument)
|
||||
case 'o': // "-o" selects output filename
|
||||
output_filename = cliargs_safe_get_next(name_outfile);
|
||||
break;
|
||||
case 'l': // "-l" selects symbol dump filename
|
||||
symboldump_filename = cliargs_safe_get_next(name_dumpfile);
|
||||
case 'l': // "-l" selects symbol list filename
|
||||
symbollist_filename = cliargs_safe_get_next(arg_symbollist);
|
||||
break;
|
||||
case 'r': // "-r" selects report filename
|
||||
report_filename = cliargs_safe_get_next(arg_reportfile);
|
||||
break;
|
||||
case 'v': // "-v" changes verbosity
|
||||
Process_verbosity++;
|
||||
@ -473,8 +529,7 @@ int main(int argc, const char *argv[])
|
||||
// handle command line arguments
|
||||
cliargs_handle_options(short_option, long_option);
|
||||
// generate list of files to process
|
||||
cliargs_get_rest(&toplevel_src_count, &toplevel_sources,
|
||||
"No top level sources given");
|
||||
cliargs_get_rest(&toplevel_src_count, &toplevel_sources, "No top level sources given");
|
||||
// Init modules (most of them will just build keyword trees)
|
||||
ALU_init();
|
||||
Basics_init();
|
||||
|
@ -11,8 +11,9 @@
|
||||
|
||||
|
||||
// Variables
|
||||
extern const char *symboldump_filename;
|
||||
extern const char *symbollist_filename;
|
||||
extern const char *output_filename;
|
||||
extern const char *report_filename;
|
||||
// maximum recursion depth for macro calls and "!source"
|
||||
extern signed long macro_recursions_left;
|
||||
extern signed long source_recursions_left;
|
||||
|
@ -908,7 +908,7 @@ static void perform_ranged_fp(double (*fn)(double))
|
||||
|
||||
|
||||
// convert right-hand value from fp to int
|
||||
static void right_fp_to_int()
|
||||
static void right_fp_to_int(void)
|
||||
{
|
||||
RIGHT_INTVAL = RIGHT_FPVAL;
|
||||
RIGHT_FLAGS &= ~MVALUE_IS_FP;
|
||||
|
@ -6,6 +6,7 @@
|
||||
// 4 Oct 2006 Fixed a typo in a comment
|
||||
// 22 Nov 2007 Added warn_on_indented_labels
|
||||
// 2 Jun 2014 Added warn_on_old_for and warn_on_type_mismatch
|
||||
// 19 Nov 2014 Merged Johann Klasek's report listing generator patch
|
||||
#include <stdio.h>
|
||||
#include "platform.h"
|
||||
#include "acme.h"
|
||||
@ -107,6 +108,7 @@ int pass_undefined_count; // "NeedValue" type errors
|
||||
int pass_real_errors; // Errors yet
|
||||
signed long max_errors = MAXERRORS; // errors before giving up
|
||||
FILE *msg_stream = NULL; // set to stdout by --use-stdout
|
||||
struct report *report = NULL;
|
||||
|
||||
|
||||
// memory allocation stuff
|
||||
|
16
src/global.h
16
src/global.h
@ -3,12 +3,14 @@
|
||||
// Have a look at "acme.c" for further info
|
||||
//
|
||||
// Global stuff - things that are needed by several modules
|
||||
// 19 Nov 2014 Merged Johann Klasek's report listing generator patch
|
||||
#ifndef global_H
|
||||
#define global_H
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "config.h"
|
||||
|
||||
#define PSEUDO_OPCODE_PREFIX '!' // FIXME - this is not yet used consistently!
|
||||
@ -73,6 +75,20 @@ extern int pass_real_errors; // Errors yet
|
||||
extern signed long max_errors; // errors before giving up
|
||||
extern FILE *msg_stream; // set to stdout by --errors_to_stdout
|
||||
|
||||
// report stuff
|
||||
#define REPORT_ASCBUFSIZE 1024
|
||||
#define REPORT_BINBUFSIZE 9 // eight are shown, then "..."
|
||||
struct report {
|
||||
FILE *fd; // report file descriptor (NULL => no report)
|
||||
struct input *last_input;
|
||||
size_t asc_used;
|
||||
size_t bin_used;
|
||||
int bin_address; // address at start of bin_buf[]
|
||||
char asc_buf[REPORT_ASCBUFSIZE]; // source bytes
|
||||
char bin_buf[REPORT_BINBUFSIZE]; // output bytes
|
||||
};
|
||||
extern struct report *report;
|
||||
|
||||
// Macros for skipping a single space character
|
||||
#define SKIPSPACE() \
|
||||
do { \
|
||||
|
69
src/input.c
69
src/input.c
@ -3,6 +3,7 @@
|
||||
// Have a look at "acme.c" for further info
|
||||
//
|
||||
// Input stuff
|
||||
// 19 Nov 2014 Merged Johann Klasek's report listing generator patch
|
||||
#include "config.h"
|
||||
#include "alu.h"
|
||||
#include "dynabuf.h"
|
||||
@ -75,6 +76,61 @@ void Input_new_file(const char *filename, FILE *fd)
|
||||
Input_now->src.fd = fd;
|
||||
}
|
||||
|
||||
|
||||
// remember source code character for report generator
|
||||
#define IF_WANTED_REPORT_SRCCHAR(c) do { if (report->fd) report_srcchar(c); } while(0)
|
||||
static void report_srcchar(char new_char)
|
||||
{
|
||||
static char prev_char = '\0';
|
||||
int ii;
|
||||
char hex_address[5];
|
||||
char hexdump[2 * REPORT_BINBUFSIZE + 2]; // +2 for '.' and terminator
|
||||
|
||||
// if input has changed, insert explanation
|
||||
if (Input_now != report->last_input) {
|
||||
fprintf(report->fd, "\n; ******** Source: %s\n", Input_now->original_filename);
|
||||
report->last_input = Input_now;
|
||||
report->asc_used = 0; // clear buffer
|
||||
prev_char = '\0';
|
||||
}
|
||||
if ((prev_char == '\n' || prev_char == '\r')) {
|
||||
// this check makes empty lines screw up line numbers:
|
||||
// && new_char != '\n') {
|
||||
// line start after line break detected and EOS processed,
|
||||
// build report line:
|
||||
// show line number...
|
||||
fprintf(report->fd, "%6d ", Input_now->line_number - 1);
|
||||
// prepare outbytes' start address
|
||||
if (report->bin_used)
|
||||
snprintf(hex_address, 5, "%04x", report->bin_address);
|
||||
else
|
||||
hex_address[0] = '\0';
|
||||
// prepare outbytes
|
||||
hexdump[0] = '\0';
|
||||
for (ii = 0; ii < report->bin_used; ++ii)
|
||||
sprintf(hexdump + 2 * ii, "%02x", (unsigned int) (unsigned char) (report->bin_buf[ii]));
|
||||
// if binary buffer is full, overwrite last byte with "..."
|
||||
if (report->bin_used == REPORT_BINBUFSIZE)
|
||||
sprintf(hexdump + 2 * (REPORT_BINBUFSIZE - 1), "...");
|
||||
// show address and bytes
|
||||
fprintf(report->fd, "%-4s %-19s", hex_address, hexdump);
|
||||
// at this point the output should be a multiple of 8 characters
|
||||
// so far to preserve tabs of the source...
|
||||
if (report->asc_used == REPORT_ASCBUFSIZE)
|
||||
--report->asc_used;
|
||||
report->asc_buf[report->asc_used] = '\0';
|
||||
fprintf(report->fd, "%s\n", report->asc_buf); // show source line
|
||||
report->asc_used = 0; // reset buffers
|
||||
report->bin_used = 0;
|
||||
}
|
||||
if (new_char != '\n' && new_char != '\r') { // detect line break
|
||||
if (report->asc_used < REPORT_ASCBUFSIZE)
|
||||
report->asc_buf[report->asc_used++] = new_char;
|
||||
}
|
||||
prev_char = new_char;
|
||||
}
|
||||
|
||||
|
||||
// Deliver source code from current file (!) in shortened high-level format
|
||||
static char get_processed_from_file(void)
|
||||
{
|
||||
@ -85,6 +141,7 @@ static char get_processed_from_file(void)
|
||||
case INPUTSTATE_NORMAL:
|
||||
// fetch a fresh byte from the current source file
|
||||
from_file = getc(Input_now->src.fd);
|
||||
IF_WANTED_REPORT_SRCCHAR(from_file);
|
||||
// now process it
|
||||
/*FALLTHROUGH*/
|
||||
case INPUTSTATE_AGAIN:
|
||||
@ -147,9 +204,10 @@ static char get_processed_from_file(void)
|
||||
}
|
||||
case INPUTSTATE_SKIPBLANKS:
|
||||
// read until non-blank, then deliver that
|
||||
do
|
||||
do {
|
||||
from_file = getc(Input_now->src.fd);
|
||||
while ((from_file == CHAR_TAB) || (from_file == ' '));
|
||||
IF_WANTED_REPORT_SRCCHAR(from_file);
|
||||
} while ((from_file == CHAR_TAB) || (from_file == ' '));
|
||||
// re-process last byte
|
||||
Input_now->state = INPUTSTATE_AGAIN;
|
||||
break;
|
||||
@ -165,6 +223,7 @@ static char get_processed_from_file(void)
|
||||
|
||||
case INPUTSTATE_SKIPLF:
|
||||
from_file = getc(Input_now->src.fd);
|
||||
IF_WANTED_REPORT_SRCCHAR(from_file);
|
||||
// if LF, ignore it and fetch another byte
|
||||
// otherwise, process current byte
|
||||
if (from_file == CHAR_LF)
|
||||
@ -174,9 +233,10 @@ static char get_processed_from_file(void)
|
||||
break;
|
||||
case INPUTSTATE_COMMENT:
|
||||
// read until end-of-line or end-of-file
|
||||
do
|
||||
do {
|
||||
from_file = getc(Input_now->src.fd);
|
||||
while ((from_file != EOF) && (from_file != CHAR_CR) && (from_file != CHAR_LF));
|
||||
IF_WANTED_REPORT_SRCCHAR(from_file);
|
||||
} while ((from_file != EOF) && (from_file != CHAR_CR) && (from_file != CHAR_LF));
|
||||
// re-process last byte
|
||||
Input_now->state = INPUTSTATE_AGAIN;
|
||||
break;
|
||||
@ -236,6 +296,7 @@ char GetQuotedByte(void)
|
||||
} else {
|
||||
// fetch a fresh byte from the current source file
|
||||
from_file = getc(Input_now->src.fd);
|
||||
IF_WANTED_REPORT_SRCCHAR(from_file);
|
||||
switch (from_file) {
|
||||
case EOF:
|
||||
// remember to send an end-of-file
|
||||
|
@ -114,7 +114,7 @@ enum { IDX_BIT,IDX_ASL,IDX_ROL,IDX_LSR,IDX_ROR,IDX_STY,IDX_STX,IDX_L
|
||||
SCS misc_abs[] = { 0x2c24, 0x0e06, 0x2e26, 0x4e46, 0x6e66, 0x8c84, 0x8e86, 0xaca4, 0xaea6, 0xccc4, 0xece4, 0xcec6, 0xeee6, 0x0c04, 0x1c14, 0x2c24, 0xcec6, 0xeee6, 0x9c64, 0x02, 0, 0, 0xf400, 0, 0, 0, 0, 0x04, 0x0c00, 0, 0}; // $ff $ffff
|
||||
SCS misc_xabs[] = { 0, 0x1e16, 0x3e36, 0x5e56, 0x7e76, 0x94, 0, 0xbcb4, 0, 0, 0, 0xded6, 0xfef6, 0, 0, 0x3c34, 0xded6, 0xfef6, 0x9e74, 0, 0, 0, 0, 0, 0, 0, 0, 0x14, 0x1c00, 0, 0}; // $ff,x $ffff,x
|
||||
SCS misc_yabs[] = { 0, 0, 0, 0, 0, 0, 0x96, 0, 0xbeb6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // $ff,y $ffff,y
|
||||
SCB misc_imm[] = { 0, 0, 0, 0, 0, 0, 0, 0xa0, 0xa2, 0xc0, 0xe0, 0, 0, 0, 0, 0x89, 0, 0, 0, 0, 0xc2, 0xe2, 0, 0x2b, 0x4b, 0x6b, 0xcb, 0x80, 0, 0, 0xab}; // #$ff
|
||||
SCB misc_imm[] = { 0, 0, 0, 0, 0, 0, 0, 0xa0, 0xa2, 0xc0, 0xe0, 0, 0, 0, 0, 0x89, 0, 0, 0, 0, 0xc2, 0xe2, 0, 0x0b, 0x4b, 0x6b, 0xcb, 0x80, 0, 0, 0xab}; // #$ff
|
||||
SCB misc_impl[] = { 0, 0x0a, 0x2a, 0x4a, 0x6a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3a, 0x1a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0x0c, 0x02, 0}; // implied/accu
|
||||
|
||||
// Code tables for group GROUP_ALLJUMPS:
|
||||
|
19
src/output.c
19
src/output.c
@ -6,6 +6,7 @@
|
||||
// 24 Nov 2007 Added possibility to suppress segment overlap warnings
|
||||
// 25 Sep 2011 Fixed bug in !to (colons in filename could be interpreted as EOS)
|
||||
// 5 Mar 2014 Fixed bug where setting *>0xffff resulted in hangups.
|
||||
// 19 Nov 2014 Merged Johann Klasek's report listing generator patch
|
||||
#include <stdlib.h>
|
||||
//#include <stdio.h>
|
||||
#include <string.h> // for memset()
|
||||
@ -89,6 +90,16 @@ static struct node_t segment_modifiers[] = {
|
||||
};
|
||||
|
||||
|
||||
// report binary output
|
||||
static void report_binary(char value)
|
||||
{
|
||||
if (report->bin_used == 0)
|
||||
report->bin_address = out->write_idx; // remember address at start of line
|
||||
if (report->bin_used < REPORT_BINBUFSIZE)
|
||||
report->bin_buf[report->bin_used++] = value;
|
||||
}
|
||||
|
||||
|
||||
// set up new out->segment.max value according to the given address.
|
||||
// just find the next segment start and subtract 1.
|
||||
static void find_segment_max(intval_t new_pc)
|
||||
@ -138,6 +149,8 @@ static void real_output(intval_t byte)
|
||||
if (out->write_idx > out->highest_written)
|
||||
out->highest_written = out->write_idx;
|
||||
// write byte and advance ptrs
|
||||
if (report->fd)
|
||||
report_binary(byte & 0xff); // file for reporting, taking also CPU_2add
|
||||
out->buffer[out->write_idx++] = byte & 0xff;
|
||||
CPU_state.add_to_pc++;
|
||||
}
|
||||
@ -154,6 +167,8 @@ static void no_output(intval_t byte)
|
||||
|
||||
|
||||
// call this if really calling Output_byte would be a waste of time
|
||||
// FIXME - check all users of this, because future changes
|
||||
// ("several-projects-at-once") may be incompatible with this!
|
||||
void Output_fake(int size)
|
||||
{
|
||||
if (size < 1)
|
||||
@ -584,6 +599,10 @@ when encountering "* = VALUE":
|
||||
|
||||
Problem: always check for "undefined"; there are some problematic combinations.
|
||||
I need a way to return the size of a generated code block even if PC undefined.
|
||||
Maybe like this:
|
||||
* = new_address [, invisible] [, overlay] [, &size_symbol_ref {]
|
||||
...code...
|
||||
[} ; at end of block, size is written to size symbol given above!]
|
||||
*/
|
||||
|
||||
|
||||
|
23
src/symbol.c
23
src/symbol.c
@ -36,8 +36,8 @@ static void dump_one_symbol(struct node_ra_t *node, FILE *fd)
|
||||
// output name
|
||||
if (warn_on_type_mismatch
|
||||
&& symbol->result.addr_refs == 1)
|
||||
fprintf(fd, "!addr\t");
|
||||
fprintf(fd, "%s", node->id_string);
|
||||
fprintf(fd, "!addr");
|
||||
fprintf(fd, "\t%s", node->id_string);
|
||||
switch (symbol->result.flags & MVALUE_FORCEBITS) {
|
||||
case MVALUE_FORCE16:
|
||||
fprintf(fd, "+2\t= ");
|
||||
@ -169,7 +169,7 @@ static enum eos PO_set(void) // Now GotByte = illegal char
|
||||
}
|
||||
|
||||
|
||||
// Select dump file
|
||||
// set file name for symbol list
|
||||
static enum eos PO_sl(void)
|
||||
{
|
||||
// bugfix: first read filename, *then* check for first pass.
|
||||
@ -186,14 +186,14 @@ static enum eos PO_sl(void)
|
||||
if (pass_count)
|
||||
return SKIP_REMAINDER;
|
||||
|
||||
// if symbol dump file already chosen, complain and exit
|
||||
if (symboldump_filename) {
|
||||
Throw_warning("Label dump file already chosen.");
|
||||
// if symbol list file name already set, complain and exit
|
||||
if (symbollist_filename) {
|
||||
Throw_warning("Symbol list file name already chosen.");
|
||||
return SKIP_REMAINDER;
|
||||
}
|
||||
|
||||
// get malloc'd copy of filename
|
||||
symboldump_filename = DynaBuf_get_copy(GlobalDynaBuf);
|
||||
symbollist_filename = DynaBuf_get_copy(GlobalDynaBuf);
|
||||
// ensure there's no garbage at end of line
|
||||
return ENSURE_EOS;
|
||||
}
|
||||
@ -201,8 +201,9 @@ static enum eos PO_sl(void)
|
||||
|
||||
// predefined stuff
|
||||
static struct node_t pseudo_opcodes[] = {
|
||||
PREDEFNODE("set", PO_set),
|
||||
PREDEFLAST(s_sl, PO_sl),
|
||||
PREDEFNODE("set", PO_set),
|
||||
PREDEFNODE("symbollist", PO_sl),
|
||||
PREDEFLAST(s_sl, PO_sl),
|
||||
// ^^^^ this marks the last element
|
||||
};
|
||||
|
||||
@ -268,10 +269,10 @@ void symbol_define(intval_t value)
|
||||
|
||||
|
||||
// dump global symbols to file
|
||||
void symbols_dump_all(FILE *fd)
|
||||
void symbols_list(FILE *fd)
|
||||
{
|
||||
Tree_dump_forest(symbols_forest, ZONE_GLOBAL, dump_one_symbol, fd);
|
||||
PLATFORM_SETFILETYPE_TEXT(symboldump_filename);
|
||||
PLATFORM_SETFILETYPE_TEXT(symbollist_filename);
|
||||
}
|
||||
|
||||
|
||||
|
@ -41,7 +41,7 @@ extern struct symbol *symbol_find(zone_t, int flags);
|
||||
// name must be held in GlobalDynaBuf.
|
||||
extern void symbol_define(intval_t value);
|
||||
// dump global symbols to file
|
||||
extern void symbols_dump_all(FILE *fd);
|
||||
extern void symbols_list(FILE *fd);
|
||||
// fix name of anonymous forward label (held in GlobalDynaBuf, NOT TERMINATED!)
|
||||
// so it references the *next* anonymous forward label definition.
|
||||
extern void symbol_fix_forward_anon_name(int increment);
|
||||
|
Loading…
x
Reference in New Issue
Block a user