ACME release 0.96.4: Fixed bug in zero page wrap-around warnings. Added "!xor" pseudo op. Added "-I" CLI switch.

git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@97 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
marcobaye 2017-12-22 22:55:36 +00:00
parent f23a38de8c
commit 9628f69f4e
19 changed files with 251 additions and 61 deletions

View File

@ -798,6 +798,24 @@ Examples: !to "TinyDemo", cbm ; define output file + format
; Useful if you want to store your code in an EPROM.
Call: !xor EXPRESSION [ { BLOCK } ]
Purpose: Change the value to XOR all output bytes with (the
value defaults to zero on startup). This "encryption"
facility was added to compensate for the shortcomings
of the "!scrxor" pseudo opcode, which only XORs
strings and characters, but not numbers.
When used with block syntax, the previously chosen
value is restored afterwards.
Parameters: EXPRESSION: Any formula the value parser accepts.
BLOCK: A block of assembler statements.
Examples: ; first as normal screencodes:
!scr "Hello everybody...", GROUPLOGOCHAR
; and now as inverted screencodes:
!xor $80 {
!scr "Hello everybody...", GROUPLOGOCHAR
}
----------------------------------------------------------------------
Section: Offset assembly
----------------------------------------------------------------------

View File

@ -12,6 +12,20 @@ platform used. There should be another help file in this archive
outlining the platform specific changes.
----------------------------------------------------------------------
Section: New in release 0.96.4
----------------------------------------------------------------------
Bugfix: Removed warnings about zero page wrap-around for the 65816's
24-bit pointers (because wrap-around does not actually happen).
Thanks to Johann Klasek for reporting this.
Added "!xor" pseudo opcode to compensate for the shortcomings of the
"!scrxor" pseudo opcode. Thanks to spider-j for the initial bug
report.
Added "-I" CLI switch to add search paths for input files. Thanks to
peiselulli for the suggestion.
----------------------------------------------------------------------
Section: New in release 0.96.3
----------------------------------------------------------------------

View File

@ -161,8 +161,6 @@ Zeropage pointer wraps around from $ff to $00
A zeropage-indirect addressing mode uses $ff as the argument. The
6502 will then fetch the second pointer byte from $00 instead of
$0100, therefore this warning is issued.
With the 65816's three-byte pointers, this warning is also given
for $fe arguments.
...called from here.
If warnings and/or errors are output during a macro call, messages

View File

@ -6,7 +6,7 @@
- free software -
(C) 1998-2016 Marco Baye
(C) 1998-2017 Marco Baye
----------------------------------------------------------------------
@ -14,7 +14,7 @@ Section: Copyright
----------------------------------------------------------------------
ACME - a crossassembler for producing 6502/6510/65c02/65816 code.
Copyright (C) 1998-2016 Marco Baye
Copyright (C) 1998-2017 Marco Baye
The ACME icon was designed by Wanja "Brix" Gayk
This program is free software; you can redistribute it and/or modify

View File

@ -251,6 +251,12 @@ Available options are:
"-DSYSTEM=128" could build the C128 version of the software
(using conditional assembly in your source code file).
-I PATH/TO/DIR add search path for input files
This option allows to add a directory to the search list for
input files. If an input file cannot be found in the current
working directory, all directories in the search list are
tried (the first match is used).
-W fine-tune amount and type of warnings
-Wno-label-indent
Disables warnings about labels not being in the leftmost

View File

@ -15,6 +15,9 @@
// convert UNIX-style pathname to Amiga-style pathname (no change)
#define PLATFORM_CONVERTPATHCHAR(a) (a)
// directory separator for include paths
#define DIRECTORY_SEPARATOR '\0' // actually '/', but paths ending on ':' are ok, so auto-adding '/' is bad)
// string containing the prefix for accessing files from the library tree
#define PLATFORM_LIBPREFIX "progdir:acme_lib/"
#define NO_NEED_FOR_ENV_VAR

View File

@ -18,6 +18,9 @@
// convert UNIX-style pathname to DOS-style pathname
#define PLATFORM_CONVERTPATHCHAR(a) DOS_convert_path_char(a)
// directory separator for include paths
#define DIRECTORY_SEPARATOR '\\'
// string containing the prefix for accessing files from the library tree
#define PLATFORM_LIBPREFIX DOS_lib_prefix

View File

@ -17,6 +17,9 @@
// convert UNIX-style pathname to RISC OS-style pathname
#define PLATFORM_CONVERTPATHCHAR(a) RISCOS_convert_path_char(a)
// directory separator for include paths
#define DIRECTORY_SEPARATOR '\0' // actually '.', but paths ending on ':' are ok, so auto-adding '.' is bad)
// string containing the prefix for accessing files from the library tree
#define PLATFORM_LIBPREFIX "ACME_Lib:"
#define NO_NEED_FOR_ENV_VAR

View File

@ -15,6 +15,9 @@
// convert UNIX-style pathname to AnyOS-style pathname (no change)
#define PLATFORM_CONVERTPATHCHAR(a) (a)
// directory separator for include paths
#define DIRECTORY_SEPARATOR '/'
// string containing the prefix for accessing files from the library tree
#define PLATFORM_LIBPREFIX AnyOS_lib_prefix

View File

@ -131,6 +131,7 @@ static void show_help_and_exit(void)
" --" OPTION_MAXDEPTH " NUMBER set recursion depth for macro calls and !src\n"
" -vDIGIT set verbosity level\n"
" -DSYMBOL=VALUE define global symbol\n"
" -I PATH/TO/DIR add search path for input files\n"
// as long as there is only one -W option:
#define OPTIONWNO_LABEL_INDENT "no-label-indent"
" -W" OPTIONWNO_LABEL_INDENT " suppress warnings about indented labels\n"
@ -185,7 +186,7 @@ int ACME_finalize(int exit_code)
report_close(report);
if (symbollist_filename) {
fd = fopen(symbollist_filename, FILE_WRITETEXT);
fd = fopen(symbollist_filename, FILE_WRITETEXT); // FIXME - what if filename is given via !sl in sub-dir? fix path!
if (fd) {
symbols_list(fd);
fclose(fd);
@ -220,7 +221,7 @@ static void save_output_file(void)
fputs("No output file specified (use the \"-o\" option or the \"!to\" pseudo opcode).\n", stderr);
return;
}
fd = fopen(output_filename, FILE_WRITEBINARY);
fd = fopen(output_filename, FILE_WRITEBINARY); // FIXME - what if filename is given via !to in sub-dir? fix path!
if (fd == NULL) {
fprintf(stderr, "Error: Cannot open output file \"%s\".\n",
output_filename);
@ -488,17 +489,24 @@ static char short_option(const char *argument)
case 'D': // "-D" define constants
define_symbol(argument + 1);
goto done;
case 'h': // "-h" shows help
show_help_and_exit();
case 'f': // "-f" selects output format
set_output_format();
break;
case 'o': // "-o" selects output filename
output_filename = cliargs_safe_get_next(name_outfile);
case 'h': // "-h" shows help
show_help_and_exit();
break;
case 'I': // "-I" adds an include directory
if (argument[1])
includepaths_add(argument + 1);
else
includepaths_add(cliargs_safe_get_next("include path"));
goto done;
case 'l': // "-l" selects symbol list filename
symbollist_filename = cliargs_safe_get_next(arg_symbollist);
break;
case 'o': // "-o" selects output filename
output_filename = cliargs_safe_get_next(name_outfile);
break;
case 'r': // "-r" selects report filename
report_filename = cliargs_safe_get_next(arg_reportfile);
break;
@ -553,6 +561,7 @@ int main(int argc, const char *argv[])
PLATFORM_INIT;
// prepare a buffer large enough to hold pointers to "-D" switch values
// cli_defines = safe_malloc(argc * sizeof(*cli_defines));
includepaths_init(); // must be done before cli arg handling
// handle command line arguments
cliargs_handle_options(short_option, long_option);
// generate list of files to process

View File

@ -109,17 +109,10 @@ void encoding_passinit(void)
}
// try to load encoding table from given file
void encoding_load(char target[256], const char *filename)
void encoding_load_from_file(char target[256], FILE *stream)
{
FILE *fd = fopen(filename, FILE_READBINARY);
if (fd) {
if (fread(target, sizeof(char), 256, fd) != 256)
Throw_error("Conversion table incomplete.");
fclose(fd);
} else {
Throw_error(exception_cannot_open_input_file);
}
if (fread(target, sizeof(char), 256, stream) != 256)
Throw_error("Conversion table incomplete.");
}
// lookup encoder held in DynaBuf and return its struct pointer (or NULL on failure)

View File

@ -7,6 +7,9 @@
#define encoding_H
#include <stdio.h> // for FILE*
//struct encoder;
extern const struct encoder *encoder_current; // gets set before each pass TODO - set for each part
extern const struct encoder encoder_raw;
@ -23,7 +26,7 @@ extern char encoding_encode_char(char byte);
// set "raw" as default encoding
extern void encoding_passinit(void);
// try to load encoding table from given file
extern void encoding_load(char target[256], const char *filename);
extern void encoding_load_from_file(char target[256], FILE *stream);
// lookup encoder held in DynaBuf and return its struct pointer (or NULL on failure)
extern const struct encoder *encoding_find(void);

View File

@ -472,13 +472,16 @@ int Input_read_and_lower_keyword(void)
return length;
}
// Try to read a file name. If "allow_library" is TRUE, library access by using
// <...> quoting is possible as well. The file name given in the assembler
// source code is converted from UNIX style to platform style.
// Try to read a file name.
// If "allow_library" is TRUE, library access by using <...> quoting
// is possible as well. If "uses_lib" is non-NULL, info about library
// usage is stored there.
// The file name given in the assembler source code is converted from
// UNIX style to platform style.
// Returns whether error occurred (TRUE on error). Filename in GlobalDynaBuf.
// Errors are handled and reported, but caller should call
// Input_skip_remainder() then.
int Input_read_filename(int allow_library)
int Input_read_filename(int allow_library, int *uses_lib)
{
char *lib_prefix,
end_quote;
@ -487,6 +490,8 @@ int Input_read_filename(int allow_library)
SKIPSPACE();
// check for library access
if (GotByte == '<') {
if (uses_lib)
*uses_lib = 1;
// if library access forbidden, complain
if (allow_library == FALSE) {
Throw_error("Writing to library not supported.");
@ -506,6 +511,8 @@ int Input_read_filename(int allow_library)
DynaBuf_add_string(GlobalDynaBuf, lib_prefix);
end_quote = '>';
} else {
if (uses_lib)
*uses_lib = 0;
if (GotByte == '"') {
end_quote = '"';
} else {
@ -569,3 +576,77 @@ int Input_get_force_bit(void)
SKIPSPACE();
return force_bit;
}
// include path stuff - should be moved to its own file:
// ring list struct
struct ipi {
struct ipi *next,
*prev;
const char *path;
};
static struct ipi ipi_head; // head element
static struct dynabuf *pathbuf; // buffer to combine search path and file spec
// init list
void includepaths_init(void)
{
// init ring list
ipi_head.next = &ipi_head;
ipi_head.prev = &ipi_head;
// init dynabuf
pathbuf = DynaBuf_create(256);
}
// add entry
void includepaths_add(const char *path)
{
struct ipi *ipi;
ipi = safe_malloc(sizeof(*ipi));
ipi->path = path;
ipi->next = &ipi_head;
ipi->prev = ipi_head.prev;
ipi->next->prev = ipi;
ipi->prev->next = ipi;
}
// open file for reading (trying list entries as prefixes)
// "uses_lib" tells whether to access library or to make use of include paths
// file name is expected in GlobalDynaBuf
FILE *includepaths_open_ro(int uses_lib)
{
FILE *stream;
struct ipi *ipi;
// first try directly, regardless of whether lib or not:
stream = fopen(GLOBALDYNABUF_CURRENT, FILE_READBINARY);
// if failed and not lib, try include paths:
if ((stream == NULL) && !uses_lib) {
for (ipi = ipi_head.next; ipi != &ipi_head; ipi = ipi->next) {
DYNABUF_CLEAR(pathbuf);
// add first part
DynaBuf_add_string(pathbuf, ipi->path);
// if wanted and possible, ensure last char is directory separator
if (DIRECTORY_SEPARATOR
&& pathbuf->size
&& (pathbuf->buffer[pathbuf->size - 1] != DIRECTORY_SEPARATOR))
DynaBuf_append(pathbuf, DIRECTORY_SEPARATOR);
// add second part
DynaBuf_add_string(pathbuf, GLOBALDYNABUF_CURRENT);
// terminate
DynaBuf_append(pathbuf, '\0');
// try
stream = fopen(pathbuf->buffer, FILE_READBINARY);
//printf("trying <<%s>> - ", pathbuf->buffer);
if (stream) {
//printf("ok\n");
break;
} else {
//printf("failed\n");
}
}
}
if (stream == NULL)
Throw_error(exception_cannot_open_input_file);
return stream;
}

View File

@ -99,13 +99,16 @@ extern int Input_read_keyword(void);
// Return its length (without terminator).
// Zero lengths will produce a "missing string" error.
extern int Input_read_and_lower_keyword(void);
// Try to read a file name. If "allow_library" is TRUE, library access by using
// <...> quoting is possible as well. The file name given in the assembler
// source code is converted from UNIX style to platform style.
// Try to read a file name.
// If "allow_library" is TRUE, library access by using <...> quoting
// is possible as well. If "uses_lib" is non-NULL, info about library
// usage is stored there.
// The file name given in the assembler source code is converted from
// UNIX style to platform style.
// Returns whether error occurred (TRUE on error). Filename in GlobalDynaBuf.
// Errors are handled and reported, but caller should call
// Input_skip_remainder() then.
extern int Input_read_filename(int library_allowed);
extern int Input_read_filename(int library_allowed, int *uses_lib);
// Try to read a comma, skipping spaces before and after. Return TRUE if comma
// found, otherwise FALSE.
extern int Input_accept_comma(void);
@ -113,4 +116,16 @@ extern int Input_accept_comma(void);
extern int Input_get_force_bit(void);
// include path stuff - should be moved to its own file:
// init list
extern void includepaths_init(void);
// add entry
extern void includepaths_add(const char *path);
// open file for reading (trying list entries as prefixes)
// "uses_lib" tells whether to access library or to make use of include paths
// file name is expected in GlobalDynaBuf
extern FILE *includepaths_open_ro(int uses_lib);
#endif

View File

@ -828,10 +828,9 @@ static unsigned int imm_ops(int *force_bit, unsigned char opcode, int immediate_
}
// helper function to warn if zp pointer wraps around
// call with bits=0 for 2-byte pointers and bits=1 for 3-byte pointers
static void check_zp_wraparound(struct result *result, int bits)
static void check_zp_wraparound(struct result *result)
{
if (((result->val.intval | bits) == 0xff)
if ((result->val.intval == 0xff)
&& (result->flags & MVALUE_DEFINED))
Throw_warning("Zeropage pointer wraps around from $ff to $00");
}
@ -868,23 +867,21 @@ static void group_main(int index, int immediate_mode)
break;
case INDIRECT_ADDRESSING: // ($ff)
make_command(force_bit, &result, accu_ind8[index]);
check_zp_wraparound(&result, 0);
check_zp_wraparound(&result);
break;
case INDIRECT_Y_INDEXED_ADDRESSING: // ($ff),y
make_command(force_bit, &result, accu_indy8[index]);
check_zp_wraparound(&result, 0);
check_zp_wraparound(&result);
break;
case INDIRECT_Z_INDEXED_ADDRESSING: // ($ff),z
make_command(force_bit, &result, accu_indz8[index]);
check_zp_wraparound(&result, 0);
check_zp_wraparound(&result);
break;
case LONG_INDIRECT_ADDRESSING: // [$ff]
make_command(force_bit, &result, accu_lind8[index]);
check_zp_wraparound(&result, 1);
break;
case LONG_INDIRECT_Y_INDEXED_ADDRESSING: // [$ff],y
make_command(force_bit, &result, accu_lindy8[index]);
check_zp_wraparound(&result, 1);
break;
case STACK_INDEXED_INDIRECT_Y_INDEXED_ADDRESSING: // ($ff,s),y
make_command(force_bit, &result, accu_sindy8[index]);

View File

@ -49,6 +49,7 @@ struct output {
int flags; // segment flags ("overlay" and "invisible", see header file)
struct segment list_head; // head element of doubly-linked ring list
} segment;
char xor; // output modifier
};
@ -142,7 +143,7 @@ static void real_output(intval_t byte)
// 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;
out->buffer[out->write_idx++] = (byte & 0xff) ^ out->xor;
++CPU_state.add_to_pc;
}
@ -478,6 +479,7 @@ void Output_passinit(void)
out->segment.start = NO_SEGMENT_START; // TODO - "no active segment" could be made a segment flag!
out->segment.max = OUTBUFFERSIZE - 1;
out->segment.flags = 0;
out->xor = 0;
//vcpu stuff:
CPU_state.pc.flags = 0; // not defined yet
@ -541,6 +543,16 @@ void Output_start_segment(intval_t address_change, int segment_flags)
}
char output_get_xor(void)
{
return out->xor;
}
void output_set_xor(char xor)
{
out->xor = xor;
}
// set program counter to defined value (FIXME - allow for undefined!)
// if start address was given on command line, main loop will call this before each pass.
// in addition to that, it will be called on each "* = VALUE".

View File

@ -87,6 +87,8 @@ extern void Output_save_file(FILE *fd);
extern void Output_start_segment(intval_t address_change, int segment_flags);
// Show start and end of current segment
extern void Output_end_segment(void);
extern char output_get_xor(void);
extern void output_set_xor(char xor);
// set program counter to defined value (TODO - allow undefined!)
extern void vcpu_set_pc(intval_t new_pc, int flags);

View File

@ -89,6 +89,26 @@ static enum eos po_initmem(void)
}
// change output "encryption" ("!xor" pseudo opcode)
static enum eos po_xor(void)
{
char old_value;
intval_t change;
old_value = output_get_xor();
change = ALU_any_int();
if ((change > 0xff) || (change < -0x80)) {
Throw_error(exception_number_out_of_range);
change = 0;
}
output_set_xor(old_value ^ change);
// if there's a block, parse that and then restore old value!
if (Parse_optional_block())
output_set_xor(old_value);
return ENSURE_EOS;
}
// select output file and format ("!to" pseudo opcode)
static enum eos po_to(void)
{
@ -99,7 +119,7 @@ static enum eos po_to(void)
// read filename to global dynamic buffer
// if no file name given, exit (complaining will have been done)
if (Input_read_filename(FALSE))
if (Input_read_filename(FALSE, NULL))
return SKIP_REMAINDER;
// only act upon this pseudo opcode in first pass
@ -260,13 +280,16 @@ static enum eos obsolete_po_cbm(void)
}
// read encoding table from file
static enum eos user_defined_encoding(void)
static enum eos user_defined_encoding(FILE *stream)
{
char local_table[256],
*buffered_table = encoding_loaded_table;
const struct encoder *buffered_encoder = encoder_current;
encoding_load(local_table, GLOBALDYNABUF_CURRENT);
if (stream) {
encoding_load_from_file(local_table, stream);
fclose(stream);
}
encoder_current = &encoder_file; // activate new encoding
encoding_loaded_table = local_table; // activate local table
// If there's a block, parse that and then restore old values
@ -306,11 +329,16 @@ static enum eos predefined_encoding(void)
// set current encoding ("!convtab" pseudo opcode)
static enum eos po_convtab(void)
{
int uses_lib;
FILE *stream;
if ((GotByte == '<') || (GotByte == '"')) {
// if file name is missing, don't bother continuing
if (Input_read_filename(TRUE))
if (Input_read_filename(TRUE, &uses_lib))
return SKIP_REMAINDER;
return user_defined_encoding();
stream = includepaths_open_ro(uses_lib);
return user_defined_encoding(stream);
} else {
return predefined_encoding();
}
@ -382,20 +410,21 @@ static enum eos po_scrxor(void)
// FIXME - split this into "parser" and "worker" fn and move worker fn somewhere else.
static enum eos po_binary(void)
{
FILE *fd;
int uses_lib;
FILE *stream;
int byte;
intval_t size = -1, // means "not given" => "until EOF"
skip = 0;
// if file name is missing, don't bother continuing
if (Input_read_filename(TRUE))
if (Input_read_filename(TRUE, &uses_lib))
return SKIP_REMAINDER;
// try to open file
fd = fopen(GLOBALDYNABUF_CURRENT, FILE_READBINARY);
if (fd == NULL) {
Throw_error(exception_cannot_open_input_file);
stream = includepaths_open_ro(uses_lib);
if (stream == NULL)
return SKIP_REMAINDER;
}
// read optional arguments
if (Input_accept_comma()) {
if (ALU_optional_defined_int(&size)
@ -411,11 +440,11 @@ static enum eos po_binary(void)
output_skip(size); // really including is useless anyway
} else {
// really insert file
fseek(fd, skip, SEEK_SET); // set read pointer
fseek(stream, skip, SEEK_SET); // set read pointer
// if "size" non-negative, read "size" bytes.
// otherwise, read until EOF.
while (size != 0) {
byte = getc(fd);
byte = getc(stream);
if (byte == EOF)
break;
Output_byte(byte);
@ -429,7 +458,7 @@ static enum eos po_binary(void)
while (--size);
}
}
fclose(fd);
fclose(stream);
// if verbose, produce some output
if ((pass_count == 0) && (config.process_verbosity > 1)) {
int amount = vcpu_get_statement_size();
@ -663,7 +692,7 @@ static enum eos po_symbollist(void)
// read filename to global dynamic buffer
// if no file name given, exit (complaining will have been done)
if (Input_read_filename(FALSE))
if (Input_read_filename(FALSE, NULL))
return SKIP_REMAINDER;
// only process this pseudo opcode in first pass
@ -730,7 +759,8 @@ static enum eos obsolete_po_subzone(void)
// include source file ("!source" or "!src"). has to be re-entrant.
static enum eos po_source(void) // now GotByte = illegal char
{
FILE *fd;
int uses_lib;
FILE *stream;
char local_gotbyte;
struct input new_input,
*outer_input;
@ -740,11 +770,12 @@ static enum eos po_source(void) // now GotByte = illegal char
if (--source_recursions_left < 0)
Throw_serious_error("Too deeply nested. Recursive \"!source\"?");
// read file name. quit function on error
if (Input_read_filename(TRUE))
if (Input_read_filename(TRUE, &uses_lib))
return SKIP_REMAINDER;
// if file could be opened, parse it. otherwise, complain
if ((fd = fopen(GLOBALDYNABUF_CURRENT, FILE_READBINARY))) {
stream = includepaths_open_ro(uses_lib);
if (stream) {
#ifdef __GNUC__
char filename[GlobalDynaBuf->size]; // GCC can do this
#else
@ -755,14 +786,12 @@ static enum eos po_source(void) // now GotByte = illegal char
outer_input = Input_now; // remember old input
local_gotbyte = GotByte; // CAUTION - ugly kluge
Input_now = &new_input; // activate new input
flow_parse_and_close_file(fd, filename);
flow_parse_and_close_file(stream, filename);
Input_now = outer_input; // restore previous input
GotByte = local_gotbyte; // CAUTION - ugly kluge
#ifndef __GNUC__
free(filename); // GCC auto-frees
#endif
} else {
Throw_error(exception_cannot_open_input_file);
}
// leave nesting level
++source_recursions_left;
@ -1064,6 +1093,7 @@ static enum eos po_endoffile(void)
// pseudo opcode table
static struct ronode pseudo_opcode_list[] = {
PREDEFNODE("initmem", po_initmem),
PREDEFNODE("xor", po_xor),
PREDEFNODE("to", po_to),
PREDEFNODE(s_8, po_byte),
PREDEFNODE(s_08, po_byte),

View File

@ -7,9 +7,9 @@
#define version_H
#define RELEASE "0.96.3" // update before release FIXME
#define RELEASE "0.96.4" // update before release FIXME
#define CODENAME "Fenchurch" // update before release
#define CHANGE_DATE "3 Nov" // update before release FIXME
#define CHANGE_DATE "22 Dec" // update before release FIXME
#define CHANGE_YEAR "2017" // update before release
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME