mirror of
https://github.com/VARCem/Vasm.git
synced 2026-07-08 18:16:18 +00:00
First commit after fork.
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,5 +1,9 @@
|
||||
# Local stuff
|
||||
.gitignore
|
||||
t.*
|
||||
test*.*
|
||||
hello.*
|
||||
*.cmd
|
||||
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
92
CHANGELOG
92
CHANGELOG
@@ -1,39 +1,22 @@
|
||||
+ implement full getopt interface
|
||||
+ full source restructuring, broken up into modules
|
||||
+ allow 'X' for .byte
|
||||
+ fix .org to auto-fill
|
||||
+ add a .end directive
|
||||
+ implement .fill
|
||||
+ fix the symbol table stuff, added 'where' to them
|
||||
+ add generating hex files for output
|
||||
+ add << and >> operators in expressions
|
||||
+ fix the ^ and / operators in expressions
|
||||
+ fix the ! (NOT) operator, added the ~ alias
|
||||
+ support '.', '*' and '$' for "current", not just @
|
||||
+ added "EQU" in addition to "="
|
||||
+ allow 'X' for .byte
|
||||
+ add '.', '*' and '$' for "current pc", not just @
|
||||
+ fix .org to auto-fill
|
||||
+ implement ".end" directive
|
||||
+ implement ".page [plen[,pwidth]" and ".title [str]" directives
|
||||
+ implement paged listing file
|
||||
+ implement .binary (and .blob) for binary blob imports
|
||||
+ add ".page [plen[,pwidth]" and ".title [str]" directives
|
||||
+ add paged listing file
|
||||
+ add .cpu directive and underlying multi-target support
|
||||
- implement .nol option
|
||||
- implement .sym option
|
||||
- allow [] for expressions, not just ()
|
||||
+ implement multiple source files on command line
|
||||
+ add generating .s19 et al (Motorola) files for output
|
||||
|
||||
- Add C02/RC02/WC02/816, 68xx, 80xx et al support.
|
||||
The basic infrastructure for multi-CPU support is in now in place; we can
|
||||
start adding more processors and their (sub-)models in the backend files.
|
||||
|
||||
- Filling, ORG and hex files.
|
||||
We currently allow for filling spaces and auto-filling the .org directive
|
||||
for use with straight-binary output files. This is, however, not necessary
|
||||
if we are using hex (IntelHEX) or srec (Motorola SRecord) output files, as
|
||||
those formats "know" that data does not have to be linear. For this to be
|
||||
implemented properly, we will have to re-work the "generating output" code
|
||||
to do it as it goes (in pass 2), and not only at the end of that pass. This
|
||||
allows such "jumping" to be handled by those file formats.
|
||||
|
||||
+ move the processor-specific errors to the backend.
|
||||
+ implement multiple source files on command line
|
||||
+ Reading raw source data.
|
||||
We currently perform binary-mode reads on the input source files and all
|
||||
included files. Although this works fine on Linux (and, assumedly, on all
|
||||
@@ -51,3 +34,62 @@
|
||||
That said, reading text files in binary mode is not a good practice to
|
||||
begin with, so most likely this problem will be fixed by changing the input
|
||||
scanner to process all input files in ASCII (text) mode instead. DONE.
|
||||
+ implement .if/ifdef/ifndef .. .else .. .endif directives
|
||||
+ implement .def() inside expression handler for use with .if
|
||||
+ implement ".fill" directive
|
||||
+ implement ".align" directive
|
||||
- implement ".nol option" directive
|
||||
+ implement ".sym option" directive
|
||||
+ implement ".radix" directive for default numbering
|
||||
+ implement ".asciz" directive
|
||||
+ allow argument to .title to have no quotes
|
||||
+ implement predefined symbols ("P65C02" etc) for processors
|
||||
+ allow register A for accu-based (implied) operations
|
||||
+ re-implement expression comparisons with upstream code
|
||||
+ re-added the NOT operators, must have deleted those earlier..
|
||||
+ reworked expression handler to (also) recognize keywords such as
|
||||
NOT, AND, ASR and such, instead of just the ! and & etc chars.
|
||||
+ added .func() functions as part of the expression handler
|
||||
+ move .def( special-case from expr.c to new func.c.
|
||||
+ implement .sum() function
|
||||
+ allow labels to start with .
|
||||
These are sometimes found in assemblers, either the same way we use
|
||||
@ now, but sometimes also as 'extenders' for the previous global labels.
|
||||
|
||||
foo: ldx #$00
|
||||
.1 lda .msg, x
|
||||
beq .2
|
||||
jsr $ffd2
|
||||
jmp .1
|
||||
.2 rts
|
||||
.msg: .asciz "Hello!"
|
||||
|
||||
The above looks the same as when using but '@' local labels, but,
|
||||
not completely. With "dot labels", they (internally) get *added* to
|
||||
the previous global label, so the above would be in the symbol table
|
||||
as 'foo.1', 'foo.2' and 'foo.msg', respectively.
|
||||
- implement loginal AND (&&) and OR (||) operators
|
||||
- parentheses (precedence levels within an expression) ?
|
||||
|
||||
- We now support byte, word and doubleword values. However, are we consistent
|
||||
in checking these types within the symbols, labels and expressions?
|
||||
|
||||
- Filling, ORG and hex files.
|
||||
We currently allow for filling spaces and auto-filling the .org directive
|
||||
for use with straight-binary output files. This is, however, not necessary
|
||||
if we are using hex (IntelHEX) or srec (Motorola SRecord) output files, as
|
||||
those formats "know" that data does not have to be linear. For this to be
|
||||
implemented properly, we will have to re-work the "generating output" code
|
||||
to do it as it goes (in pass 2), and not only at the end of that pass. This
|
||||
allows such "jumping" to be handled by those file formats.
|
||||
|
||||
- fix the sub-relative include path
|
||||
If one includes a "../foo/bar/bla.inc" file, and then that file also does
|
||||
an include of, say, "xxx.inc", then that file is considered "local" to its
|
||||
parent. So, we should check for that.
|
||||
|
||||
- add include search paths using system path and/or -I option?
|
||||
|
||||
- Add C02/RC02/WC02/816, 68xx, 80xx et al support.
|
||||
The basic infrastructure for multi-CPU support is now in place; we can
|
||||
start adding more processors and their (sub-)models in the backend files.
|
||||
|
||||
53
LICENSE
53
LICENSE
@@ -1,33 +1,32 @@
|
||||
The BSD 3-Clause Open Software License.
|
||||
|
||||
VASM VARCem Multi-Target Assembler.
|
||||
A simple table-driven assembler for several 8-bit target
|
||||
devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
code originated from Bernd B”ckmann's "asm6502" project.
|
||||
|
||||
This file is part of the VARCem Project.
|
||||
Redistribution and use in source and binary forms, with
|
||||
or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
Authors: Fred N. van Kempen, <waltje@varcem.com>
|
||||
Bernd B”ckmann, <https://codeberg.org/boeckmann/asm6502>
|
||||
1. Redistributions of source code must retain the entire
|
||||
above notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
Copyright 2023 Fred N. van Kempen.
|
||||
Copyright 2022,2023 Bernd B”ckmann.
|
||||
2. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
MIT License Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom
|
||||
the Software is furnished to do so, subject to the following
|
||||
condition:
|
||||
3. Neither the name of the copyright holder nor the names
|
||||
of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
20
README.md
20
README.md
@@ -1,6 +1,6 @@
|
||||
Welcome to **VARCem**, the Virtual Archaeological Computer EMulator.
|
||||
|
||||
Vasm is a multi-target, table-driven cross assembler, part of the
|
||||
**Vasm** is a multi-target, table-driven cross assembler, part of the
|
||||
VARCem8 emulator project. It implements a general assembler block
|
||||
with the usual (and, some less usual) features, and then uses a
|
||||
back-end specific for a given microprocessor to generate code for
|
||||
@@ -8,13 +8,23 @@ that processor.
|
||||
|
||||
HISTORY
|
||||
-------
|
||||
Vasm has its roots in the [asm6502](https://github.com/boeckmann/asm6502) project.
|
||||
|
||||
Vasm has its roots in the [asm6502](https://github.com/boeckmann/asm6502)
|
||||
project. From there on, the code was split up into modules, features
|
||||
have been added and existing features have been improved. All this
|
||||
did not fit within the design goals of the original project, resulting
|
||||
in a fork so both projects can benefit.
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
Vasm is released under the MIT license, the same license as the
|
||||
original project (see HISTORY above.)
|
||||
VARCem as a whole is released under the BSD 3-Clause Open Software
|
||||
License, which is compatible with the GPL (GNU Public License)
|
||||
version 2 or later that is used by many of the modules imported
|
||||
from other emulator projects. Parts project are released under the
|
||||
MIT license.
|
||||
|
||||
The author of the original project (see HISTORY above) has authorized
|
||||
the VARCem team to re-license its fork of their project to the
|
||||
BSD 3-Clause Open Source License.
|
||||
|
||||
Author credits and specific copyrights can be found in each of
|
||||
the source files.
|
||||
|
||||
752
src/expr.c
Normal file
752
src/expr.c
Normal file
@@ -0,0 +1,752 @@
|
||||
/*
|
||||
* VASM VARCem Multi-Target Assembler.
|
||||
* A simple table-driven assembler for several 8-bit target
|
||||
* devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
* code originated from Bernd B”ckmann's "asm6502" project.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Handle all expressions.
|
||||
*
|
||||
* Version: @(#)expr.c 1.0.4 2023/04/23
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <waltje@varcem.com>
|
||||
* Bernd B”ckmann, <https://codeberg.org/boeckmann/asm6502>
|
||||
*
|
||||
* Copyright 2023 Fred N. van Kempen.
|
||||
* Copyright 2022,2023 Bernd B”ckmann.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "global.h"
|
||||
|
||||
|
||||
#ifndef isxdigit
|
||||
# define isxdigit(x) (isdigit((x)) || (((x) >= 'a') && ((x) <= 'f')) || \
|
||||
(((x) >= 'A') && ((x) <= 'F')))
|
||||
#endif
|
||||
|
||||
|
||||
static int
|
||||
starts_with(char *text, char *s)
|
||||
{
|
||||
while (! IS_END(*s)) {
|
||||
if (toupper(*text++) != toupper(*s++))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
digit(const char *p)
|
||||
{
|
||||
if (*p <= '9')
|
||||
return (int)(*p - '0');
|
||||
if (*p <= 'F')
|
||||
return (int)(*p + 10 - 'A');
|
||||
|
||||
return (int)(*p + 10 - 'a');
|
||||
}
|
||||
|
||||
|
||||
/* Read a number in some radix. */
|
||||
static value_t
|
||||
number(char **p)
|
||||
{
|
||||
value_t num = { 0 };
|
||||
uint8_t type = 0;
|
||||
char *pt = *p;
|
||||
|
||||
if (**p == '&') {
|
||||
(*p)++;
|
||||
do_dec:
|
||||
if (! isdigit(**p))
|
||||
error(ERR_NUM, NULL);
|
||||
do {
|
||||
num.v = num.v * 10 + digit((*p)++);
|
||||
} while (isdigit(**p));
|
||||
|
||||
type = NUM_TYPE(num.v);
|
||||
} else if (**p == '\\') {
|
||||
(*p)++;
|
||||
do_oct:
|
||||
if (! (**p >= 0 && **p <= '7'))
|
||||
error(ERR_NUM, NULL);
|
||||
do {
|
||||
num.v = num.v * 8 + digit((*p)++);
|
||||
} while (**p >= '0' && **p <= '7');
|
||||
|
||||
type = NUM_TYPE(num.v);
|
||||
} else if (**p == '$') {
|
||||
(*p)++;
|
||||
do_hex:
|
||||
if (! isxdigit(**p))
|
||||
error(ERR_NUM, NULL);
|
||||
do {
|
||||
num.v = (num.v << 4) + digit((*p)++);
|
||||
} while (isxdigit(**p));
|
||||
|
||||
type = ((*p - pt) > 7) ? TYPE_DWORD : ((*p - pt) > 3) ? TYPE_WORD : NUM_TYPE(num.v);
|
||||
} else if (**p == '%') {
|
||||
(*p)++;
|
||||
do_bin:
|
||||
if ((**p != '0') && (**p != '1'))
|
||||
error(ERR_NUM, NULL);
|
||||
do {
|
||||
num.v = (num.v << 1) + digit((*p)++);
|
||||
} while ((**p == '0') || (**p == '1'));
|
||||
|
||||
type = ((*p - pt) > 17) ? TYPE_DWORD : ((*p - pt) > 9) ? TYPE_WORD : NUM_TYPE(num.v);
|
||||
} else {
|
||||
/* No explicit radix specifier present, go with the default. */
|
||||
switch (radix) {
|
||||
case 2:
|
||||
goto do_bin;
|
||||
|
||||
case 8:
|
||||
goto do_oct;
|
||||
|
||||
case 10:
|
||||
goto do_dec;
|
||||
|
||||
case 16:
|
||||
goto do_hex;
|
||||
}
|
||||
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
SET_TYPE(num, type);
|
||||
SET_DEFINED(num);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
static value_t
|
||||
primary(char **p, int label)
|
||||
{
|
||||
char id[ID_LEN], id2[ID_LEN], *pt;
|
||||
value_t res = { 0 };
|
||||
symbol_t *sym;
|
||||
|
||||
skip_white(p);
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (opt_d)
|
||||
printf("> PRIMARY(%s)\n", dumpline(*p));
|
||||
#endif
|
||||
pt = *p;
|
||||
if (**p == '(') {
|
||||
/* Should we keep a nesting count? */
|
||||
(*p)++;
|
||||
res = expr(p);
|
||||
|
||||
skip_white(p);
|
||||
|
||||
if (**p != ')')
|
||||
error(ERR_UNBALANCED, NULL);
|
||||
(*p)++;
|
||||
} else if (**p == DOT_CHAR) {
|
||||
/* Check for functions. */
|
||||
(*p)++;
|
||||
pt = *p;
|
||||
if (isalpha(**p)) {
|
||||
ident_upcase(p, id);
|
||||
if (**p == '(') {
|
||||
/* We have an alnum AND a (, must be function. */
|
||||
(*p)++;
|
||||
|
||||
/* Execute function. */
|
||||
res = function(id, p);
|
||||
|
||||
if (**p != ')')
|
||||
error(ERR_OPER, NULL);
|
||||
(*p)++;
|
||||
} else {
|
||||
/* We have alnum but no (, must be a dot label */
|
||||
*p = pt;
|
||||
goto dot_label;
|
||||
}
|
||||
} else {
|
||||
dot_label:
|
||||
if (isalnum(**p) || IS_IDENT(**p)) {
|
||||
/* Dot labels require preceeding global label. */
|
||||
if (current_label == NULL)
|
||||
error(ERR_NO_GLOBAL, NULL);
|
||||
|
||||
/* OK, create full global label. */
|
||||
(*p)--;
|
||||
nident(p, id2);
|
||||
if ((strlen(current_label->name) + strlen(id2)) >= ID_LEN)
|
||||
error(ERR_IDLEN, NULL);
|
||||
strcpy(id, current_label->name);
|
||||
strcat(id, id2);
|
||||
sym = sym_lookup(id, NULL);
|
||||
if (sym != NULL) {
|
||||
res = sym->value;
|
||||
} else {
|
||||
res.v = 0;
|
||||
res.t = 0;
|
||||
}
|
||||
} else {
|
||||
/* Current program counter. */
|
||||
res.v = pc;
|
||||
res.t = TYPE_WORD | VALUE_DEFINED;
|
||||
}
|
||||
}
|
||||
} else if (**p == '@') {
|
||||
/* Current program counter or local label. */
|
||||
(*p)++;
|
||||
if (isalnum(**p)) {
|
||||
/* Most likely a local label. */
|
||||
if (current_label == NULL)
|
||||
error(ERR_NO_GLOBAL, NULL);
|
||||
nident(p, id);
|
||||
sym = sym_lookup(id, ¤t_label->locals);
|
||||
if (sym != NULL) {
|
||||
res = sym->value;
|
||||
} else {
|
||||
res.v = 0;
|
||||
res.t = 0;
|
||||
}
|
||||
} else {
|
||||
/* Current program counter. */
|
||||
program_counter:
|
||||
res.v = pc;
|
||||
res.t = TYPE_WORD | VALUE_DEFINED;
|
||||
}
|
||||
} else if (**p == '*') {
|
||||
/* Current program counter. */
|
||||
(*p)++;
|
||||
goto program_counter;
|
||||
} else if ((**p == '$') && (! isxdigit(*(pt+1)))) {
|
||||
(*p)++;
|
||||
goto program_counter;
|
||||
} else if (**p == '\'') {
|
||||
/* Single character. */
|
||||
(*p)++;
|
||||
if (is_end(**p) || (**p < 0x20))
|
||||
error(ERR_CHR, NULL);
|
||||
|
||||
res.v = **p;
|
||||
res.t = TYPE_BYTE | VALUE_DEFINED;
|
||||
|
||||
(*p)++;
|
||||
if (**p != '\'')
|
||||
error(ERR_CHR, NULL);
|
||||
(*p)++;
|
||||
} else if (isalpha(**p)) {
|
||||
/* Symbol reference. */
|
||||
nident(p, id);
|
||||
sym = sym_lookup(id, NULL);
|
||||
if (sym == NULL) {
|
||||
/* Forward reference, remember it. */
|
||||
sym = sym_aquire(id, NULL);
|
||||
if (DEFINED(sym->value))
|
||||
error(ERR_REDEF, id);
|
||||
|
||||
/* Set the correct type. */
|
||||
if (label) {
|
||||
sym->kind = KIND_LBL;
|
||||
sym->value.t = TYPE_WORD;
|
||||
} else {
|
||||
sym->kind = KIND_VAR;
|
||||
sym->value.t = TYPE_BYTE;
|
||||
}
|
||||
sym->value.v = 0;
|
||||
}
|
||||
res = sym->value;
|
||||
} else {
|
||||
/* Must be just a number, but do mind the radix! */
|
||||
res = number(p);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For compatibility with other assemblers,
|
||||
* we add word-based operators for:
|
||||
*
|
||||
* % MOD
|
||||
* & AND
|
||||
* << ASL
|
||||
* >> ASR
|
||||
*
|
||||
* for completeness.
|
||||
*/
|
||||
static value_t
|
||||
product(char **p)
|
||||
{
|
||||
value_t n2, res;
|
||||
char op, op2;
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (opt_d)
|
||||
printf("PRODUCT(%s)\n", dumpline(*p));
|
||||
#endif
|
||||
res = primary(p, 1);
|
||||
|
||||
skip_white(p);
|
||||
|
||||
op = **p; op2 = *((*p)+1);
|
||||
if (starts_with(*p, "MOD ")) { op = '%'; *p += 4; }
|
||||
else if (starts_with(*p, "AND ")) { op = '&'; *p += 4; }
|
||||
else if (starts_with(*p, "ASL ")) { op = '<'; op2 = '<'; *p += 4; }
|
||||
else if (starts_with(*p, "ASR ")) { op = '>'; op2 = '>'; *p += 4; };
|
||||
|
||||
while ((op == '*') || (op == '&') || (op == '/') || (op == '%') ||
|
||||
(op == '<' && op2 == '<') || (op == '>' && op2 == '>') ||
|
||||
(op == '|' && op2 == '|') || (op == '&' && op2 == '&')) {
|
||||
|
||||
/* Skip operator. */
|
||||
(*p)++;
|
||||
|
||||
/* For double-character operators, skip the second character. */
|
||||
if ((op == '<' || op == '>' || op == '|') ||
|
||||
(op == '&' && op2 == '&'))
|
||||
(*p)++;
|
||||
|
||||
n2 = primary(p, 1);
|
||||
|
||||
switch (op) {
|
||||
case '*': // multiply
|
||||
res.v = (uint16_t)(res.v * n2.v);
|
||||
break;
|
||||
|
||||
case '/': // divide
|
||||
if (n2.v == 0)
|
||||
error(ERR_ZERO, NULL);
|
||||
res.v = (uint16_t)(res.v / n2.v);
|
||||
break;
|
||||
|
||||
case '%': // modulo
|
||||
if (n2.v == 0)
|
||||
error(ERR_ZERO, NULL);
|
||||
res.v = (uint16_t)(res.v % n2.v);
|
||||
break;
|
||||
|
||||
case '&': // AND
|
||||
if (op2 == op) // logical AND
|
||||
res.v = !!res.v && !!n2.v;
|
||||
else // bitwise AND
|
||||
res.v = (uint16_t)(res.v & n2.v);
|
||||
break;
|
||||
|
||||
case '|': // OR
|
||||
if (op2 == op) // logical OR
|
||||
res.v = !!res.v || !!n2.v;
|
||||
else // bitwise OR
|
||||
res.v = (uint16_t)(res.v | n2.v);
|
||||
break;
|
||||
|
||||
case '<': // bitwise shift LEFT
|
||||
res.v = res.v << n2.v;
|
||||
break;
|
||||
|
||||
case '>': // bitwise shift RIGHT
|
||||
res.v = res.v >> n2.v;
|
||||
break;
|
||||
}
|
||||
INFER_TYPE(res, n2);
|
||||
INFER_DEFINED(res, n2);
|
||||
|
||||
skip_white(p);
|
||||
|
||||
op = **p;
|
||||
op2 = *((*p)+1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For compatibility with other assemblers,
|
||||
* we add word-based operators for:
|
||||
*
|
||||
* | OR
|
||||
* ^ XOR (and/or EOR)
|
||||
*
|
||||
* for completeness.
|
||||
*/
|
||||
static value_t
|
||||
term(char **p)
|
||||
{
|
||||
value_t n2, res;
|
||||
char op;
|
||||
|
||||
skip_white(p);
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (opt_d)
|
||||
printf("TERM(%s)\n", dumpline(*p));
|
||||
#endif
|
||||
if (**p == '-') { // indicate negative value
|
||||
/* Unary minus. */
|
||||
(*p)++;
|
||||
res = product(p);
|
||||
res.v = -res.v;
|
||||
} else {
|
||||
/* Unary plus. */
|
||||
if (**p == '+') // skip, default is positive
|
||||
(*p)++;
|
||||
|
||||
res = product(p);
|
||||
}
|
||||
|
||||
skip_white(p);
|
||||
|
||||
op = **p;
|
||||
if (starts_with(*p, "OR ")) { op = '|'; *p += 3; }
|
||||
else if (starts_with(*p, "XOR ")) { op = '^'; *p += 4; }
|
||||
else if (starts_with(*p, "EOR ")) { op = '^'; *p += 4; };
|
||||
|
||||
while ((op == '+') || (op == '-') || (op == '|') || (op == '^')) {
|
||||
/* Skip operator. */
|
||||
(*p)++;
|
||||
|
||||
n2 = product(p);
|
||||
|
||||
switch (op) {
|
||||
case '+': // add
|
||||
res.v = res.v + n2.v;
|
||||
break;
|
||||
|
||||
case '-': // subtract
|
||||
res.v = res.v - n2.v;
|
||||
break;
|
||||
|
||||
case '|': // bitwise OR
|
||||
res.v = res.v | n2.v;
|
||||
break;
|
||||
|
||||
case '^': // bitwise XOR
|
||||
res.v = res.v ^ n2.v;
|
||||
break;
|
||||
}
|
||||
INFER_TYPE(res, n2);
|
||||
INFER_DEFINED(res, n2);
|
||||
|
||||
skip_white(p);
|
||||
|
||||
op = **p;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static value_t
|
||||
compare(char **p)
|
||||
{
|
||||
value_t res, n2;
|
||||
char op, op2;
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (opt_d)
|
||||
printf("COMPARE(%s)\n", dumpline(*p));
|
||||
#endif
|
||||
res = term(p);
|
||||
|
||||
skip_white(p);
|
||||
|
||||
op = **p; op2 = *(*p + 1);
|
||||
while ((op == '<') || (op == '>') ||
|
||||
(op == '=' && op2 == '=') || (op == '!' && op2 == '=') ||
|
||||
(op == '<' && op2 == '=') || (op == '>' && op2 == '=')) {
|
||||
|
||||
/* Skip operator. */
|
||||
(*p)++;
|
||||
|
||||
/* For double-character operators, skip the second character. */
|
||||
if ((op == '=') || (op == '!') ||
|
||||
(op == '<' && op2 == '=') || (op == '>' && op2 == '='))
|
||||
(*p)++;
|
||||
|
||||
n2 = term(p);
|
||||
switch (op) {
|
||||
case '=':
|
||||
res.v = res.v == n2.v;
|
||||
break;
|
||||
|
||||
case '!':
|
||||
res.v = res.v != n2.v;
|
||||
break;
|
||||
|
||||
case '<':
|
||||
res.v = (op2 == '=') ? res.v <= n2.v : res.v < n2.v;
|
||||
break;
|
||||
|
||||
case '>':
|
||||
res.v = (op2 == '=') ? res.v >= n2.v : res.v > n2.v;
|
||||
break;
|
||||
}
|
||||
|
||||
INFER_DEFINED(res, n2);
|
||||
if (DEFINED(res) && res.v)
|
||||
res.v = 1;
|
||||
SET_TYPE(res, TYPE_BYTE);
|
||||
|
||||
skip_white(p);
|
||||
|
||||
op = **p;
|
||||
op2 = *((*p)+1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For compatibility with other assemblers,
|
||||
* we add word-based operators for:
|
||||
*
|
||||
* ! NOT
|
||||
* ~ NOT
|
||||
*
|
||||
* for completeness.
|
||||
*/
|
||||
value_t
|
||||
expr(char **p)
|
||||
{
|
||||
value_t v;
|
||||
char op;
|
||||
|
||||
skip_white(p);
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (opt_d)
|
||||
printf("EXPR(%s)\n", dumpline(*p));
|
||||
#endif
|
||||
|
||||
op = **p;
|
||||
if (starts_with(*p, "NOT ")) { op = '~'; *p += 4; };
|
||||
|
||||
if (op == '>') {
|
||||
/* High-byte (MSB) operator. */
|
||||
(*p)++;
|
||||
v = compare(p);
|
||||
v.v = v.v >> 8;
|
||||
SET_TYPE(v, TYPE_BYTE);
|
||||
} else if (op == '<') {
|
||||
/* Low-byte (LSB) operator. */
|
||||
(*p)++;
|
||||
v = compare(p);
|
||||
v.v = v.v & 0xff;
|
||||
SET_TYPE(v, TYPE_BYTE);
|
||||
} else if ((op == '!') || (op == '~')) {
|
||||
/* NOT operators. */
|
||||
(*p)++;
|
||||
v = term(p);
|
||||
v.v = ~v.v;
|
||||
SET_TYPE(v, TYPE_WORD);
|
||||
} else if (starts_with(*p, "[b]")) {
|
||||
/* Lossless conversion to byte. */
|
||||
*p += 3;
|
||||
v = compare(p);
|
||||
if (DEFINED(v) && v.v > 0xff)
|
||||
error(ERR_RNG_BYTE, NULL);
|
||||
SET_TYPE(v, TYPE_BYTE);
|
||||
} else if (starts_with(*p, "[d]")) {
|
||||
/* Lossless conversion to doubleword. */
|
||||
*p += 3;
|
||||
v = compare(p);
|
||||
SET_TYPE(v, TYPE_DWORD);
|
||||
} else if (starts_with(*p, "[w]")) {
|
||||
/* Lossless conversion to word. */
|
||||
*p += 3;
|
||||
v = compare(p);
|
||||
SET_TYPE(v, TYPE_WORD);
|
||||
} else {
|
||||
/* Iterate. */
|
||||
v = compare(p);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
/* Take a value and try to convert it to a byte value. */
|
||||
value_t
|
||||
to_byte(value_t v)
|
||||
{
|
||||
if (DEFINED(v) && (v.v > 0xff))
|
||||
error(ERR_RNG_BYTE, NULL);
|
||||
|
||||
SET_TYPE(v, TYPE_BYTE);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
/* Take a value and try to convert it to a word value. */
|
||||
value_t
|
||||
to_word(value_t v)
|
||||
{
|
||||
if (DEFINED(v) && (v.v > 0xffff))
|
||||
error(ERR_RNG_WORD, NULL);
|
||||
|
||||
SET_TYPE(v, TYPE_WORD);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
char
|
||||
value_type(uint8_t type)
|
||||
{
|
||||
switch (type & TYPE_MASK) {
|
||||
case TYPE_BYTE:
|
||||
return 'B';
|
||||
|
||||
case TYPE_WORD:
|
||||
return 'W';
|
||||
|
||||
case TYPE_DWORD:
|
||||
return 'D';
|
||||
}
|
||||
|
||||
return '?';
|
||||
}
|
||||
|
||||
|
||||
/* Determine the desired format for printing a value. */
|
||||
int
|
||||
value_format(char **p)
|
||||
{
|
||||
char *pt = *p;
|
||||
int fmt = 0;
|
||||
|
||||
skip_white(p);
|
||||
if (**p != FMT_B_CHAR) {
|
||||
*p = pt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
skip_curr_and_white(p);
|
||||
|
||||
switch (**p) {
|
||||
case FMT_BIN_CHAR:
|
||||
case FMT_DEC_CHAR:
|
||||
case FMT_HEX_CHAR:
|
||||
case FMT_HEX1_CHAR:
|
||||
case FMT_HEX2_CHAR:
|
||||
fmt = (int)**p;
|
||||
(*p)++;
|
||||
break;
|
||||
|
||||
case FMT_E_CHAR:
|
||||
fmt = FMT_DEC_CHAR;
|
||||
break;
|
||||
|
||||
default:
|
||||
*p = pt;
|
||||
return -ERR_FMT;
|
||||
}
|
||||
|
||||
if (**p != FMT_E_CHAR) {
|
||||
*p = pt;
|
||||
return -ERR_FMT;
|
||||
}
|
||||
|
||||
(*p)++;
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
value_print(value_t v)
|
||||
{
|
||||
static char buff[9];
|
||||
|
||||
switch (TYPE(v)) {
|
||||
case TYPE_BYTE:
|
||||
sprintf(buff, "%02X", v.v & 0xff);
|
||||
break;
|
||||
|
||||
case TYPE_WORD:
|
||||
sprintf(buff, "%04X", v.v & 0xffff);
|
||||
break;
|
||||
|
||||
case TYPE_DWORD:
|
||||
sprintf(buff, "%08X", v.v);
|
||||
break;
|
||||
}
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
|
||||
/* Print a value in a specific format. */
|
||||
char *
|
||||
value_print_format(value_t v, int fmt)
|
||||
{
|
||||
static char buff[33];
|
||||
char *bufp = buff;
|
||||
int len = (v.t & TYPE_DWORD) ? 32 : (v.t & TYPE_WORD) ? 16 : 8;
|
||||
int i;
|
||||
|
||||
switch (fmt) {
|
||||
case FMT_BIN_CHAR:
|
||||
for (i = 0; i < len; i++)
|
||||
*bufp++ = (v.v & (1 << ((len - i) - 1))) ? '1':'0';
|
||||
*bufp = '\0';
|
||||
break;
|
||||
|
||||
case FMT_DEC_CHAR:
|
||||
sprintf(bufp, "%u", (unsigned)v.v);
|
||||
break;
|
||||
|
||||
case FMT_HEX_CHAR:
|
||||
sprintf(bufp, "$%0*X", len / 4, (unsigned)v.v);
|
||||
break;
|
||||
|
||||
case FMT_HEX1_CHAR:
|
||||
sprintf(bufp, "0x%0*x", len / 4, (unsigned)v.v);
|
||||
break;
|
||||
|
||||
case FMT_HEX2_CHAR:
|
||||
sprintf(bufp, "0x%0*X", len / 4, (unsigned)v.v);
|
||||
break;
|
||||
}
|
||||
|
||||
return buff;
|
||||
}
|
||||
2
src/f.sh
Normal file
2
src/f.sh
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
vasm -p6502 -s -l foo.lst -o foo.hex '-DLOAD=$400' foo.asm
|
||||
149
src/func.c
Normal file
149
src/func.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* VASM VARCem Multi-Target Assembler.
|
||||
* A simple table-driven assembler for several 8-bit target
|
||||
* devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
* code originated from Bernd B”ckmann's "asm6502" project.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Handle all functions.
|
||||
*
|
||||
* Version: @(#)func.c 1.0.1 2023/04/22
|
||||
*
|
||||
* Author: Fred N. van Kempen, <waltje@varcem.com>
|
||||
*
|
||||
* Copyright 2023 Fred N. van Kempen.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "global.h"
|
||||
|
||||
|
||||
typedef struct pseudo {
|
||||
const char *name;
|
||||
value_t (*func)(char **);
|
||||
} func_t;
|
||||
|
||||
|
||||
/* Implement the ".def(symbol)" function. */
|
||||
static value_t
|
||||
do_def(char **p)
|
||||
{
|
||||
char id[ID_LEN];
|
||||
value_t res = { 0 };
|
||||
symbol_t *sym;
|
||||
|
||||
ident(p, id);
|
||||
sym = sym_lookup(id, NULL);
|
||||
if (sym == NULL) {
|
||||
/* Forward reference, remember it. */
|
||||
sym = sym_aquire(id, NULL);
|
||||
if (DEFINED(sym->value))
|
||||
error(ERR_REDEF, id);
|
||||
|
||||
/* Set the correct type. */
|
||||
sym->kind = KIND_VAR;
|
||||
sym->value.t = TYPE_BYTE;
|
||||
sym->value.v = 0;
|
||||
}
|
||||
res = sym->value;
|
||||
if (IS_END(**p))
|
||||
error(ERR_EOL, NULL);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Implement the ".sum(startaddr,numbytes)" function. */
|
||||
static value_t
|
||||
do_sum(char **p)
|
||||
{
|
||||
value_t res = { 0 };
|
||||
value_t v1, v2;
|
||||
|
||||
v1 = expr(p);
|
||||
|
||||
skip_white(p);
|
||||
if (IS_END(**p))
|
||||
error(ERR_EOL, NULL);
|
||||
|
||||
if (**p != ',')
|
||||
error(ERR_OPER, NULL);
|
||||
(*p)++;
|
||||
|
||||
v2 = expr(p);
|
||||
|
||||
/*
|
||||
* Calculate the (regular) checksum of the code bytes
|
||||
* between v1 (inclusive) and v2 (exclusive), using a
|
||||
* normal addition.
|
||||
*/
|
||||
if (code != NULL) {
|
||||
v2.v += v1.v;
|
||||
while (v1.v < v2.v)
|
||||
res.v += code[v1.v++ - code_base];
|
||||
}
|
||||
SET_DEFINED(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static const func_t functions[] = {
|
||||
{ "DEF", do_def },
|
||||
{ "DEFINED", do_def },
|
||||
{ "SUM", do_sum },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
value_t
|
||||
function(const char *name, char **p)
|
||||
{
|
||||
const func_t *ptr;
|
||||
value_t res = { 0 };
|
||||
|
||||
/* Skip any whitespace. */
|
||||
skip_white(p);
|
||||
|
||||
for (ptr = functions; ptr->name != NULL; ptr++) {
|
||||
if (! strcmp(ptr->name, name)) {
|
||||
res = ptr->func(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
279
src/global.h
Normal file
279
src/global.h
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* VASM VARCem Multi-Target Assembler.
|
||||
* A simple table-driven assembler for several 8-bit target
|
||||
* devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
* code originated from Bernd B”ckmann's "asm6502" project.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Definitions for the entire application.
|
||||
*
|
||||
* Version: @(#)global.h 1.0.6 2023/04/23
|
||||
*
|
||||
* Author: Fred N. van Kempen, <waltje@varcem.com>
|
||||
*
|
||||
* Copyright 2023 Fred N. van Kempen.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef GLOBAL_H
|
||||
# define GLOBAL_H
|
||||
|
||||
|
||||
#define COMMENT_CHAR ';' // starts a comment (until EOL)
|
||||
#define DOT_CHAR '.' // starts a directive or local label
|
||||
#define EOF_CHAR 0x1a
|
||||
#define EQUAL_CHAR '=' // indicates variable assignment
|
||||
#define COLON_CHAR ':' // marks a label
|
||||
#define ALPHA_CHAR '@' // marks a local label
|
||||
#define FMT_B_CHAR '[' // starts a format specifier
|
||||
#define FMT_E_CHAR ']' // ends a format specifier
|
||||
#define FMT_BIN_CHAR '%' // specifies binary format
|
||||
#define FMT_DEC_CHAR '#' // specifies decimal format
|
||||
#define FMT_HEX_CHAR '$' // specifies hex format ($ style)
|
||||
#define FMT_HEX1_CHAR 'x' // specifies hex format (C style)
|
||||
#define FMT_HEX2_CHAR 'X' // specifies hex format (C style)
|
||||
|
||||
#define IS_EOL(c) (((c) == EOF_CHAR) || ((c) == '\n') || ((c) == '\r'))
|
||||
#define IS_END(c) ((!(c)) || IS_EOL((c)))
|
||||
#define IS_SPACE(c) (((c) == '\t') || ((c) == ' '))
|
||||
#define IS_IDENT(c) (((c) == DOT_CHAR) || ((c) == '_'))
|
||||
|
||||
#define MAX_FILENAMES 256 + 1 // maximum include files
|
||||
#define MAX_IFLEVEL 16 // maximum depth of IF levels
|
||||
#define RADIX_DEFAULT 10 // default radix is decimal
|
||||
|
||||
|
||||
typedef enum errors_e {
|
||||
ERR_USER = 1, // user-specified error
|
||||
ERR_ZERO, // "division by zero"
|
||||
ERR_NOCPU, // "processor type not set"
|
||||
ERR_CPU, // "unknown processor type"
|
||||
ERR_MEM, // "out of memory"
|
||||
ERR_NODIRECTIVE, // "unknown directive"
|
||||
ERR_INSTR, // "unknown instruction"
|
||||
ERR_NUM, // "value expected"
|
||||
ERR_FMT, // "invalid format specifier"
|
||||
ERR_EXPR, // "error in expression"
|
||||
ERR_OPER, // "incomplete operator"
|
||||
ERR_UNBALANCED, // "unbalanced parentheses"
|
||||
ERR_ID, // "identifier expected"
|
||||
ERR_IDLEN, // "identifier length exceeded"
|
||||
ERR_STMT, // "illegal statement"
|
||||
ERR_EOL, // "end of line expected"
|
||||
ERR_REDEF, // "illegal redefinition"
|
||||
ERR_IF, // "IF nesting too deep"
|
||||
ERR_ELSE, // "ELSE without IF"
|
||||
ERR_ENDIF, // "ENDIF without IF"
|
||||
ERR_LBLREDEF, // "symbol already defined as label"
|
||||
ERR_CLBR, // "missing closing brace"
|
||||
ERR_UNDEF, // "undefined value"
|
||||
ERR_ILLTYPE, // "illegal type"
|
||||
ERR_STREND, // "string not terminated"
|
||||
ERR_CHREND, // "character constant not terminated"
|
||||
ERR_RNG, // "value out of range"
|
||||
ERR_RNG_BYTE, // "byte value out of range
|
||||
ERR_RNG_WORD, // "word value out of range
|
||||
ERR_LOCAL_REDEF, // "illegal redefinition of local label"
|
||||
ERR_NO_GLOBAL, // "local label definition .. global label"
|
||||
ERR_CHR, // "malformed character constant"
|
||||
ERR_STRLEN, // "string too long"
|
||||
ERR_STR, // "string expected"
|
||||
ERR_OPEN, // "can not open file"
|
||||
ERR_MAXINC, // "maximum number of include files reached"
|
||||
ERR_NO_FMT, // "file format not enabled"
|
||||
|
||||
ERR_MAXERR // last generic error
|
||||
} errors_t;
|
||||
|
||||
|
||||
#define ID_LEN 32 // max #characters in identifiers
|
||||
#define STR_LEN 128 // max #characters in string literals
|
||||
|
||||
#define MAXINT(a,b) (((b) >= (a)) ? (b) : (a))
|
||||
|
||||
|
||||
/* The generic "value" type for variables and expressions. */
|
||||
typedef struct value {
|
||||
uint32_t v;
|
||||
uint8_t t;
|
||||
#define TYPE_NONE 0x00
|
||||
#define TYPE_BYTE 0x01
|
||||
#define TYPE_WORD 0x02
|
||||
#define TYPE_DWORD 0x04
|
||||
#define TYPE_MASK 0x0f
|
||||
} value_t;
|
||||
|
||||
/* For the value-specific directives. */
|
||||
#define VALUE_DEFINED 0x80
|
||||
#define DEFINED(x) (((x).t & VALUE_DEFINED) != 0)
|
||||
#define UNDEFINED(x) (((x).t & VALUE_DEFINED) == 0)
|
||||
#define SET_DEFINED(v) ((v).t = ((v).t | VALUE_DEFINED))
|
||||
#define SET_UNDEFINED(v) ((v).t = (v).t & TYPE_MASK);
|
||||
#define INFER_DEFINED(a,b) \
|
||||
if (UNDEFINED(a) || UNDEFINED(b)) { SET_UNDEFINED(a); } \
|
||||
else { SET_DEFINED(a); }
|
||||
|
||||
/* For the type-specific directives. */
|
||||
#define TYPE(v) ((v).t & TYPE_MASK)
|
||||
#define SET_TYPE(v, u) ((v).t = ((v).t & VALUE_DEFINED) | (u))
|
||||
#define NUM_TYPE(x) (((x) < 0x100) ? TYPE_BYTE : ((x) < 0x10000) ? TYPE_WORD : TYPE_DWORD)
|
||||
#define INFER_TYPE(a,b) (((a).v >= 0x100) || ((b).v >= 0x100)) \
|
||||
? SET_TYPE((a), TYPE_WORD) \
|
||||
: SET_TYPE((a), MAXINT(TYPE(a),(TYPE(b))))
|
||||
|
||||
|
||||
/* Data type for storing symbols (labels and variables.) */
|
||||
typedef struct sym_ {
|
||||
char name[ID_LEN];
|
||||
value_t value;
|
||||
uint8_t kind; // is it a label or a variable?
|
||||
#define KIND_LBL 1
|
||||
#define KIND_VAR 2
|
||||
uint8_t pass; // defined in which pass?
|
||||
short filenr; // in which file was it defined?
|
||||
int linenr; // on what line in that file?
|
||||
struct sym_ *next;
|
||||
struct sym_ *locals; // local subdefinitions
|
||||
} symbol_t;
|
||||
|
||||
/* Symbol-specific directives. */
|
||||
#define IS_LBL(x) (((x)->kind & KIND_LBL) != 0)
|
||||
#define IS_VAR(x) (((x)->kind & KIND_VAR) != 0)
|
||||
|
||||
struct pseudo;
|
||||
|
||||
|
||||
/* Global variables. */
|
||||
extern int opt_d,
|
||||
opt_C,
|
||||
opt_F,
|
||||
opt_P,
|
||||
opt_q,
|
||||
opt_v;
|
||||
extern char myname[],
|
||||
version[];
|
||||
|
||||
extern uint16_t pc;
|
||||
extern int line,
|
||||
newline;
|
||||
extern symbol_t *current_label;
|
||||
extern int8_t org_done;
|
||||
extern int8_t radix;
|
||||
extern int iflevel,
|
||||
ifstate,
|
||||
newifstate,
|
||||
ifstack[];
|
||||
extern char *filenames[];
|
||||
extern int filelines[];
|
||||
extern int filenames_idx,
|
||||
filenames_len;
|
||||
|
||||
extern char *text;
|
||||
extern int text_len;
|
||||
|
||||
extern uint8_t *code;
|
||||
extern uint32_t code_base;
|
||||
extern uint16_t oc,
|
||||
sa;
|
||||
|
||||
extern int list_plength,
|
||||
list_pwidth;
|
||||
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
# define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
|
||||
/* Functions. */
|
||||
#ifdef _DEBUG
|
||||
extern char *dumpline(const char *p);
|
||||
#endif
|
||||
extern int pass(char **, int);
|
||||
extern void error(int, const char *);
|
||||
extern int is_end(char);
|
||||
extern void skip_eol(char **);
|
||||
extern void skip_white(char **);
|
||||
extern void skip_white_and_comment(char **);
|
||||
extern void skip_curr_and_white(char **);
|
||||
extern void ident(char **, char *);
|
||||
extern void upcase(char **, char *);
|
||||
extern void ident_upcase(char **, char *);
|
||||
extern void nident(char **, char *);
|
||||
extern void nident_upcase(char **, char *);
|
||||
|
||||
extern symbol_t *sym_table(void);
|
||||
extern char sym_type(const symbol_t *);
|
||||
extern symbol_t *sym_lookup(const char *, symbol_t **);
|
||||
extern void sym_free(symbol_t **);
|
||||
extern symbol_t *sym_aquire(const char *, symbol_t **);
|
||||
extern symbol_t *define_label(const char *, uint16_t, symbol_t *);
|
||||
extern void define_variable(const char *, value_t);
|
||||
|
||||
extern value_t expr(char **);
|
||||
extern value_t to_byte(value_t);
|
||||
extern value_t to_word(value_t);
|
||||
extern char value_type(uint8_t);
|
||||
extern int value_format(char **);
|
||||
extern char *value_print(value_t);
|
||||
extern char *value_print_format(value_t, int);
|
||||
|
||||
extern value_t function(const char *, char **);
|
||||
|
||||
extern size_t file_size(const char *);
|
||||
extern int file_read_buf(const char *, char *);
|
||||
extern int file_read(const char *, char **, size_t *);
|
||||
extern void file_add(const char *, int, const char *, size_t);
|
||||
|
||||
extern void emit_addr(uint32_t);
|
||||
extern int emit_str(const char *, int, int);
|
||||
extern int emit_byte(uint8_t, int);
|
||||
extern int emit_word(uint16_t, int);
|
||||
extern int emit_dword(uint32_t, int);
|
||||
extern int save_code(const char *, const uint8_t *, int);
|
||||
|
||||
extern void list_set_head(const char *);
|
||||
extern void list_set_syms(int);
|
||||
extern int list_init(const char *);
|
||||
extern void list_close(void);
|
||||
extern void list_line(const char *);
|
||||
extern void list_page(const char *);
|
||||
extern void list_save(uint16_t, uint16_t);
|
||||
extern void list_symbols(void);
|
||||
|
||||
extern const struct pseudo *is_pseudo(const char *);
|
||||
extern char *pseudo(const struct pseudo *, char **, int);
|
||||
|
||||
extern int set_cpu(const char *, int);
|
||||
|
||||
|
||||
#endif /*GLOBAL_H*/
|
||||
212
src/input.c
Normal file
212
src/input.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* VASM VARCem Multi-Target Assembler.
|
||||
* A simple table-driven assembler for several 8-bit target
|
||||
* devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
* code originated from Bernd B”ckmann's "asm6502" project.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Handle reading source input. Care must be taken (especially
|
||||
* on Windows systems, where we seem to have some issues with
|
||||
* the "fread" function on text files) to properly read data
|
||||
* from them when opened as a text file.
|
||||
*
|
||||
* Version: @(#)input.c 1.0.3 2023/04/11
|
||||
*
|
||||
* Author: Fred N. van Kempen, <waltje@varcem.com>
|
||||
*
|
||||
* Copyright 2023 Fred N. van Kempen.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "global.h"
|
||||
|
||||
|
||||
/*
|
||||
* The text variable holds all the assembler source.
|
||||
*
|
||||
* The main assembler file and all files included are joined by an EOF (0x1A)
|
||||
* character and stored as a whole in the text variable. Binary zero
|
||||
* marks the end of the assembler text.
|
||||
*/
|
||||
char *text = NULL; // holds the assembler source
|
||||
int text_len; // total length of the source
|
||||
|
||||
/*
|
||||
* The filenames variable stores the filenames of all included files.
|
||||
* When parsing the source the filenames_idx variable is incremented
|
||||
* when en EOF character is encountered, and the line counter variable is
|
||||
* set to filelines[filenames_idx], current filename is set to
|
||||
* filenames[filenames_idx].
|
||||
*/
|
||||
char *filenames[MAX_FILENAMES];
|
||||
int filelines[MAX_FILENAMES];
|
||||
int filenames_idx;
|
||||
int filenames_len;
|
||||
|
||||
|
||||
/* Determine the "cooked" size (in characters) of a text file. */
|
||||
size_t
|
||||
file_size(const char *fn)
|
||||
{
|
||||
size_t size;
|
||||
FILE *fp;
|
||||
int c;
|
||||
|
||||
/* Open the file in text mode. */
|
||||
if ((fp = fopen(fn, "r")) == NULL)
|
||||
error(ERR_OPEN, fn);
|
||||
|
||||
/* Text mode, so read file, counting characters. */
|
||||
size = 0;
|
||||
while (!feof(fp) && !ferror(fp)) {
|
||||
if ((c = fgetc(fp)) == EOF)
|
||||
break;
|
||||
if (c == '\r')
|
||||
continue;
|
||||
else
|
||||
size++;
|
||||
}
|
||||
|
||||
/* File can be closed now. */
|
||||
(void)fclose(fp);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
file_read_buf(const char *fn, char *bufp)
|
||||
{
|
||||
char *ptr;
|
||||
FILE *fp;
|
||||
int c;
|
||||
|
||||
/* Open the file in text mode. */
|
||||
if ((fp = fopen(fn, "r")) == NULL)
|
||||
return 0;
|
||||
|
||||
/* Now read the file's contents into the buffer. */
|
||||
ptr = bufp;
|
||||
while (!feof(fp) && !ferror(fp)) {
|
||||
if ((c = fgetc(fp)) == EOF)
|
||||
break;
|
||||
if (c == '\r')
|
||||
continue;
|
||||
*ptr++ = c;
|
||||
}
|
||||
*ptr = '\0';
|
||||
|
||||
/* File can be closed now. */
|
||||
(void)fclose(fp);
|
||||
|
||||
/* Return the buffer size. */
|
||||
return (int)(ptr - bufp);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
file_read(const char *fn, char **pp, size_t *sizep)
|
||||
{
|
||||
char *ptr;
|
||||
size_t size;
|
||||
FILE *fp;
|
||||
int c;
|
||||
|
||||
/* Open the file in text mode. */
|
||||
if ((fp = fopen(fn, "r")) == NULL)
|
||||
return 0;
|
||||
|
||||
/* Text mode, so read file, counting characters. */
|
||||
size = 0;
|
||||
while (!feof(fp) && !ferror(fp)) {
|
||||
if ((c = fgetc(fp)) == EOF)
|
||||
break;
|
||||
if (c == '\r')
|
||||
continue;
|
||||
else
|
||||
size++;
|
||||
}
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
/* Allocate a buffer for the contents. */
|
||||
if (*pp == NULL) {
|
||||
/* No buffer yet, just allocate one. */
|
||||
*pp = malloc(size + 1); // +1 for NUL at end
|
||||
ptr = *pp;
|
||||
} else {
|
||||
/* We already have a buffer, so add to it. */
|
||||
*pp = realloc(*pp, *sizep + 1 + size + 1); // +1 for EOF inbetween
|
||||
ptr = *pp + *sizep;
|
||||
*ptr++ = EOF_CHAR; // insert EOF
|
||||
}
|
||||
ptr[size] = '\0'; // terminate buffer
|
||||
*sizep += size;
|
||||
|
||||
if (*pp == NULL) {
|
||||
(void)fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Now read the file's contents into the buffer. */
|
||||
while (!feof(fp) && !ferror(fp)) {
|
||||
if ((c = fgetc(fp)) == EOF)
|
||||
break;
|
||||
if (c == '\r')
|
||||
continue;
|
||||
*ptr++ = c;
|
||||
}
|
||||
*ptr = '\0';
|
||||
|
||||
/* File can be closed now. */
|
||||
(void)fclose(fp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
file_add(const char *name, int linenr, const char *str, size_t size)
|
||||
{
|
||||
int c = filenames_idx;
|
||||
|
||||
filenames[c] = strdup(name);
|
||||
filelines[c] = 1;
|
||||
// filetexts[c] = str;
|
||||
// filesizes[c] = size;
|
||||
|
||||
filenames_idx++;
|
||||
filenames_len++;
|
||||
}
|
||||
335
src/list.c
Normal file
335
src/list.c
Normal file
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* VASM VARCem Multi-Target Assembler.
|
||||
* A simple table-driven assembler for several 8-bit target
|
||||
* devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
* code originated from Bernd B”ckmann's "asm6502" project.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Handle the listfile output.
|
||||
*
|
||||
* Version: @(#)list.c 1.0.3 2023/04/17
|
||||
*
|
||||
* Author: Fred N. van Kempen, <waltje@varcem.com>
|
||||
*
|
||||
* Copyright 2023 Fred N. van Kempen.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "global.h"
|
||||
|
||||
|
||||
#define LIST_PLENGTH 66 // number of lines per page
|
||||
#define LIST_PWIDTH 80 // number of characters per line
|
||||
|
||||
#define LIST_CHAR_FF "\014" // FormFeed character
|
||||
#define LIST_CHAR_SI "\017" // SI (condensed printing mode)
|
||||
#define LIST_CHAR_DC2 "\022" // DC2 (end condensed printing mode)
|
||||
|
||||
#define LIST_NBYTES 4 // this many code bytes per line
|
||||
|
||||
|
||||
int list_plength = LIST_PLENGTH, // lines per page
|
||||
list_pwidth = LIST_PWIDTH; // characters per line
|
||||
|
||||
static int list_lnr,
|
||||
list_pnr,
|
||||
list_pln;
|
||||
static uint16_t list_oc,
|
||||
list_pc;
|
||||
static char *list_head;
|
||||
static FILE *list_file = NULL;
|
||||
static int list_syms = 0;
|
||||
|
||||
|
||||
void
|
||||
list_set_head(const char *head)
|
||||
{
|
||||
if (list_head != NULL)
|
||||
free(list_head);
|
||||
list_head = NULL;
|
||||
|
||||
/* .. and set the new one. */
|
||||
if (head != NULL)
|
||||
list_head = strdup(head);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
list_set_syms(int syms)
|
||||
{
|
||||
list_syms = syms;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Start a new page in the listing file.
|
||||
*
|
||||
* We have the dimensions set in PLENGTH (66) and PWIDTH (80),
|
||||
* which can be changed with the .page directive. Do remember
|
||||
* that these numbers INCLUDE the page margings, so effectively
|
||||
* we have less than those- most printers require about 0.25"
|
||||
* of margings at the minimum, so a U.S. Letter page of 8.5x11"
|
||||
* will result in 80 (at 10cpi) characters and 63 (at 6lpi) lines
|
||||
* for the page. We also use 3 lines per page for the header, so
|
||||
* with those default settings, we get to "keep" 60 lines.
|
||||
*/
|
||||
void
|
||||
list_page(const char *head)
|
||||
{
|
||||
char buff[1024], page[256], date[64];
|
||||
char *ptr = buff;
|
||||
struct tm *tm;
|
||||
time_t now;
|
||||
int i, skip;
|
||||
|
||||
if (list_file == NULL)
|
||||
return;
|
||||
|
||||
if (head == NULL)
|
||||
head = list_head;
|
||||
|
||||
/* Initialize printer to condensed mode if width > 80. */
|
||||
if (opt_P && list_pnr == 0 && list_pwidth > 80) {
|
||||
fprintf(list_file, LIST_CHAR_SI);
|
||||
}
|
||||
|
||||
/* Bump the page number. */
|
||||
list_pnr++;
|
||||
|
||||
/* Get a (localized) date and time string. */
|
||||
(void)time(&now);
|
||||
tm = localtime(&now);
|
||||
strftime(date, sizeof(date), "%c", tm);
|
||||
|
||||
sprintf(page, "%s Page %i", date, list_pnr);
|
||||
skip = list_pwidth - (strlen(myname) + 1 + strlen(version) + strlen(page));
|
||||
if (list_pnr > 1) {
|
||||
/* Insert a form-feed for all but first page. */
|
||||
sprintf(ptr, "%s", LIST_CHAR_FF);
|
||||
ptr += strlen(ptr);
|
||||
}
|
||||
sprintf(ptr, "%s %s", myname, version);
|
||||
ptr += strlen(ptr);
|
||||
while (skip--)
|
||||
*ptr++ = ' ';
|
||||
strcpy(ptr, page);
|
||||
fprintf(list_file, "%s\n", buff);
|
||||
|
||||
sprintf(page, "File: %s", filenames[filenames_idx]);
|
||||
i = (head != NULL) ? strlen(head) : 0;
|
||||
skip = list_pwidth - (i + strlen(page));
|
||||
ptr = buff;
|
||||
if (head != NULL) {
|
||||
sprintf(ptr, "%s", head);
|
||||
ptr += strlen(ptr);
|
||||
}
|
||||
while (skip--)
|
||||
*ptr++ = ' ';
|
||||
strcpy(ptr, page);
|
||||
fprintf(list_file, "%s\n\n", buff);
|
||||
|
||||
/* OK, good for another page.. */
|
||||
list_pln = list_plength - (3 + 3); // margin + header
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate one line of listing info.
|
||||
*
|
||||
* Keep in mind that many source files contain TAB characters,
|
||||
* and for those to look "nice" in our listings, we must make
|
||||
* sure the actual listing starts at a multiple-of-8 position
|
||||
* plus one. For now, we are using position 33.
|
||||
*/
|
||||
void
|
||||
list_line(const char *p)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (list_file == NULL)
|
||||
return;
|
||||
|
||||
if (list_pln == 0) {
|
||||
/* Reset the page. */
|
||||
list_page(list_head);
|
||||
}
|
||||
|
||||
/* Output listing line number. */
|
||||
fprintf(list_file, "%05i ", list_lnr++);
|
||||
|
||||
/* Output program counter, but only if we emitted code. */
|
||||
if (list_oc < oc) {
|
||||
if (opt_C)
|
||||
fprintf(list_file, "%04X ", list_oc);
|
||||
fprintf(list_file, "%04X ", list_pc);
|
||||
} else {
|
||||
if (opt_C)
|
||||
fputs(" ", list_file);
|
||||
fputs(" ", list_file);
|
||||
}
|
||||
|
||||
/* Output any code bytes. */
|
||||
while (list_oc < oc && count < LIST_NBYTES) {
|
||||
fprintf(list_file, "%02X ", code[list_oc++]);
|
||||
list_pc++;
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Fill the remaining space. */
|
||||
while (count < LIST_NBYTES) {
|
||||
fputs(" ", list_file);
|
||||
count++;
|
||||
}
|
||||
|
||||
fprintf(list_file, "%6i%c ", line, ifstate ? ':' : '-');
|
||||
|
||||
if (p != NULL) {
|
||||
while (*p && *p != '\n' && *p != EOF_CHAR)
|
||||
fputc(*p++, list_file);
|
||||
}
|
||||
fputs("\n", list_file);
|
||||
|
||||
list_pln--;
|
||||
|
||||
if (list_oc < oc)
|
||||
list_line(NULL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
list_symbols(void)
|
||||
{
|
||||
symbol_t *sym = sym_table();
|
||||
symbol_t *loc;
|
||||
FILE *fp;
|
||||
|
||||
/* Has this been enabled? */
|
||||
if (! list_syms)
|
||||
return;
|
||||
|
||||
/* If we are not using a listing file, dump to stdout. */
|
||||
if (list_file != NULL) {
|
||||
list_page("** SYMBOL TABLE **"); // new page
|
||||
fp = list_file; // use listing file
|
||||
} else
|
||||
fp = stdout; // use stdout
|
||||
|
||||
if (sym != NULL) {
|
||||
if (list_file == NULL) // only when on stdout
|
||||
fprintf(fp, "Symbol table:\n");
|
||||
|
||||
for (; sym; sym = sym->next) {
|
||||
if ((list_file != NULL) && (list_pln == 0))
|
||||
list_page("** SYMBOL TABLE **");
|
||||
|
||||
fprintf(fp, "%-32s %c ", sym->name, sym_type(sym));
|
||||
if (DEFINED(sym->value)) {
|
||||
fprintf(fp, "%5s ", value_print(sym->value));
|
||||
if (IS_VAR(sym))
|
||||
fprintf(fp, "%c", value_type(sym->value.t));
|
||||
else
|
||||
fprintf(fp, " ");
|
||||
fprintf(fp, " ");
|
||||
if (sym->filenr != -1)
|
||||
fprintf(fp, "%s:%i",
|
||||
filenames[sym->filenr], sym->linenr);
|
||||
else
|
||||
fprintf(fp, "-command line-");
|
||||
} else
|
||||
fprintf(fp, "%5s", "??");
|
||||
fprintf(fp, "\n");
|
||||
|
||||
if (list_file != NULL)
|
||||
list_pln--;
|
||||
|
||||
if ((list_syms == 2) && IS_LBL(sym)) {
|
||||
for (loc = sym->locals; loc; loc = loc->next) {
|
||||
if ((list_file != NULL) && (--list_pln == 0))
|
||||
list_page("** SYMBOL TABLE **");
|
||||
|
||||
fprintf(fp, " %c%-29s %c ",
|
||||
ALPHA_CHAR, loc->name, sym_type(sym));
|
||||
fprintf(fp, "%5s %s:%i\n",
|
||||
value_print(loc->value),
|
||||
filenames[loc->filenr], loc->linenr);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
fprintf(fp, "No symbols defined.\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
list_save(uint16_t pc, uint16_t oc)
|
||||
{
|
||||
if (list_file != NULL) {
|
||||
list_oc = oc;
|
||||
list_pc = pc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
list_close(void)
|
||||
{
|
||||
if (list_file != NULL) {
|
||||
/* Reset printer to normal mode if needed. */
|
||||
if (opt_P && list_pwidth > 80 && list_pnr > 0) {
|
||||
fprintf(list_file, LIST_CHAR_DC2);
|
||||
}
|
||||
|
||||
(void)fclose(list_file);
|
||||
|
||||
list_file = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
list_init(const char *fn)
|
||||
{
|
||||
list_file = fopen(fn, "w");
|
||||
if (list_file == NULL)
|
||||
return 0;
|
||||
|
||||
list_lnr = 1;
|
||||
list_pnr = list_pln = 0;
|
||||
list_oc = list_pc = 0;
|
||||
list_head = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
314
src/main.c
Normal file
314
src/main.c
Normal file
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* VASM VARCem Multi-Target Assembler.
|
||||
* A simple table-driven assembler for several 8-bit target
|
||||
* devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
* code originated from Bernd B”ckmann's "asm6502" project.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* A simple but reasonably useful assembler for the 6502.
|
||||
*
|
||||
* Usage: vasm [-dCFqsvPV] [-p processor] [-l fn] [-o fn] [-Dsym[=val]] file ...
|
||||
*
|
||||
* Version: @(#)main.c 1.0.7 2023/04/23
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <waltje@varcem.com>
|
||||
* Bernd B”ckmann, <https://codeberg.org/boeckmann/asm6502>
|
||||
*
|
||||
* Copyright 2023 Fred N. van Kempen.
|
||||
* Copyright 2022,2023 Bernd B”ckmann.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <setjmp.h>
|
||||
#ifndef _MSC_VER
|
||||
# include <getopt.h>
|
||||
#endif
|
||||
#include "global.h"
|
||||
#include "version.h"
|
||||
|
||||
|
||||
int opt_d, // set DEBUG env variable to enable debug
|
||||
opt_C, // is true, also list the list offset
|
||||
opt_F, // if true, perform autofill with .org
|
||||
opt_P, // enable Printer mode
|
||||
opt_q, // be very quiet
|
||||
opt_v; // more verbose
|
||||
char myname[64], // my name
|
||||
version[128]; // my full version string
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
extern int getopt(int ac, char *av[], const char *),
|
||||
optind, opterr;
|
||||
extern char *optarg;
|
||||
#endif
|
||||
|
||||
|
||||
/* Define a symbol from the command line. */
|
||||
static void
|
||||
do_define(char *str)
|
||||
{
|
||||
char id[ID_LEN];
|
||||
char **p = &str;
|
||||
value_t v = { 0 };
|
||||
|
||||
ident(p, id);
|
||||
if (**p == '=') {
|
||||
/* We have an equal sign. */
|
||||
(*p)++;
|
||||
if (! IS_END(**p)) {
|
||||
/* Try to decode a value. */
|
||||
v = expr(p);
|
||||
} else {
|
||||
/* No value given, whoops. */
|
||||
goto nodata;
|
||||
}
|
||||
} else {
|
||||
nodata:
|
||||
v.v = 1;
|
||||
SET_DEFINED(v);
|
||||
SET_TYPE(v, TYPE_BYTE);
|
||||
}
|
||||
|
||||
define_variable(id, v);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
usage(const char *prog)
|
||||
{
|
||||
printf("Usage: %s [-dCFPqsvV] [-p processor] [-l fn] [-o fn] [-Dsym[=val]] file ...\n", prog);
|
||||
|
||||
exit(1);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
banner(void)
|
||||
{
|
||||
printf("%s %s\nCopyright 2023 Fred N. van Kempen, <waltje@varcem.com>\n",
|
||||
APP_TITLE, version);
|
||||
#ifdef _WIN32
|
||||
printf("Copyright 2022,2023 Bernd B”ckmann, <bernd@varcem.com>\n\n");
|
||||
#else
|
||||
printf("Copyright 2022,2023 Bernd B\303\266ckmann, <bernd@varcem.com>\n\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *out_name, *list_name;
|
||||
char *ttext;
|
||||
int c, opt_s;
|
||||
size_t size;
|
||||
int errors = 0;
|
||||
|
||||
/* Set option defaults. */
|
||||
#ifdef _DEBUG
|
||||
opt_d = (getenv("DEBUG") != NULL);
|
||||
#endif
|
||||
opt_C = 0;
|
||||
opt_F = 1;
|
||||
opt_P = opt_s = 0;
|
||||
opt_q = opt_v = 0;
|
||||
out_name = list_name = NULL;
|
||||
filenames_idx = -1; // this indicates "command line"
|
||||
radix = RADIX_DEFAULT;
|
||||
|
||||
/* Create a version string. */
|
||||
sprintf(myname, "%s", APP_NAME);
|
||||
sprintf(version, "version %s (%s, %s)",
|
||||
APP_VERSION,
|
||||
#ifdef _WIN32
|
||||
"Windows",
|
||||
#else
|
||||
"Linux",
|
||||
#endif
|
||||
STR(ARCH));
|
||||
|
||||
opterr = 0;
|
||||
while ((c = getopt(argc, argv, "dCD:Fl:o:Pp:qsvV")) != EOF) switch(c) {
|
||||
case 'C': // toggle list-offset display (disabled)
|
||||
opt_C ^= 1;
|
||||
break;
|
||||
|
||||
case 'D': // define symbol
|
||||
do_define(optarg);
|
||||
break;
|
||||
|
||||
case 'd': // debug mode (disabled)
|
||||
opt_d ^= 1;
|
||||
break;
|
||||
|
||||
case 'F': // auto-fill for .org (enabled)
|
||||
opt_F ^= 1;
|
||||
break;
|
||||
|
||||
case 'l': // set listing file name (none)
|
||||
list_name = optarg;
|
||||
break;
|
||||
|
||||
case 'o': // set output file name (none)
|
||||
out_name = optarg;
|
||||
break;
|
||||
|
||||
case 'P': // enable Printer mode
|
||||
opt_P ^= 1;
|
||||
break;
|
||||
|
||||
case 'p': // processor name
|
||||
if (! set_cpu(optarg, 1)) {
|
||||
fprintf(stderr, "Unknown processor '%s'.\n", optarg);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'q': // be very quiet during operation (disabled)
|
||||
opt_q ^= 1;
|
||||
break;
|
||||
|
||||
case 's': // show (or dump) the symbol table
|
||||
opt_s ^= 1;
|
||||
list_set_syms(opt_s << 1); // FULL or OFF
|
||||
break;
|
||||
|
||||
case 'v': // level of verbosity (lowest)
|
||||
opt_v++;
|
||||
break;
|
||||
|
||||
case 'V': // just show version and exit
|
||||
banner();
|
||||
exit(EXIT_SUCCESS);
|
||||
/*NOTREACHED*/
|
||||
|
||||
default:
|
||||
usage(argv[0]);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/* Say hello. */
|
||||
if (! opt_q)
|
||||
banner();
|
||||
|
||||
/* We need at least one filename argument. */
|
||||
if (optind == argc)
|
||||
usage(argv[0]);
|
||||
|
||||
//FIXME: if we do not have an output file, auto-generate filename
|
||||
// from the (first) input file?
|
||||
if (out_name == NULL) {
|
||||
fprintf(stderr, "No output file specified.\n");
|
||||
errors = 1;
|
||||
goto ret0;
|
||||
}
|
||||
|
||||
/* Create a listing file if requested. */
|
||||
if ((list_name != NULL) && !list_init(list_name)) {
|
||||
fprintf(stderr, "Listing file '%s' could not be created!\n", list_name);
|
||||
errors = 1;
|
||||
goto ret0;
|
||||
}
|
||||
|
||||
/* Read all input files into our buffer. */
|
||||
text = NULL;
|
||||
size = 0;
|
||||
filenames_idx = 0;
|
||||
while (optind < argc) {
|
||||
if (! file_read(argv[optind], &text, &size)) {
|
||||
fprintf(stderr, "Error loading file %s\n", argv[optind]);
|
||||
errors = 1;
|
||||
goto ret0;
|
||||
}
|
||||
|
||||
file_add(argv[optind++], 1, text, size);
|
||||
}
|
||||
text_len = size;
|
||||
|
||||
/* Perform Pass 1. */
|
||||
ttext = text;
|
||||
errors = pass(&ttext, 1);
|
||||
if (errors)
|
||||
goto ret1;
|
||||
|
||||
/* Create the output buffer. */
|
||||
ttext = text;
|
||||
code = malloc(oc);
|
||||
|
||||
/* Perform Pass 2. */
|
||||
errors = pass(&ttext, 2);
|
||||
if (errors)
|
||||
goto ret2;
|
||||
|
||||
if (! opt_q)
|
||||
printf("Generated %i bytes of output.\n", oc);
|
||||
|
||||
if (! save_code(out_name, code, oc)) {
|
||||
fprintf(stderr, "error writing output file %s\n", out_name);
|
||||
errors = 1;
|
||||
goto ret2;
|
||||
}
|
||||
|
||||
/* Dump the symbols, if enabled. */
|
||||
list_symbols();
|
||||
|
||||
ret2:
|
||||
list_close();
|
||||
|
||||
if (code != NULL)
|
||||
free(code);
|
||||
|
||||
ret1:
|
||||
// if (text != NULL)
|
||||
// free(text);
|
||||
|
||||
sym_free(NULL);
|
||||
|
||||
ret0:
|
||||
if (errors) {
|
||||
if (list_name != NULL)
|
||||
(void)remove(list_name);
|
||||
if (out_name != NULL)
|
||||
(void)remove(out_name);
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
244
src/output.c
Normal file
244
src/output.c
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* VASM VARCem Multi-Target Assembler.
|
||||
* A simple table-driven assembler for several 8-bit target
|
||||
* devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
* code originated from Bernd B”ckmann's "asm6502" project.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Handle the writing of output data.
|
||||
*
|
||||
* **NOTE** This is far from 'correct' right now. We perform output in
|
||||
* a single block right after assembly, but for non-binary
|
||||
* output formats, this is wrong. The right way to do this is
|
||||
* to "start" the output file as needed, and then, as we move
|
||||
* on in the assembly, output data as needed. This also allows
|
||||
* for the proper use of the ".org" directive, as this then
|
||||
* merely changes the 'load address' of the following bytes.
|
||||
*
|
||||
* Version: @(#)output.c 1.0.3 2023/04/22
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <waltje@varcem.com>
|
||||
* Bernd B”ckmann, <https://codeberg.org/boeckmann/asm6502>
|
||||
*
|
||||
* Copyright 2023 Fred N. van Kempen.
|
||||
* Copyright 2022,2023 Bernd B”ckmann.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef USE_IHEX
|
||||
# include <ihex.h>
|
||||
#endif
|
||||
#ifdef USE_SREC
|
||||
# include <srec.h>
|
||||
#endif
|
||||
#include "global.h"
|
||||
|
||||
|
||||
uint8_t *code = NULL; // holds the emitted code
|
||||
uint32_t code_base = 0; // our load (base) address
|
||||
|
||||
static FILE *out_file; // output file
|
||||
|
||||
|
||||
/* Set our load (base) address. */
|
||||
void
|
||||
emit_addr(uint32_t addr)
|
||||
{
|
||||
code_base = addr;
|
||||
}
|
||||
|
||||
|
||||
/* Copy a string (of characters) to the output. */
|
||||
int
|
||||
emit_str(const char *p, int len, int pass)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
if (pass == 2) {
|
||||
for (i = 0; i < len; i++)
|
||||
code[oc + i] = (uint8_t)*p++;
|
||||
}
|
||||
|
||||
oc += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/* Copy a single byte to the output. */
|
||||
int
|
||||
emit_byte(uint8_t b, int pass)
|
||||
{
|
||||
if (pass == 2)
|
||||
code[oc] = b;
|
||||
|
||||
oc++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Copy a single word to the output. */
|
||||
int
|
||||
emit_word(uint16_t w, int pass)
|
||||
{
|
||||
if (pass == 2) {
|
||||
/* We use little-endian format here. */
|
||||
code[oc] = w & 0xff;
|
||||
code[oc + 1] = w >> 8;
|
||||
}
|
||||
|
||||
oc += 2;
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
/* Copy a single double-word to the output. */
|
||||
int
|
||||
emit_dword(uint32_t w, int pass)
|
||||
{
|
||||
if (pass == 2) {
|
||||
/* We use little-endian format here. */
|
||||
code[oc] = w & 0xff;
|
||||
code[oc + 1] = (w >> 8) & 0xff;
|
||||
code[oc + 2] = (w >> 16) & 0xff;
|
||||
code[oc + 3] = (w >> 24) & 0xff;
|
||||
}
|
||||
|
||||
oc += 2;
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_IHEX
|
||||
void
|
||||
ihex_flush_buffer(ihex_t *ihex, char *buffer, char *eptr)
|
||||
{
|
||||
*eptr = '\0';
|
||||
|
||||
(void)fputs(buffer, out_file);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//FIXME: we should use out_name, and update that if we change it here!
|
||||
int
|
||||
save_code(const char *fn, const uint8_t *data, int len)
|
||||
{
|
||||
char name[1024], *p;
|
||||
#ifdef USE_IHEX
|
||||
ihex_t ihex;
|
||||
ihex_count_t count;
|
||||
uint8_t *ptr;
|
||||
#endif
|
||||
int fmt, i;
|
||||
|
||||
/* Copy the filename and determine the desired format. */
|
||||
strncpy(name, fn, sizeof(name) - 1);
|
||||
p = strrchr(name, '/');
|
||||
#ifdef _WIN32
|
||||
if (p == NULL)
|
||||
p = strrchr(name, '\\');
|
||||
#endif
|
||||
if (p == NULL)
|
||||
p = name;
|
||||
p = strrchr(p, '.');
|
||||
if (p != NULL)
|
||||
p++;
|
||||
|
||||
fmt = 1;
|
||||
if (p == NULL) {
|
||||
/* No filename extension - use .bin as a default! */
|
||||
strcat(name, ".bin");
|
||||
} else if (! strcasecmp(p, "hex")) {
|
||||
fmt = 2;
|
||||
} else if (!strcasecmp(p, "srec") || !strcasecmp(p, "s19")) {
|
||||
fmt = 3;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
switch (fmt) {
|
||||
case 1: // raw binary
|
||||
out_file = fopen(fn, "wb");
|
||||
if (out_file == NULL)
|
||||
break;
|
||||
i = fwrite(data, len, 1, out_file);
|
||||
(void)fclose(out_file);
|
||||
break;
|
||||
|
||||
case 2: // intel hex
|
||||
#ifdef USE_IHEX
|
||||
out_file = fopen(fn, "w");
|
||||
if (out_file == NULL)
|
||||
break;
|
||||
ihex_init(&ihex);
|
||||
// ihex_write_at_address(&ihex, pc);
|
||||
ihex_set_output_line_length(&ihex,
|
||||
IHEX_DEFAULT_OUTPUT_LINE_LENGTH);
|
||||
ptr = code;
|
||||
while (oc > 0) {
|
||||
count = (oc > 1024) ? 1024 : oc;
|
||||
ihex_write_bytes(&ihex, ptr, count);
|
||||
ptr += count;
|
||||
oc -= count;
|
||||
}
|
||||
|
||||
if (sa != 0)
|
||||
ihex_write_start_address(&ihex, sa);
|
||||
|
||||
ihex_end_write(&ihex);
|
||||
(void)fclose(out_file);
|
||||
i = 1;
|
||||
#else
|
||||
error(ERR_NO_FMT, p);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 3: // motorola SRecord
|
||||
i = 0;
|
||||
error(ERR_NO_FMT, p);
|
||||
}
|
||||
|
||||
out_file = NULL;
|
||||
|
||||
/* If this did not work, let them know. */
|
||||
if ((i == 0) && (pc != 0))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
505
src/parse.c
Normal file
505
src/parse.c
Normal file
@@ -0,0 +1,505 @@
|
||||
/*
|
||||
* VASM VARCem Multi-Target Assembler.
|
||||
* A simple table-driven assembler for several 8-bit target
|
||||
* devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
* code originated from Bernd B”ckmann's "asm6502" project.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Parse the source input, process it, and generate output.
|
||||
*
|
||||
* Version: @(#)parse.c 1.0.6 2023/04/23
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <waltje@varcem.com>
|
||||
* Bernd B”ckmann, <https://codeberg.org/boeckmann/asm6502>
|
||||
*
|
||||
* Copyright 2023 Fred N. van Kempen.
|
||||
* Copyright 2022,2023 Bernd B”ckmann.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
# include <stdnoreturn.h>
|
||||
#else
|
||||
# define noreturn /*NORETURN*/
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <setjmp.h>
|
||||
#include "global.h"
|
||||
#include "target.h"
|
||||
|
||||
|
||||
int line, // currently processed line number
|
||||
newline; // next line to be processed
|
||||
symbol_t *current_label = NULL; // search scope for local labels
|
||||
int8_t org_done; // has a .org been performed?
|
||||
int8_t radix; // current numerical radix
|
||||
int iflevel, // current level of conditionals
|
||||
ifstate, newifstate, // current conditional state
|
||||
ifstack[MAX_IFLEVEL];
|
||||
|
||||
/* program counter and output counter may not be in sync */
|
||||
/* this happens if an .org directive is used, which modifies the */
|
||||
/* program counter but not the output counter. */
|
||||
uint16_t pc = 0; // addr of currently assembled instr
|
||||
uint16_t oc = 0; // counter of emitted output bytes
|
||||
uint16_t sa = 0; // start addr for generated code (.end)
|
||||
|
||||
|
||||
static int errors;
|
||||
static jmp_buf error_jmp;
|
||||
static char error_hint[128];
|
||||
static const char *err_msg[] = {
|
||||
"no error",
|
||||
"fatal",
|
||||
"division by zero detected",
|
||||
"processor type not set",
|
||||
"unknown processor type",
|
||||
"out of memory",
|
||||
"unknown directive",
|
||||
"unknown instruction",
|
||||
"value expected",
|
||||
"invalid format specifier",
|
||||
"error in expression",
|
||||
"incomplete operator",
|
||||
"unbalanced parentheses",
|
||||
"identifier expected",
|
||||
"identifier length exceeded",
|
||||
"illegal statement",
|
||||
"end of line expected",
|
||||
"illegal redefinition",
|
||||
"IF nesting too deep",
|
||||
"ELSE without IF",
|
||||
"ENDIF without IF",
|
||||
"symbol already defined as label",
|
||||
"missing closing brace",
|
||||
"undefined value",
|
||||
"illegal type",
|
||||
"string not terminated",
|
||||
"character constant not terminated",
|
||||
"value out of range",
|
||||
"byte value out of range",
|
||||
"word value out of range",
|
||||
"illegal redefinition of local label",
|
||||
"local label definition requires previous global label",
|
||||
"malformed character constant",
|
||||
"string too long",
|
||||
"string expected",
|
||||
"can not open file",
|
||||
"maximum number of include files reached",
|
||||
"file format not enabled"
|
||||
};
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
char *
|
||||
dumpline(const char *p)
|
||||
{
|
||||
static char temp[1024];
|
||||
char *s = temp;
|
||||
|
||||
while (*p && *p != '\n')
|
||||
*s++ = *p++;
|
||||
*s = '\0';
|
||||
|
||||
return(temp);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Display error message and abort action. */
|
||||
noreturn void
|
||||
error(int err, const char *msg)
|
||||
{
|
||||
errors++;
|
||||
|
||||
if (msg != NULL)
|
||||
strncpy(error_hint, msg, sizeof(error_hint) - 1);
|
||||
else
|
||||
memset(error_hint, 0x00, sizeof(error_hint));
|
||||
|
||||
longjmp(error_jmp, err);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
skip_eol(char **p)
|
||||
{
|
||||
if (**p == EOF_CHAR)
|
||||
(*p)++;
|
||||
if (**p == 0x0d)
|
||||
(*p)++;
|
||||
if (**p == 0x0a)
|
||||
(*p)++;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
is_end(char p)
|
||||
{
|
||||
return IS_END(p);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
skip_white(char **p)
|
||||
{
|
||||
while (IS_SPACE(**p))
|
||||
(*p)++;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
skip_white_and_comment(char **p)
|
||||
{
|
||||
while (IS_SPACE(**p))
|
||||
(*p)++;
|
||||
|
||||
if (**p == COMMENT_CHAR) {
|
||||
(*p)++;
|
||||
|
||||
while (! IS_END(**p))
|
||||
(*p)++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
skip_curr_and_white(char **p)
|
||||
{
|
||||
(*p)++;
|
||||
|
||||
while (IS_SPACE(**p))
|
||||
(*p)++;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_ident(char **p, char *id, int numeric)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* Identifiers may have letters, digits, and some specials. */
|
||||
if ((!numeric && !isalpha(**p) && !IS_IDENT(**p)) ||
|
||||
(!isalnum(**p) && !IS_IDENT(**p))) error(ERR_ID, NULL);
|
||||
|
||||
do {
|
||||
*id++ = *(*p)++;
|
||||
if (++i >= ID_LEN)
|
||||
error(ERR_IDLEN, NULL);
|
||||
} while (isalnum(**p) || IS_IDENT(**p));
|
||||
|
||||
*id = '\0';
|
||||
}
|
||||
|
||||
|
||||
/* Read identifier which may not start with a digit. */
|
||||
void
|
||||
ident(char **p, char *id)
|
||||
{
|
||||
_ident(p, id, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Read identifier which may start with a digit. */
|
||||
void
|
||||
nident(char **p, char *id)
|
||||
{
|
||||
_ident(p, id, 1);
|
||||
}
|
||||
|
||||
|
||||
/* Read string and convert to uppercase. */
|
||||
void
|
||||
upcase(char **p, char *str)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
*str++ = (char)toupper(*(*p)++);
|
||||
if (++i >= ID_LEN)
|
||||
error(ERR_IDLEN, NULL);
|
||||
} while (isalnum(**p));
|
||||
|
||||
*str = '\0';
|
||||
}
|
||||
|
||||
|
||||
/* Read identifier and convert to uppercase. */
|
||||
void
|
||||
ident_upcase(char **p, char *id)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (!isalpha(**p) && !IS_IDENT(**p))
|
||||
error(ERR_ID, NULL);
|
||||
|
||||
do {
|
||||
*id++ = (char)toupper(*(*p)++);
|
||||
if (++i >= ID_LEN)
|
||||
error(ERR_IDLEN, NULL);
|
||||
} while (isalnum(**p) || IS_IDENT(**p));
|
||||
|
||||
*id = '\0';
|
||||
}
|
||||
|
||||
|
||||
/* Read identifier and convert to uppercase. */
|
||||
void
|
||||
nident_upcase(char **p, char *id)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
*id++ = (char)toupper(*(*p)++);
|
||||
if (++i >= ID_LEN)
|
||||
error(ERR_IDLEN, NULL);
|
||||
} while (isalnum(**p) || IS_IDENT(**p));
|
||||
|
||||
*id = '\0';
|
||||
}
|
||||
|
||||
|
||||
/* Processes one statement or assembler instruction. */
|
||||
static char *
|
||||
statement(char **p, int pass)
|
||||
{
|
||||
char id[ID_LEN], id2[ID_LEN];
|
||||
const struct pseudo *ptr;
|
||||
char *newp = NULL;
|
||||
value_t v;
|
||||
char *pt;
|
||||
|
||||
skip_white_and_comment(p);
|
||||
if (IS_END(**p))
|
||||
return NULL;
|
||||
|
||||
/* First check for variable or label definition. */
|
||||
pt = *p;
|
||||
if (isalpha(**p)) {
|
||||
ident(p, id);
|
||||
skip_white(p);
|
||||
|
||||
if ((**p == EQUAL_CHAR) || !strncmp(*p, "EQU", 3)) {
|
||||
/* Variable definition. */
|
||||
if (**p == EQUAL_CHAR)
|
||||
(*p)++;
|
||||
else
|
||||
(*p) += 3;
|
||||
|
||||
v = expr(p);
|
||||
|
||||
if (ifstate)
|
||||
define_variable(id, v);
|
||||
return NULL;
|
||||
} else if ((**p == COLON_CHAR) || !trg_instr_ok(id)) {
|
||||
/*
|
||||
* Labels either have a colon at the end, OR are anything
|
||||
* but an valid instruction. To force a label with the same
|
||||
* name as an instruction, add a colon to it :)
|
||||
*/
|
||||
if (**p == COLON_CHAR)
|
||||
(*p)++;
|
||||
|
||||
if (ifstate)
|
||||
current_label = define_label(id, pc, NULL);
|
||||
|
||||
skip_white_and_comment(p);
|
||||
if (IS_END(**p))
|
||||
return NULL;
|
||||
} else
|
||||
*p = pt;
|
||||
}
|
||||
|
||||
/* Local label definition? */
|
||||
else if (**p == ALPHA_CHAR) {
|
||||
(*p)++;
|
||||
nident(p, id);
|
||||
|
||||
if (ifstate) {
|
||||
if (current_label == NULL)
|
||||
error(ERR_NO_GLOBAL, NULL);
|
||||
|
||||
define_label(id, pc, current_label);
|
||||
}
|
||||
|
||||
skip_white(p);
|
||||
|
||||
if (**p == COLON_CHAR)
|
||||
(*p)++;
|
||||
|
||||
skip_white_and_comment(p);
|
||||
if (IS_END(**p))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check for directive or instruction. */
|
||||
again:
|
||||
if (**p == DOT_CHAR) {
|
||||
/* Local label or directive. */
|
||||
pt = *p;
|
||||
(*p)++;
|
||||
nident_upcase(p, id);
|
||||
if ((ptr = is_pseudo(id)) != NULL) {
|
||||
/* All good, we're a directive. */
|
||||
newp = pseudo(ptr, p, pass);
|
||||
|
||||
return newp;
|
||||
}
|
||||
|
||||
if (ifstate) {
|
||||
if (current_label == NULL)
|
||||
error(ERR_NO_GLOBAL, NULL);
|
||||
|
||||
/* Restore our pointer and get the label ID. */
|
||||
*p = pt;
|
||||
nident(p, id2);
|
||||
|
||||
/* We don't care about the colon. */
|
||||
if (**p == COLON_CHAR)
|
||||
(*p)++;
|
||||
|
||||
if ((strlen(current_label->name) + strlen(id2)) >= ID_LEN)
|
||||
error(ERR_IDLEN, id2);
|
||||
strcpy(id, current_label->name);
|
||||
strcat(id, id2);
|
||||
|
||||
define_label(id, pc, NULL);
|
||||
}
|
||||
|
||||
skip_white_and_comment(p);
|
||||
if (IS_END(**p))
|
||||
return NULL;
|
||||
|
||||
/* Restart scanning for statements on this line. */
|
||||
goto again;
|
||||
}
|
||||
|
||||
skip_white_and_comment(p);
|
||||
if (IS_END(**p))
|
||||
return NULL;
|
||||
|
||||
/* We only parse the rest if we are active. */
|
||||
if (ifstate) {
|
||||
if (isalpha(**p)) {
|
||||
/* Execute instruction and update program counter. */
|
||||
pc += trg_instr(p, pass);
|
||||
} else
|
||||
error(ERR_STMT, NULL);
|
||||
} else {
|
||||
/* Just skip. */
|
||||
while (! IS_END(**p))
|
||||
(*p)++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pass(char **p, int pass)
|
||||
{
|
||||
const char *msg;
|
||||
char *list;
|
||||
char *newp;
|
||||
int err;
|
||||
|
||||
errors = 0;
|
||||
line = 1;
|
||||
current_label = NULL;
|
||||
org_done = 0;
|
||||
radix = RADIX_DEFAULT;
|
||||
pc = oc = 0;
|
||||
filenames_idx = 0;
|
||||
iflevel = 0;
|
||||
ifstate = 1;
|
||||
memset(ifstack, 0x00, sizeof(ifstack));
|
||||
|
||||
list_set_head(NULL);
|
||||
|
||||
if ((err = setjmp(error_jmp)) == 0) {
|
||||
while (**p) {
|
||||
/* Save current line position for the listing. */
|
||||
list = *p;
|
||||
|
||||
newline = line + 1;
|
||||
newifstate = ifstate;
|
||||
|
||||
newp = statement(p, pass);
|
||||
|
||||
skip_white_and_comment(p);
|
||||
|
||||
/*
|
||||
* Every statement ends with a newline.
|
||||
* If it is not found here it is an error condition.
|
||||
*/
|
||||
if (! IS_END(**p))
|
||||
error(ERR_EOL, NULL);
|
||||
|
||||
skip_eol(p);
|
||||
|
||||
if (pass == 2)
|
||||
list_line(list);
|
||||
|
||||
line = newline;
|
||||
ifstate = newifstate;
|
||||
|
||||
if (**p == EOF_CHAR) {
|
||||
(*p)++;
|
||||
filenames_idx++;
|
||||
line = filelines[filenames_idx];
|
||||
}
|
||||
|
||||
if (newp != NULL)
|
||||
text = newp;
|
||||
|
||||
list_save(pc, oc);
|
||||
}
|
||||
} else {
|
||||
if (err < ERR_MAXERR)
|
||||
msg = err_msg[err];
|
||||
else
|
||||
msg = trg_error(err);
|
||||
|
||||
printf("%s:%i: error: %s",
|
||||
filenames[filenames_idx], line, msg);
|
||||
if (error_hint[0] != '\0')
|
||||
printf(" (%s)", error_hint);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
1034
src/pseudo.c
Normal file
1034
src/pseudo.c
Normal file
File diff suppressed because it is too large
Load Diff
256
src/symbol.c
Normal file
256
src/symbol.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* VASM VARCem Multi-Target Assembler.
|
||||
* A simple table-driven assembler for several 8-bit target
|
||||
* devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
* code originated from Bernd B”ckmann's "asm6502" project.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Handle symbols.
|
||||
*
|
||||
* Version: @(#)symbol.c 1.0.3 2023/04/22
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <waltje@varcem.com>
|
||||
* Bernd B”ckmann, <https://codeberg.org/boeckmann/asm6502>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "global.h"
|
||||
|
||||
|
||||
static symbol_t *symbols = NULL; // global symbol table
|
||||
|
||||
|
||||
/* Create a new symbol, initialize to defaults. */
|
||||
static symbol_t *
|
||||
sym_new(const char *name)
|
||||
{
|
||||
symbol_t *sym;
|
||||
|
||||
sym = malloc(sizeof(symbol_t));
|
||||
if (sym == NULL)
|
||||
error(ERR_MEM, name);
|
||||
memset(sym, 0x00, sizeof(symbol_t));
|
||||
|
||||
strcpy(sym->name, name);
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
|
||||
/* Return the first entry of the symbol table. */
|
||||
symbol_t *
|
||||
sym_table(void)
|
||||
{
|
||||
return symbols;
|
||||
}
|
||||
|
||||
|
||||
/* Delete all entries from a symbol table. */
|
||||
void
|
||||
sym_free(symbol_t **table)
|
||||
{
|
||||
symbol_t *sym, *next;
|
||||
|
||||
if (table == NULL)
|
||||
table = &symbols;
|
||||
|
||||
sym = *table;
|
||||
|
||||
while (sym != NULL) {
|
||||
if (sym->locals != NULL)
|
||||
sym_free(&sym->locals);
|
||||
next = sym->next;
|
||||
free(sym);
|
||||
sym = next;
|
||||
}
|
||||
|
||||
*table = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Look up a symbol in one of the tables. */
|
||||
symbol_t *
|
||||
sym_lookup(const char *name, symbol_t **table)
|
||||
{
|
||||
symbol_t *ptr;
|
||||
|
||||
if (table == NULL)
|
||||
table = &symbols;
|
||||
|
||||
for (ptr = *table; ptr != NULL; ptr = ptr->next) {
|
||||
if (! strcmp(name, ptr->name))
|
||||
return ptr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
char
|
||||
sym_type(const symbol_t *sym)
|
||||
{
|
||||
switch (sym->kind) {
|
||||
case KIND_LBL:
|
||||
return 'L';
|
||||
|
||||
case KIND_VAR:
|
||||
return 'V';
|
||||
}
|
||||
|
||||
return '-';
|
||||
}
|
||||
|
||||
|
||||
symbol_t *
|
||||
sym_aquire(const char *name, symbol_t **table)
|
||||
{
|
||||
symbol_t *ptr, *sym;
|
||||
|
||||
if (table == NULL)
|
||||
table = &symbols;
|
||||
|
||||
sym = sym_lookup(name, table);
|
||||
|
||||
if (sym == NULL) {
|
||||
sym = sym_new(name);
|
||||
|
||||
/* Insert symbol in alphabetical order. */
|
||||
if ((*table == NULL) || (strcasecmp((*table)->name, name) > 0)) {
|
||||
sym->next = *table;
|
||||
*table = sym;
|
||||
} else {
|
||||
for (ptr = *table; ptr->next != NULL; ptr = ptr->next) {
|
||||
if (strcasecmp(ptr->next->name, name) > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
sym->next = ptr->next;
|
||||
ptr->next = sym;
|
||||
}
|
||||
}
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
|
||||
symbol_t *
|
||||
define_label(const char *id, uint16_t v, symbol_t *parent)
|
||||
{
|
||||
char nid[ID_LEN];
|
||||
symbol_t *sym;
|
||||
|
||||
if (parent != NULL) {
|
||||
if (*id == DOT_CHAR) {
|
||||
/*
|
||||
* This is a "dot label", meaning, its name
|
||||
* has to be tacked on to the preceeding
|
||||
* global label's name.
|
||||
*/
|
||||
if ((strlen(parent->name) + strlen(id)) >= ID_LEN)
|
||||
error(ERR_IDLEN, id);
|
||||
strcpy(nid, parent->name);
|
||||
strcat(nid, id);
|
||||
id = nid;
|
||||
}
|
||||
sym = sym_aquire(id, &parent->locals);
|
||||
} else
|
||||
sym = sym_aquire(id, NULL);
|
||||
|
||||
if (IS_VAR(sym) || (DEFINED(sym->value) && (sym->value.v != v)))
|
||||
error(parent ? ERR_LOCAL_REDEF : ERR_REDEF, id);
|
||||
|
||||
sym->kind = KIND_LBL;
|
||||
sym->filenr = filenames_idx;
|
||||
sym->linenr = line;
|
||||
sym->value.v = v;
|
||||
sym->value.t = ((TYPE(sym->value) == TYPE_WORD)
|
||||
? TYPE_WORD : NUM_TYPE(v)) | VALUE_DEFINED;
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
define_variable(const char *id, value_t v)
|
||||
{
|
||||
symbol_t *sym;
|
||||
|
||||
sym = sym_aquire(id, NULL);
|
||||
if (DEFINED(sym->value) && (sym->value.v != v.v))
|
||||
error(ERR_REDEF, id);
|
||||
|
||||
sym->kind = KIND_VAR;
|
||||
sym->filenr = filenames_idx;
|
||||
sym->linenr = line;
|
||||
|
||||
/* if the type is already set do not change it */
|
||||
sym->value.v = v.v;
|
||||
if (TYPE(sym->value)) {
|
||||
#if 0
|
||||
if (NUM_TYPE(v.v) > TYPE(sym->value)) error(ERR_REDEF, id);
|
||||
#endif
|
||||
if (DEFINED(v))
|
||||
SET_DEFINED(sym->value);
|
||||
} else
|
||||
sym->value.t = v.t;
|
||||
|
||||
/* If previously defined as label make it word sized. */
|
||||
if (IS_LBL(sym))
|
||||
SET_TYPE(sym->value, TYPE_WORD);
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
sym_print(const symbol_t *sym)
|
||||
{
|
||||
static char buff[32];
|
||||
|
||||
switch (TYPE(sym->value)) {
|
||||
case TYPE_BYTE:
|
||||
sprintf(buff, "%02X", sym->value.v & 0xff);
|
||||
break;
|
||||
|
||||
case TYPE_WORD:
|
||||
sprintf(buff, "%04X", sym->value.v & 0xffff);
|
||||
break;
|
||||
|
||||
case TYPE_DWORD:
|
||||
sprintf(buff, "%08X", sym->value.v);
|
||||
break;
|
||||
}
|
||||
|
||||
return buff;
|
||||
}
|
||||
180
src/target.c
Normal file
180
src/target.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* VASM VARCem Multi-Target Assembler.
|
||||
* A simple table-driven assembler for several 8-bit target
|
||||
* devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
* code originated from Bernd B”ckmann's "asm6502" project.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Handle selection of a target device.
|
||||
*
|
||||
* Version: @(#)target.c 1.0.1 2023/04/20
|
||||
*
|
||||
* Author: Fred N. van Kempen, <waltje@varcem.com>
|
||||
*
|
||||
* Copyright 2023 Fred N. van Kempen.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "global.h"
|
||||
#include "target.h"
|
||||
|
||||
|
||||
extern const target_t t_6502_old,
|
||||
t_6502_nmos,
|
||||
t_csg6510,
|
||||
t_csg8500,
|
||||
t_65c02;
|
||||
|
||||
|
||||
static const target_t *targets[] = {
|
||||
&t_6502_old, // original MOS6502 (NMOS)
|
||||
&t_6502_nmos, // standard MOS6502 (NMOS)
|
||||
&t_csg6510, // CSG 6510 (NMOS)
|
||||
&t_csg8500, // CSG 8500 (NMOS)
|
||||
|
||||
&t_65c02, // standard MOS65C02 (CMOS)
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
static const target_t *target = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* Select a specific CPU or model.
|
||||
*
|
||||
* Called once to allow the back-end to set up the proper tables
|
||||
* and such, which may depend on the exact processor model used.
|
||||
*/
|
||||
int
|
||||
set_cpu(const char *p, int pass)
|
||||
{
|
||||
const target_t **t;
|
||||
|
||||
if (opt_v && (pass == 1))
|
||||
printf("Setting processor to '%s'\n", p);
|
||||
|
||||
target = NULL;
|
||||
|
||||
for (t = targets; *t != NULL; t++) {
|
||||
if (! strcasecmp((*t)->name, p)) {
|
||||
target = *t;
|
||||
|
||||
/* Create a predefined "CPU" symbol. */
|
||||
trg_symbol(target->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Create a target-specific symbol. */
|
||||
void
|
||||
trg_symbol(const char *name)
|
||||
{
|
||||
char id[ID_LEN+1];
|
||||
value_t v = { 0 };
|
||||
int i = 0;
|
||||
|
||||
id[i++] = 'P';
|
||||
do {
|
||||
id[i++] = (char)toupper(*name++);
|
||||
if (i >= ID_LEN)
|
||||
error(ERR_IDLEN, NULL);
|
||||
} while (*name != '\0');
|
||||
id[i] = '\0';
|
||||
|
||||
v.v = 1;
|
||||
SET_DEFINED(v);
|
||||
SET_TYPE(v, TYPE_BYTE);
|
||||
|
||||
define_variable(id, v);
|
||||
}
|
||||
|
||||
|
||||
/* Get a target-specific error message. */
|
||||
const char *
|
||||
trg_error(int err)
|
||||
{
|
||||
if (target == NULL)
|
||||
error(ERR_NOCPU, NULL);
|
||||
|
||||
return target->error(err);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process one instruction.
|
||||
*
|
||||
* This gets called by the main code, once per pass. Its task is
|
||||
* to process an entire instruction line, or, at least, the part
|
||||
* of the line where the assembler thinks the "code" is. So, in
|
||||
* most cases, we get called with "p" pointing to the very start
|
||||
* of the code and we can begin parsing right away.
|
||||
*
|
||||
* If we find an error, we simply call the error() function, and
|
||||
* that will properly terminate all processing for us.
|
||||
*
|
||||
* During pass 2, we will generate any code bytes, which we emit
|
||||
* by calling the emit() function.
|
||||
*/
|
||||
int
|
||||
trg_instr(char **p, int pass)
|
||||
{
|
||||
if (target == NULL)
|
||||
error(ERR_NOCPU, NULL);
|
||||
|
||||
return target->instr(target, p, pass);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check to see if the identifier matches an existing mnemonic.
|
||||
*
|
||||
* The assembler will not allow the use of these "reserved words"
|
||||
* as label names.
|
||||
*/
|
||||
int
|
||||
trg_instr_ok(const char *p)
|
||||
{
|
||||
if (target == NULL)
|
||||
error(ERR_NOCPU, NULL);
|
||||
|
||||
return target->instr_ok(target, p);
|
||||
}
|
||||
73
src/target.h
Normal file
73
src/target.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* VASM VARCem Multi-Target Assembler.
|
||||
* A simple table-driven assembler for several 8-bit target
|
||||
* devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
* code originated from Bernd B”ckmann's "asm6502" project.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Definitions for the target backends.
|
||||
*
|
||||
* Version: @(#)target.h 1.0.1 2023/04/20
|
||||
*
|
||||
* Author: Fred N. van Kempen, <waltje@varcem.com>
|
||||
*
|
||||
* Copyright 2023 Fred N. van Kempen.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef TARGET_H
|
||||
# define TARGET_H
|
||||
|
||||
|
||||
typedef struct target {
|
||||
const char *name;
|
||||
|
||||
uint32_t flags;
|
||||
|
||||
const void *priv;
|
||||
int priv2;
|
||||
|
||||
const char *(*error)(int);
|
||||
int (*instr)(const struct target *, char **, int);
|
||||
int (*instr_ok)(const struct target *, const char *);
|
||||
} target_t;
|
||||
|
||||
|
||||
extern int trg_set_cpu(const char *);
|
||||
|
||||
extern void trg_symbol(const char *);
|
||||
extern const char *trg_error(int);
|
||||
extern int trg_instr(char **, int);
|
||||
extern int trg_instr_ok(const char *);
|
||||
|
||||
|
||||
#endif /*TARGET_H*/
|
||||
758
src/targets/mos6502.c
Normal file
758
src/targets/mos6502.c
Normal file
@@ -0,0 +1,758 @@
|
||||
/*
|
||||
* VASM VARCem Multi-Target Assembler.
|
||||
* A simple table-driven assembler for several 8-bit target
|
||||
* devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
* code originated from Bernd B”ckmann's "asm6502" project.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Implement the MOS6502 series of device targets.
|
||||
*
|
||||
* We keep two copies of the opcode table - one for the original
|
||||
* NMOS version, which was also used by a number of chips done
|
||||
* by CSG (Commodore) for their systems, and one for the CMOS
|
||||
* version produced later. The CMOS version also has variants
|
||||
* from Rockwell and WDC, with even more changes.
|
||||
*
|
||||
* Version: @(#)mos6502.c 1.0.3 2023/04/18
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <waltje@varcem.com>
|
||||
* Bernd B”ckmann, <https://codeberg.org/boeckmann/asm6502>
|
||||
*
|
||||
* Copyright 2023 Fred N. van Kempen.
|
||||
* Copyright 2022,2023 Bernd B”ckmann.
|
||||
*
|
||||
* MIT License Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following
|
||||
* condition:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "../global.h"
|
||||
#include "../target.h"
|
||||
|
||||
|
||||
#define AM_NUM 15 // number of addressing modes
|
||||
# define AM_ACC 0 // A
|
||||
# define AM_IMP 1 // (none)
|
||||
# define AM_IMM 2 // #$12
|
||||
# define AM_REL 3 // LABEL
|
||||
# define AM_ZP 4 // $12
|
||||
# define AM_ZPI 5 // ($12) (C02)
|
||||
# define AM_ZPR 6 // ($12),LABEL (WDC C02)
|
||||
# define AM_ZPX 7 // $12,X
|
||||
# define AM_ZPY 8 // $12,Y
|
||||
# define AM_ABS 9 // $1234
|
||||
# define AM_ABX 10 // $1234,X
|
||||
# define AM_ABY 11 // $1234,Y
|
||||
# define AM_IND 12 // ($1234)
|
||||
# define AM_INX 13 // ($1234,X)
|
||||
# define AM_INY 14 // ($1234),Y
|
||||
#define AM_INV -1
|
||||
|
||||
#define INV 0xff // FIXME: wont work with C02 etc!
|
||||
#define AM_VALID(op, am) (op->opc[am] != INV)
|
||||
|
||||
|
||||
typedef enum {
|
||||
ERR_AM = ERR_MAXERR, // "invalid addressing mode"
|
||||
ERR_REG, // "invalid register"
|
||||
ERR_ILLAM, // "malformed addressing mode"
|
||||
ERR_INX, // "malformed indirect X addressing"
|
||||
ERR_INY, // "malformed indirect Y addressing"
|
||||
ERR_OPUNDEFT, // "undefined operand size"
|
||||
ERR_RELRNG, // "relative jump target out of range"
|
||||
|
||||
ERR_MAXTRG // last local error message
|
||||
} trg_errors_t;
|
||||
|
||||
|
||||
#define CPU_NMOS_0 0x00 // first NMOS processor, ROR bug
|
||||
#define CPU_NMOS_1 0x01 // regular NMOS core
|
||||
#define CPU_CMOS 0x02 // standard CMOS core
|
||||
#define CPU_CMOS_1 0x04 // Rockwell CMOS
|
||||
#define CPU_CMOS_2 0x08 // WDC CMOS
|
||||
|
||||
|
||||
typedef struct opcode {
|
||||
char mn[4];
|
||||
uint8_t flags;
|
||||
uint8_t opc[AM_NUM];
|
||||
} opcode_t;
|
||||
|
||||
|
||||
static const opcode_t opc_nmos[] = {
|
||||
{ "ADC", CPU_NMOS_0,
|
||||
{INV ,INV ,0x69,INV ,0x65,INV ,INV ,0x75,INV ,0x6d,0x7d,0x79,INV ,0x61,0x71}},
|
||||
{ "AND", CPU_NMOS_0,
|
||||
{INV ,INV ,0x29,INV ,0x25,INV ,INV ,0x35,INV ,0x2d,0x3d,0x39,INV ,0x21,0x31}},
|
||||
{ "ASL", CPU_NMOS_0,
|
||||
{0x0a,INV ,INV ,INV ,0x06,INV ,INV ,0x16,INV ,0x0e,0x1e,INV ,INV ,INV ,INV }},
|
||||
{ "BCC", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,0x90,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BCS", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,0xb0,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BEQ", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,0xf0,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BIT", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,INV ,0x24,INV ,INV ,INV ,INV ,0x2c,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BMI", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,0x30,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BNE", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,0xd0,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BPL", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,0x10,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BRK", CPU_NMOS_0,
|
||||
{INV ,0x00,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BVC", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,0x50,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BVS", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,0x70,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "CLC", CPU_NMOS_0,
|
||||
{INV ,0x18,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "CLD", CPU_NMOS_0,
|
||||
{INV ,0xd8,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "CLI", CPU_NMOS_0,
|
||||
{INV ,0x58,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "CLV", CPU_NMOS_0,
|
||||
{INV ,0xb8,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "CMP", CPU_NMOS_0,
|
||||
{INV ,INV ,0xc9,INV ,0xc5,INV ,INV ,0xd5,INV ,0xcd,0xdd,0xd9,INV ,0xc1,0xd1}},
|
||||
{ "CPX", CPU_NMOS_0,
|
||||
{INV ,INV ,0xe0,INV ,0xe4,INV ,INV ,INV ,INV ,0xec,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "CPY", CPU_NMOS_0,
|
||||
{INV ,INV ,0xc0,INV ,0xc4,INV ,INV ,INV ,INV ,0xcc,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "DEC", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,INV ,0xc6,INV ,INV ,0xd6,INV ,0xce,0xde,INV ,INV ,INV ,INV }},
|
||||
{ "DEX", CPU_NMOS_0,
|
||||
{INV ,0xca,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "DEY", CPU_NMOS_0,
|
||||
{INV ,0x88,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "EOR", CPU_NMOS_0,
|
||||
{INV ,INV ,0x49,INV ,0x45,INV ,INV ,0x55,INV ,0x4d,0x5d,0x59,INV ,0x41,0x51}},
|
||||
{ "INC", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,INV ,0xe6,INV ,INV ,0xf6,INV ,0xee,0xfe,INV ,INV ,INV ,INV }},
|
||||
{ "INX", CPU_NMOS_0,
|
||||
{INV ,0xe8,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "INY", CPU_NMOS_0,
|
||||
{INV ,0xc8,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{"JMP", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,0x4c,INV ,INV ,0x6c,INV ,INV }},
|
||||
{ "JSR", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,0x20,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "LDA", CPU_NMOS_0,
|
||||
{INV ,INV ,0xa9,INV ,0xa5,INV ,INV ,0xb5,INV ,0xad,0xbd,0xb9,INV ,0xa1,0xb1}},
|
||||
{ "LDX", CPU_NMOS_0,
|
||||
{INV ,INV ,0xa2,INV ,0xa6,INV ,INV ,INV ,0xb6,0xae,INV ,0xbe,INV ,INV ,INV }},
|
||||
{ "LDY", CPU_NMOS_0,
|
||||
{INV ,INV ,0xa0,INV ,0xa4,INV ,INV ,0xb4,INV ,0xac,0xbc,INV ,INV ,INV ,INV }},
|
||||
{ "LSR", CPU_NMOS_0,
|
||||
{0x4a,INV ,INV ,INV ,0x46,INV ,INV ,0x56,INV ,0x4e,0x5e,INV ,INV ,INV ,INV }},
|
||||
{ "NOP", CPU_NMOS_0,
|
||||
{INV ,0xea,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "ORA", CPU_NMOS_0,
|
||||
{INV ,INV ,0x09,INV ,0x05,INV ,INV ,0x15,INV ,0x0d,0x1d,0x19,INV ,0x01,0x11}},
|
||||
{ "PHA", CPU_NMOS_0,
|
||||
{INV ,0x48,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "PHP", CPU_NMOS_0,
|
||||
{INV ,0x08,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "PLA", CPU_NMOS_0,
|
||||
{INV ,0x68,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "PLP", CPU_NMOS_0,
|
||||
{INV ,0x28,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "ROL", CPU_NMOS_0,
|
||||
{0x2a,INV ,INV ,INV ,0x26,INV ,INV ,0x36,INV ,0x2e,0x3e,INV ,INV ,INV ,INV }},
|
||||
{ "ROR", CPU_NMOS_1,
|
||||
{0x6a,INV ,INV ,INV ,0x66,INV ,INV ,0x76,INV ,0x6e,0x7e,INV ,INV ,INV ,INV }},
|
||||
{ "RTI", CPU_NMOS_0,
|
||||
{INV ,0x40,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "RTS", CPU_NMOS_0,
|
||||
{INV ,0x60,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "SBC", CPU_NMOS_0,
|
||||
{INV ,INV ,0xe9,INV ,0xe5,INV ,INV ,0xf5,INV ,0xed,0xfd,0xf9,INV ,0xe1,0xf1}},
|
||||
{ "SEC", CPU_NMOS_0,
|
||||
{INV ,0x38,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "SED", CPU_NMOS_0,
|
||||
{INV ,0xf8,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "SEI", CPU_NMOS_0,
|
||||
{INV ,0x78,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "STA", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,INV ,0x85,INV ,INV ,0x95,INV ,0x8d,0x9d,0x99,INV ,0x81,0x91}},
|
||||
{ "STX", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,INV ,0x86,INV ,INV ,INV ,0x96,0x8e,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "STY", CPU_NMOS_0,
|
||||
{INV ,INV ,INV ,INV ,0x84,INV ,INV ,0x94,INV ,0x8c,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "TAX", CPU_NMOS_0,
|
||||
{INV ,0xaa,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "TAY", CPU_NMOS_0,
|
||||
{INV ,0xa8,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "TSX", CPU_NMOS_0,
|
||||
{INV ,0xba,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "TXA", CPU_NMOS_0,
|
||||
{INV ,0x8a,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "TXS", CPU_NMOS_0,
|
||||
{INV ,0x9a,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "TYA", CPU_NMOS_0,
|
||||
{INV ,0x98,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }}
|
||||
};
|
||||
|
||||
static const opcode_t opc_cmos[] = {
|
||||
{ "ADC", CPU_CMOS,
|
||||
{INV ,INV ,0x69,INV ,0x65,0x72,INV ,0x75,INV ,0x6d,0x7d,0x79,INV ,0x61,0x71}},
|
||||
{ "AND", CPU_CMOS,
|
||||
{INV ,INV ,0x29,INV ,0x25,0x32,INV ,0x35,INV ,0x2d,0x3d,0x39,INV ,0x21,0x31}},
|
||||
{ "ASL", CPU_CMOS,
|
||||
{0x0a,INV ,INV ,INV ,0x06,INV ,INV ,0x16,INV ,0x0e,0x1e,INV ,INV ,INV ,INV }},
|
||||
{ "BBR", CPU_CMOS,
|
||||
{INV ,INV ,INV ,INV ,INV ,INV ,0x0f,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BBS", CPU_CMOS,
|
||||
{INV ,INV ,INV ,INV ,INV ,INV ,0x8f,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BCC", CPU_CMOS,
|
||||
{INV ,INV ,INV ,0x90,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BCS", CPU_CMOS,
|
||||
{INV ,INV ,INV ,0xb0,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BEQ", CPU_CMOS,
|
||||
{INV ,INV ,INV ,0xf0,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BIT", CPU_CMOS,
|
||||
{INV ,INV ,INV ,INV ,0x24,INV ,INV ,INV ,INV ,0x2c,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BMI", CPU_CMOS,
|
||||
{INV ,INV ,INV ,0x30,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BNE", CPU_CMOS,
|
||||
{INV ,INV ,INV ,0xd0,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BPL", CPU_CMOS,
|
||||
{INV ,INV ,INV ,0x10,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BRA", CPU_CMOS,
|
||||
{INV ,INV ,INV ,0x80,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BRK", CPU_CMOS,
|
||||
{INV ,0x00,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BVC", CPU_CMOS,
|
||||
{INV ,INV ,INV ,0x50,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "BVS", CPU_CMOS,
|
||||
{INV ,INV ,INV ,0x70,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "CLC", CPU_CMOS,
|
||||
{INV ,0x18,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "CLD", CPU_CMOS,
|
||||
{INV ,0xd8,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "CLI", CPU_CMOS,
|
||||
{INV ,0x58,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "CLV", CPU_CMOS,
|
||||
{INV ,0xb8,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "CMP", CPU_CMOS,
|
||||
{INV ,INV ,0xc9,INV ,0xc5,0xd2,INV ,0xd5,INV ,0xcd,0xdd,0xd9,INV ,0xc1,0xd1}},
|
||||
{ "CPX", CPU_CMOS,
|
||||
{INV ,INV ,0xe0,INV ,0xe4,INV ,INV ,INV ,INV ,0xec,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "CPY", CPU_CMOS,
|
||||
{INV ,INV ,0xc0,INV ,0xc4,INV ,INV ,INV ,INV ,0xcc,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "DEC", CPU_CMOS,
|
||||
{0x3a,INV ,INV ,INV ,0xc6,INV ,INV ,0xd6,INV ,0xce,0xde,INV ,INV ,INV ,INV }},
|
||||
{ "DEX", CPU_CMOS,
|
||||
{INV ,0xca,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "DEY", CPU_CMOS,
|
||||
{INV ,0x88,INV ,INV ,INV ,0x52,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "EOR", CPU_CMOS,
|
||||
{INV ,INV ,0x49,INV ,0x45,INV ,INV ,0x55,INV ,0x4d,0x5d,0x59,INV ,0x41,0x51}},
|
||||
{ "INC", CPU_CMOS,
|
||||
{0x1a,INV ,INV ,INV ,0xe6,INV ,INV ,0xf6,INV ,0xee,0xfe,INV ,INV ,INV ,INV }},
|
||||
{ "INX", CPU_CMOS,
|
||||
{INV ,0xe8,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "INY", CPU_CMOS,
|
||||
{INV ,0xc8,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{"JMP", CPU_CMOS,
|
||||
{INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,0x4c,0x7c,INV ,0x6c,INV ,INV }},
|
||||
{ "JSR", CPU_CMOS,
|
||||
{INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,0x20,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "LDA", CPU_CMOS,
|
||||
{INV ,INV ,0xa9,INV ,0xa5,0xb2,INV ,0xb5,INV ,0xad,0xbd,0xb9,INV ,0xa1,0xb1}},
|
||||
{ "LDX", CPU_CMOS,
|
||||
{INV ,INV ,0xa2,INV ,0xa6,INV ,INV ,INV ,0xb6,0xae,INV ,0xbe,INV ,INV ,INV }},
|
||||
{ "LDY", CPU_CMOS,
|
||||
{INV ,INV ,0xa0,INV ,0xa4,INV ,INV ,0xb4,INV ,0xac,0xbc,INV ,INV ,INV ,INV }},
|
||||
{ "LSR", CPU_CMOS,
|
||||
{0x4a,INV ,INV ,INV ,0x46,INV ,INV ,0x56,INV ,0x4e,0x5e,INV ,INV ,INV ,INV }},
|
||||
{ "NOP", CPU_CMOS,
|
||||
{INV ,0xea,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "ORA", CPU_CMOS,
|
||||
{INV ,INV ,0x09,INV ,0x05,0x12,INV ,0x15,INV ,0x0d,0x1d,0x19,INV ,0x01,0x11}},
|
||||
{ "PHA", CPU_CMOS,
|
||||
{INV ,0x48,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "PHP", CPU_CMOS,
|
||||
{INV ,0x08,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "PHX", CPU_CMOS,
|
||||
{INV ,0xda,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "PHY", CPU_CMOS,
|
||||
{INV ,0x5a,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "PLA", CPU_CMOS,
|
||||
{INV ,0x68,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "PLP", CPU_CMOS,
|
||||
{INV ,0x28,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "PLX", CPU_CMOS,
|
||||
{INV ,0xfa,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "PLY", CPU_CMOS,
|
||||
{INV ,0x7a,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "RMB", CPU_CMOS,
|
||||
{INV ,INV ,INV ,INV ,INV ,INV ,0x07,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "ROL", CPU_CMOS,
|
||||
{0x2a,INV ,INV ,INV ,0x26,INV ,INV ,0x36,INV ,0x2e,0x3e,INV ,INV ,INV ,INV }},
|
||||
{ "ROR", CPU_NMOS_1,
|
||||
{0x6a,INV ,INV ,INV ,0x66,INV ,INV ,0x76,INV ,0x6e,0x7e,INV ,INV ,INV ,INV }},
|
||||
{ "RTI", CPU_CMOS,
|
||||
{INV ,0x40,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "RTS", CPU_CMOS,
|
||||
{INV ,0x60,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "SBC", CPU_CMOS,
|
||||
{INV ,INV ,0xe9,INV ,0xe5,0xf2,INV ,0xf5,INV ,0xed,0xfd,0xf9,INV ,0xe1,0xf1}},
|
||||
{ "SEC", CPU_CMOS,
|
||||
{INV ,0x38,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "SED", CPU_CMOS,
|
||||
{INV ,0xf8,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "SEI", CPU_CMOS,
|
||||
{INV ,0x78,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "SMB", CPU_CMOS,
|
||||
{INV ,INV ,INV ,INV ,INV ,INV ,0x87,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "STA", CPU_CMOS,
|
||||
{INV ,INV ,INV ,INV ,0x85,0x92,INV ,0x95,INV ,0x8d,0x9d,0x99,INV ,0x81,0x91}},
|
||||
{ "STP", CPU_CMOS|CPU_CMOS_2,
|
||||
{INV ,0xdb,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "STX", CPU_CMOS,
|
||||
{INV ,INV ,INV ,INV ,0x86,INV ,INV ,INV ,0x96,0x8e,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "STY", CPU_CMOS,
|
||||
{INV ,INV ,INV ,INV ,0x84,INV ,INV ,0x94,INV ,0x8c,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "STZ", CPU_CMOS,
|
||||
{INV ,INV ,INV ,INV ,0x64,INV ,INV ,0x74,INV ,0x9c,0x9e,INV ,INV ,INV ,INV }},
|
||||
{ "TAX", CPU_CMOS,
|
||||
{INV ,0xaa,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "TAY", CPU_CMOS,
|
||||
{INV ,0xa8,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "TRB", CPU_CMOS,
|
||||
{INV ,INV ,INV ,INV ,0x14,INV ,INV ,INV ,INV ,0x1c,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "TSB", CPU_CMOS,
|
||||
{INV ,INV ,INV ,INV ,0x04,INV ,INV ,INV ,INV ,0x0c,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "TSX", CPU_CMOS,
|
||||
{INV ,0xba,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "TXA", CPU_CMOS,
|
||||
{INV ,0x8a,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "TXS", CPU_CMOS,
|
||||
{INV ,0x9a,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "TYA", CPU_CMOS,
|
||||
{INV ,0x98,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }},
|
||||
{ "WAI", CPU_CMOS|CPU_CMOS_2,
|
||||
{INV ,0xcb,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV ,INV }}
|
||||
};
|
||||
|
||||
|
||||
static const uint16_t am_size[AM_NUM] = { 1,1,2,2,2,2,2,2,2,3,3,3,3,2,2 };
|
||||
|
||||
|
||||
static const char *err_msg[] = {
|
||||
"invalid addressing mode",
|
||||
"invalid register",
|
||||
"malformed indirect X addressing",
|
||||
"malformed indirect Y addressing",
|
||||
"malformed addressing mode",
|
||||
"undefined operand size",
|
||||
"relative jump target out of range"
|
||||
};
|
||||
|
||||
|
||||
/* Handle the Implied and Accumulator modes. */
|
||||
static int
|
||||
op_imp_acc(char **p, int pass, const opcode_t *instr)
|
||||
{
|
||||
char id[ID_LEN];
|
||||
int am = AM_IMP;
|
||||
char *str = *p;
|
||||
|
||||
/* We only handle Implied and Accumulator. */
|
||||
if ((instr->opc[AM_ACC] == INV) &&
|
||||
(instr->opc[AM_IMP] == INV)) return AM_INV;
|
||||
|
||||
/* See if we have a register name. */
|
||||
if (! IS_END(**p)) {
|
||||
/* Looks like it, get it. */
|
||||
upcase(p, id);
|
||||
|
||||
/* We only allow the A register. */
|
||||
if (strcmp(id, "A")) {
|
||||
*p = str;
|
||||
#if 0
|
||||
/* Not an error, we are TRYING these to AMs.. */
|
||||
error(ERR_REG, id);
|
||||
#else
|
||||
return AM_INV;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* OK, all good. */
|
||||
}
|
||||
|
||||
if (instr->opc[AM_ACC] != INV)
|
||||
am = AM_ACC;
|
||||
else if (instr->opc[AM_IMP] != INV)
|
||||
am = AM_IMP;
|
||||
else
|
||||
error(ERR_AM, NULL);
|
||||
|
||||
emit_byte(instr->opc[am], pass);
|
||||
|
||||
return am;
|
||||
}
|
||||
|
||||
|
||||
/* Handle the Immediate mode. */
|
||||
static int
|
||||
op_imm(char **p, int pass, const opcode_t *instr)
|
||||
{
|
||||
int am = AM_IMM;
|
||||
value_t v;
|
||||
|
||||
(*p)++;
|
||||
if (instr->opc[am] == INV) error(ERR_AM, NULL);
|
||||
v = expr(p);
|
||||
if (pass == 2)
|
||||
if (UNDEFINED(v)) error(ERR_UNDEF, NULL);
|
||||
|
||||
emit_byte(instr->opc[am], pass);
|
||||
emit_byte((uint8_t)to_byte(v).v, pass);
|
||||
|
||||
return am;
|
||||
}
|
||||
|
||||
|
||||
/* Handle the Relative mode. */
|
||||
static int
|
||||
op_rel(int pass, const opcode_t *instr, value_t v)
|
||||
{
|
||||
int am = AM_REL;
|
||||
uint16_t pct = pc + 2u;
|
||||
uint16_t off;
|
||||
|
||||
/* relative branch offsets are in 2-complement */
|
||||
/* have to calculate it by hand avoiding implementation defined behaviour */
|
||||
/* using unsigned int because int may not be in 2-complement */
|
||||
if (pass == 2) {
|
||||
if (UNDEFINED(v)) error(ERR_UNDEF, NULL);
|
||||
|
||||
if ((v.v >= pct) && ((uint16_t)(v.v - pct) > 0x7f))
|
||||
error(ERR_RELRNG, NULL);
|
||||
else if ((pct > v.v) && ((uint16_t)(pct - v.v) > 0x80))
|
||||
error(ERR_RELRNG, NULL);
|
||||
}
|
||||
|
||||
if (v.v >= pct)
|
||||
off = v.v - pct;
|
||||
else
|
||||
off = (uint16_t)((~0) - (pct - v.v - 1));
|
||||
|
||||
emit_byte(instr->opc[am], pass);
|
||||
emit_byte(off & 0xff, pass);
|
||||
|
||||
return am;
|
||||
}
|
||||
|
||||
|
||||
/* Handle the Indirect mode. */
|
||||
static int
|
||||
op_ind(char **p, int pass, const opcode_t *instr)
|
||||
{
|
||||
char id[ID_LEN];
|
||||
int am = AM_INV;
|
||||
value_t v;
|
||||
|
||||
(*p)++;
|
||||
v = expr(p);
|
||||
skip_white(p);
|
||||
|
||||
/* indirect X addressing mode? */
|
||||
if (**p == ',') {
|
||||
skip_curr_and_white(p);
|
||||
ident_upcase(p, id);
|
||||
if (strcmp(id, "X"))
|
||||
error(ERR_INX, NULL);
|
||||
am = AM_INX;
|
||||
skip_white(p);
|
||||
if (**p != ')')
|
||||
error(ERR_CLBR, NULL);
|
||||
skip_curr_and_white(p);
|
||||
} else {
|
||||
if (**p != ')')
|
||||
error(ERR_CLBR, NULL);
|
||||
skip_curr_and_white(p);
|
||||
|
||||
/* indirect Y addressing mode? */
|
||||
if (**p == ',') {
|
||||
skip_curr_and_white(p);
|
||||
ident_upcase(p, id);
|
||||
|
||||
if (strcmp(id, "Y"))
|
||||
error(ERR_INY, NULL);
|
||||
am = AM_INY;
|
||||
} else
|
||||
am = AM_IND;
|
||||
}
|
||||
|
||||
if ((instr->opc[am]) == INV)
|
||||
error(ERR_AM, NULL);
|
||||
|
||||
if (pass == 2) {
|
||||
if (UNDEFINED(v))
|
||||
error(ERR_UNDEF, NULL);
|
||||
if (((am == AM_INX) || am == (AM_INY)) && (TYPE(v) != TYPE_BYTE))
|
||||
error(ERR_ILLTYPE, NULL);
|
||||
}
|
||||
|
||||
emit_byte(instr->opc[am], pass);
|
||||
if (am == AM_IND)
|
||||
emit_word(v.v, pass);
|
||||
else
|
||||
emit_byte((uint8_t)to_byte(v).v, pass);
|
||||
|
||||
return am;
|
||||
}
|
||||
|
||||
|
||||
/* Handle the absolute X and Y, zeropage X and Y modes. */
|
||||
static int
|
||||
op_abxy_zpxy(char **p, int pass, const opcode_t *instr, value_t v)
|
||||
{
|
||||
char id[ID_LEN];
|
||||
int am = AM_INV;
|
||||
|
||||
ident_upcase(p, id);
|
||||
|
||||
/* Test for absolute and zeropage X addressing. */
|
||||
if (! strcmp(id, "X")) {
|
||||
if ((TYPE(v) == TYPE_BYTE) && AM_VALID(instr, AM_ZPX))
|
||||
am = AM_ZPX;
|
||||
else if (AM_VALID(instr, AM_ABX))
|
||||
am = AM_ABX;
|
||||
else
|
||||
error(ERR_AM, NULL);
|
||||
}
|
||||
|
||||
/* Test for absolute and zeropage Y addressing. */
|
||||
else if (! strcmp(id, "Y")) {
|
||||
if ((TYPE(v) == TYPE_BYTE) && AM_VALID(instr, AM_ZPY))
|
||||
am = AM_ZPY;
|
||||
else if (AM_VALID(instr, AM_ABY))
|
||||
am = AM_ABY;
|
||||
else
|
||||
error(ERR_AM, NULL);
|
||||
}
|
||||
else
|
||||
error(ERR_AM, NULL);
|
||||
|
||||
if (pass == 2)
|
||||
if (UNDEFINED(v)) error(ERR_UNDEF, NULL);
|
||||
|
||||
emit_byte(instr->opc[am], pass);
|
||||
if ((am == AM_ZPX) || (am == AM_ZPY))
|
||||
emit_byte((uint8_t)to_byte(v).v, pass);
|
||||
else
|
||||
emit_word(v.v, pass);
|
||||
|
||||
return am;
|
||||
}
|
||||
|
||||
|
||||
/* Handle the Absolute and Zeropage modes. */
|
||||
static int
|
||||
op_abs_zp(int pass, const opcode_t *instr, value_t v)
|
||||
{
|
||||
int am = AM_INV;
|
||||
|
||||
if ((TYPE(v) == TYPE_BYTE) && AM_VALID(instr, AM_ZP)) {
|
||||
am = AM_ZP;
|
||||
|
||||
if (pass == 2) {
|
||||
if (UNDEFINED(v)) error(ERR_UNDEF, NULL);
|
||||
}
|
||||
|
||||
emit_byte(instr->opc[am], pass);
|
||||
emit_byte((uint8_t)to_byte(v).v, pass);
|
||||
} else if (AM_VALID(instr, AM_ABS)) {
|
||||
am = AM_ABS;
|
||||
|
||||
if (pass == 2) {
|
||||
if (UNDEFINED(v)) error(ERR_UNDEF, NULL);
|
||||
}
|
||||
|
||||
emit_byte(instr->opc[am], pass);
|
||||
emit_word(v.v, pass);
|
||||
} else
|
||||
error(ERR_AM, NULL);
|
||||
|
||||
return am;
|
||||
}
|
||||
|
||||
|
||||
/* Look up a mnemonic in the table. */
|
||||
static const opcode_t *
|
||||
get_mnemonic(const opcode_t *table, int size, const char *p)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
if (! strcmp(p, table[i].mn))
|
||||
return &table[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process one instruction.
|
||||
*
|
||||
* This gets called by the main code, once per pass. Its task is
|
||||
* to process an entire instruction line, or, at least, the part
|
||||
* of the line where the assembler thinks the "code" is. So, in
|
||||
* most cases, we get called with "p" pointing to the very start
|
||||
* of the code and we can begin parsing right away.
|
||||
*
|
||||
* If we find an error, we simply call the error() function, and
|
||||
* that will properly terminate all processing for us.
|
||||
*
|
||||
* During pass 2, we will generate any code bytes, which we emit
|
||||
* by calling the emit() function.
|
||||
*/
|
||||
static int
|
||||
t_instr(const target_t *trg, char **p, int pass)
|
||||
{
|
||||
char id[ID_LEN];
|
||||
const opcode_t *op;
|
||||
int am = AM_INV;
|
||||
value_t v;
|
||||
|
||||
/* Convert the mnemonic to uppercase. */
|
||||
ident_upcase(p, id);
|
||||
|
||||
/* First get instruction for given mnemonic. */
|
||||
op = get_mnemonic((const opcode_t *)trg->priv, trg->priv2, id);
|
||||
if (op == NULL)
|
||||
error(ERR_INSTR, NULL);
|
||||
|
||||
/* Found, so get addressing mode. */
|
||||
skip_white_and_comment(p);
|
||||
|
||||
/* Try Accumulator or implied first. */
|
||||
if ((am = op_imp_acc(p, pass, op)) != AM_INV) {
|
||||
/* Good, we handled that. */
|
||||
} else if (**p == '#') {
|
||||
/* Immediate mode. */
|
||||
am = op_imm(p, pass, op);
|
||||
} else if (**p == '(') {
|
||||
/* Indirect addressing modes. */
|
||||
am = op_ind(p, pass, op);
|
||||
} else {
|
||||
/* Relative and absolute addressing modes. */
|
||||
v = expr(p);
|
||||
skip_white(p);
|
||||
|
||||
/* Relative instruction mode if instruction supports it. */
|
||||
if (op->opc[AM_REL] != INV) {
|
||||
am = op_rel(pass, op, v);
|
||||
} else if (**p == ',') {
|
||||
/* .. else we try the possible absolute addressing modes. */
|
||||
skip_curr_and_white(p);
|
||||
am = op_abxy_zpxy(p, pass, op, v);
|
||||
} else {
|
||||
/* Must be absolute or zeropage addressing. */
|
||||
am = op_abs_zp(pass, op, v);
|
||||
}
|
||||
}
|
||||
|
||||
/* Bail out if that could not be done. */
|
||||
if (am == AM_INV)
|
||||
error(ERR_AM, id);
|
||||
|
||||
/* Return the amount of code generated. */
|
||||
return am_size[am];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check to see if the identifier matches an existing mnemonic.
|
||||
*
|
||||
* The assembler will not allow the use of these "reserved words"
|
||||
* as label names.
|
||||
*/
|
||||
static int
|
||||
t_instr_ok(const target_t *trg, const char *p)
|
||||
{
|
||||
char id[ID_LEN], *ptr;
|
||||
const opcode_t *op;
|
||||
|
||||
/* Convert the mnemonic to uppercase. */
|
||||
ptr = id;
|
||||
while (*p != '\0')
|
||||
*ptr++ = (char)toupper(*p++);
|
||||
*ptr = '\0';
|
||||
|
||||
/* First get instruction for given mnemonic. */
|
||||
op = get_mnemonic((const opcode_t *)trg->priv, trg->priv2, id);
|
||||
if (op != NULL)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a local error message.
|
||||
*/
|
||||
static const char *
|
||||
t_error(int err)
|
||||
{
|
||||
if (err < ERR_MAXTRG)
|
||||
return err_msg[err - ERR_MAXERR];
|
||||
|
||||
return "??";
|
||||
}
|
||||
|
||||
|
||||
const target_t t_6502_old = {
|
||||
"6502_old", CPU_CMOS,
|
||||
opc_nmos, (sizeof(opc_nmos) / sizeof(opcode_t)),
|
||||
t_error, t_instr, t_instr_ok
|
||||
};
|
||||
|
||||
const target_t t_6502_nmos = {
|
||||
"6502", CPU_NMOS_1,
|
||||
opc_nmos, (sizeof(opc_nmos) / sizeof(opcode_t)),
|
||||
t_error, t_instr, t_instr_ok
|
||||
};
|
||||
|
||||
const target_t t_csg6510 = {
|
||||
"6510", CPU_NMOS_1,
|
||||
opc_nmos, (sizeof(opc_nmos) / sizeof(opcode_t)),
|
||||
t_error, t_instr, t_instr_ok
|
||||
};
|
||||
|
||||
const target_t t_csg8500 = {
|
||||
"8500", CPU_NMOS_1,
|
||||
opc_nmos, (sizeof(opc_nmos) / sizeof(opcode_t)),
|
||||
t_error, t_instr, t_instr_ok
|
||||
};
|
||||
|
||||
const target_t t_65c02 = {
|
||||
"65c02", CPU_CMOS,
|
||||
opc_cmos, (sizeof(opc_cmos) / sizeof(opcode_t)),
|
||||
t_error, t_instr, t_instr_ok
|
||||
};
|
||||
280
src/unix/Makefile.GCC
Normal file
280
src/unix/Makefile.GCC
Normal file
@@ -0,0 +1,280 @@
|
||||
#
|
||||
# VASM VARCem Multi-Target Assembler.
|
||||
# A simple table-driven assembler for several 8-bit target
|
||||
# devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
# code originated from Bernd B”ckmann's "asm6502" project.
|
||||
#
|
||||
# This file is part of the VARCem Project.
|
||||
#
|
||||
# Makefile for UNIX-like systems using the GCC environment.
|
||||
#
|
||||
# Version: @(#)Makefile.GCC 1.1.0 2023/04/22
|
||||
#
|
||||
# Author: Fred N. van Kempen, <waltje@varcem.com>
|
||||
#
|
||||
# Copyright 2023 Fred N. van Kempen.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with
|
||||
# or without modification, are permitted provided that the
|
||||
# following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the entire
|
||||
# above notice, this list of conditions and the following
|
||||
# disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the
|
||||
# following disclaimer in the documentation and/or other
|
||||
# materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names
|
||||
# of its contributors may be used to endorse or promote
|
||||
# products derived from this software without specific
|
||||
# prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
ifndef ARCH
|
||||
ARCH := x86
|
||||
endif
|
||||
|
||||
ifndef DEBUG
|
||||
DEBUG := n
|
||||
endif
|
||||
|
||||
|
||||
# Where is the VARCem tree?
|
||||
VARCEM := ../../../..
|
||||
|
||||
# Where is our Ihex support library?
|
||||
IHEX := $(VARCEM)/contrib/Ihex
|
||||
INCS += -I$(IHEX)/include
|
||||
LDIR += -L$(IHEX)/lib/$(ARCH)/linux
|
||||
LDLIBS += -lihex #_s
|
||||
|
||||
|
||||
DEFS := -DUSE_IHEX -DALLOW_UNDEFINED_IF
|
||||
|
||||
|
||||
#########################################################################
|
||||
# Nothing should need changing from here on.. #
|
||||
#########################################################################
|
||||
|
||||
# Import the various platform/architecture names.
|
||||
ifdef MAKEFILE_LIST
|
||||
#TOPDIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
|
||||
TOPDIR := /project/VARCem/src/build
|
||||
TOPFILE := $(abspath $(firstword $(MAKEFILE_LIST)))
|
||||
else
|
||||
TOPDIR := ./build
|
||||
TOPFILE := Makefile.GCC
|
||||
endif
|
||||
include $(TOPDIR)/OSDetect.mk
|
||||
include $(TOPDIR)/archs.mk
|
||||
|
||||
# Definitions for this enivonment.
|
||||
DEVENV := gcc
|
||||
DEPS = -MMD -MF $*.d
|
||||
DEPFILE := .depends-$(DEVENV)
|
||||
|
||||
|
||||
# Compilation for X86.
|
||||
ifeq ($(ARCH), x86)
|
||||
TARGET := 32
|
||||
PREFIX :=
|
||||
RCTARGET := pe-i386
|
||||
|
||||
AFLAGS := -msse2 -mfpmath=sse
|
||||
ifeq ($(OPTIM), y)
|
||||
DFLAGS := -march=native
|
||||
else
|
||||
DFLAGS := -march=i686
|
||||
endif
|
||||
endif
|
||||
|
||||
# Compilation for X64.
|
||||
ifeq ($(ARCH), x64)
|
||||
TARGET := 64
|
||||
PREFIX :=
|
||||
RCTARGET := pe-x86-64
|
||||
|
||||
ifeq ($(OPTIM), y)
|
||||
DFLAGS := -march=native
|
||||
endif
|
||||
endif
|
||||
|
||||
# Compilation for ARM.
|
||||
ifeq ($(ARCH), armv7)
|
||||
error Target ARM7 not supported yet !
|
||||
endif
|
||||
|
||||
# Compilation for ARM64.
|
||||
ifeq ($(ARCH), aarch64)
|
||||
error Target ARM64 not supported yet !
|
||||
endif
|
||||
|
||||
|
||||
# The various toolchain programs.
|
||||
CC := gcc -m$(TARGET)
|
||||
CXX := g++ -m$(TARGET)
|
||||
CPP := cpp -P
|
||||
LINK := gcc -m$(TARGET)
|
||||
AR := ar
|
||||
RANLIB := ranlib
|
||||
STRIP := strip
|
||||
ifndef CAT
|
||||
CAT := cat
|
||||
endif
|
||||
|
||||
# Set up the correct toolchain flags.
|
||||
OPTS := -DARCH=$(ARCH) \
|
||||
-D_CRT_NON_CONFORMING_SWPRINTFS
|
||||
AOPTS := r
|
||||
LOPTS :=
|
||||
|
||||
# General build options.
|
||||
ifeq ($(DEBUG), y)
|
||||
DFLAGS += -ggdb -D_DEBUG
|
||||
AOPTIM :=
|
||||
ifndef COPTIM
|
||||
COPTIM := -Og
|
||||
endif
|
||||
else
|
||||
ifeq ($(OPTIM), y)
|
||||
AOPTIM := -mtune=native
|
||||
ifndef COPTIM
|
||||
COPTIM := -O3
|
||||
endif
|
||||
else
|
||||
ifndef COPTIM
|
||||
COPTIM := -O3
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
OPTS +=
|
||||
ifeq ($(PROFILER), y)
|
||||
LOPTS += -Xlinker -Map=$(PROG).map
|
||||
endif
|
||||
|
||||
|
||||
# Final fixups.
|
||||
INCS += -Iunix
|
||||
|
||||
# Final versions of the toolchain flags.
|
||||
CFLAGS = $(WX_FLAGS) $(OPTS) $(DFLAGS) $(COPTIM) $(AOPTIM) \
|
||||
$(AFLAGS) $(INCS) $(DEFS) -mstackrealign \
|
||||
-fomit-frame-pointer -fno-strict-aliasing \
|
||||
-Wall -Wundef #-Wmissing-declarations
|
||||
LDFLAGS := $(LOPTS) $(DFLAGS) $(LDIR)
|
||||
ARFLAGS := $(AOPTS)
|
||||
|
||||
|
||||
# Build module rules.
|
||||
.SUFFIXES: .c .cpp .o
|
||||
|
||||
ifeq ($(AUTODEP), y)
|
||||
%.o: %.c
|
||||
@echo Compiling $<
|
||||
@$(CC) $(CFLAGS) $(DEPS) -c $<
|
||||
else
|
||||
%.o: %.c
|
||||
@echo Compiling $<
|
||||
@$(CC) $(CFLAGS) -c $<
|
||||
|
||||
%.d: %.c $(wildcard $*.d)
|
||||
@echo Compiling $<
|
||||
@$(CC) $(CFLAGS) $(DEPS) -E $< >NUL
|
||||
endif
|
||||
|
||||
|
||||
#########################################################################
|
||||
# Nothing should need changing from here on.. #
|
||||
#########################################################################
|
||||
|
||||
VPATH := unix . targets
|
||||
|
||||
#LIBS :=
|
||||
#LOBJ :=
|
||||
|
||||
PROG := vasm
|
||||
SYSOBJ :=
|
||||
OBJ := $(SYSOBJ) \
|
||||
main.o symbol.o expr.o func.o input.o output.o list.o \
|
||||
parse.o pseudo.o \
|
||||
target.o \
|
||||
mos6502.o
|
||||
|
||||
|
||||
all: $(LIBS) $(PROG)
|
||||
|
||||
|
||||
libfoo.dll.a libfoo.so: $(LOBJ)
|
||||
@echo Linking shared library $@ ..
|
||||
@$(LINK) $(LDFLAGS) -shared -o $@ \
|
||||
$(LOBJ)
|
||||
$(if $(filter $(DEBUG),y),,@$(STRIP) --strip-unneeded $@)
|
||||
|
||||
libfoo.a: $(LOBJ)
|
||||
@echo Creating static library $@ ..
|
||||
@$(AR) $(ARFLAGS) $@ $(LOBJ)
|
||||
@$(RANLIB) $@
|
||||
|
||||
vasm: $(OBJ)
|
||||
@echo Linking $@ ..
|
||||
@$(LINK) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) $(LDLIBS)
|
||||
$(if $(filter $(DEBUG),y),,@$(STRIP) $@)
|
||||
|
||||
test: tests/hello.asm
|
||||
@echo Assembling hello.asm ..
|
||||
@asm6502 -v -o hello $<
|
||||
|
||||
clean:
|
||||
@echo Cleaning objects..
|
||||
@-rm -f *.o
|
||||
@-rm -f *.d
|
||||
@echo Cleaning resources..
|
||||
|
||||
|
||||
clobber: clean
|
||||
@echo Removing executables..
|
||||
@-rm -f $(PROG)
|
||||
@echo Cleaning libraries..
|
||||
@-rm -f *.so
|
||||
@-rm -f *.a
|
||||
# @-rm -f $(DEPFILE)
|
||||
|
||||
depclean:
|
||||
@-del $(DEPFILE)
|
||||
@echo Creating dependencies..
|
||||
@echo # Run "make depends" to re-create this file. >$(DEPFILE)
|
||||
|
||||
depends: DEPOBJ=$(OBJ:%.o=%.d)
|
||||
depends: depclean $(DEPOBJ)
|
||||
@$(CAT) $(DEPOBJ) >>$(DEPFILE)
|
||||
@-del $(DEPOBJ)
|
||||
|
||||
$(DEPFILE):
|
||||
|
||||
|
||||
# Module dependencies.
|
||||
ifeq ($(AUTODEP), y)
|
||||
-include *.d
|
||||
else
|
||||
ifneq ($(wildcard $(DEPFILE)), )
|
||||
include $(wildcard $(DEPFILE))
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
# End of Makefile.GCC.
|
||||
79
src/version.h
Normal file
79
src/version.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* VASM VARCem Multi-Target Assembler.
|
||||
* A simple table-driven assembler for several 8-bit target
|
||||
* devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
* code originated from Bernd B”ckmann's "asm6502" project.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Define application version and build info.
|
||||
*
|
||||
* Version: @(#)version.h 1.0.4 2023/04/22
|
||||
*
|
||||
* Author: Fred N. van Kempen, <waltje@varcem.com>
|
||||
*
|
||||
* Copyright 2023 Fred N. van Kempen.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef VERSION_H
|
||||
# define VERSION_H
|
||||
|
||||
|
||||
/* Application name. */
|
||||
#define APP_NAME "VARCem VASM"
|
||||
#define APP_TITLE "VARCem Multi-Target Assembler"
|
||||
|
||||
/* Version info. */
|
||||
#define APP_VER_MAJOR 1
|
||||
#define APP_VER_MINOR 0
|
||||
#define APP_VER_REV 12
|
||||
#define APP_VER_PATCH 0
|
||||
|
||||
|
||||
/* Standard C preprocessor macros. */
|
||||
#define STR_STRING(x) #x
|
||||
#define STR(x) STR_STRING(x)
|
||||
#define STR_RC(a,e) a ## , ## e
|
||||
|
||||
|
||||
/* These are used in the application. */
|
||||
#define APP_VER_NUM APP_VER_MAJOR.APP_VER_MINOR.APP_VER_REV
|
||||
#if defined(APP_VER_PATCH) && APP_VER_PATCH > 0
|
||||
# define APP_VER_NUM_4 APP_VER_MAJOR.APP_VER_MINOR.APP_VER_REV.APP_VER_PATCH
|
||||
#else
|
||||
# define APP_VER_NUM_4 APP_VER_MAJOR.APP_VER_MINOR.APP_VER_REV.0
|
||||
#endif
|
||||
#define APP_VERSION STR(APP_VER_NUM)
|
||||
#define APP_VERSION_4 STR(APP_VER_NUM_4)
|
||||
|
||||
|
||||
#endif /*VERSION_H*/
|
||||
303
src/win/Makefile.MSVC
Normal file
303
src/win/Makefile.MSVC
Normal file
@@ -0,0 +1,303 @@
|
||||
#
|
||||
# VARCem Virtual ARchaeological Computer EMulator.
|
||||
# An emulator of (mostly) x86-based PC systems and devices,
|
||||
# using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
# spanning the era between 1981 and 1995.
|
||||
#
|
||||
# This file is part of the VARCem Project.
|
||||
#
|
||||
# Makefile for Windows using Visual Studio 2019.
|
||||
#
|
||||
# Version: @(#)Makefile.MSVC 1.1.0 2023/04/24
|
||||
#
|
||||
# Author: Fred N. van Kempen, <waltje@varcem.com>
|
||||
#
|
||||
# Copyright 2023 Fred N. van Kempen.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with
|
||||
# or without modification, are permitted provided that the
|
||||
# following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the entire
|
||||
# above notice, this list of conditions and the following
|
||||
# disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the
|
||||
# following disclaimer in the documentation and/or other
|
||||
# materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names
|
||||
# of its contributors may be used to endorse or promote
|
||||
# products derived from this software without specific
|
||||
# prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
ifndef ARCH
|
||||
ARCH := x86
|
||||
endif
|
||||
|
||||
ifndef DEBUG
|
||||
DEBUG := n
|
||||
endif
|
||||
|
||||
|
||||
# Where is the VARCem tree?
|
||||
VARCEM := ../../../..
|
||||
|
||||
# Where is our Ihex support library?
|
||||
IHEX := $(VARCEM)/contrib/Ihex
|
||||
INCS += -I$(IHEX)/include -DUSE_IHEX=3
|
||||
LDIR += -LIBPATH:$(IHEX)/lib/$(ARCH)
|
||||
LDLIBS += ihex_s.lib
|
||||
|
||||
|
||||
DEFS := -DALLOW_UNDEFINED_IF
|
||||
|
||||
|
||||
#########################################################################
|
||||
# Nothing should need changing from here on.. #
|
||||
#########################################################################
|
||||
|
||||
# Definitions for this enivonment.
|
||||
DEVENV := msvc
|
||||
DEPS = -MMD -MF $*.d
|
||||
DEPFILE := .depends-$(DEVENV)
|
||||
|
||||
|
||||
# Compilation for Windows X86.
|
||||
ifeq ($(ARCH), x86)
|
||||
MACH := /MACHINE:$(ARCH)
|
||||
|
||||
# Allow for WinXP-SP3 builds in 32-bit mode.
|
||||
LOPTS_OS := ,5.01
|
||||
|
||||
ifeq ($(OPTIM), y)
|
||||
AFLAGS := /arch:AVX2
|
||||
else
|
||||
AFLAGS := /arch:SSE2
|
||||
endif
|
||||
endif
|
||||
|
||||
# Compilation for Windows X64.
|
||||
ifeq ($(ARCH), x64)
|
||||
MACH := /MACHINE:$(ARCH)
|
||||
LOPTS_OS :=
|
||||
endif
|
||||
|
||||
# Compilation for Windows ARM.
|
||||
ifeq ($(ARCH), arm)
|
||||
MACH := /MACHINE:arm
|
||||
LOPTS_OS :=
|
||||
# Static-link the VC runtime to avoid DLL problems on Windows RT.
|
||||
VCRUNTIME := MT
|
||||
endif
|
||||
|
||||
# Compilation for Windows ARM64.
|
||||
ifeq ($(ARCH), arm64)
|
||||
MACH := /MACHINE:arm64
|
||||
LOPTS_OS :=
|
||||
|
||||
# fatal error LNK1322: cannot avoid potential ARM hazard (Cortex-A53
|
||||
# MPCore processor bug #843419) in section #3; please consider using
|
||||
# compiler option /Gy if it was not used.
|
||||
COPTS += /Gy
|
||||
endif
|
||||
|
||||
|
||||
# The various toolchain programs.
|
||||
CC := cl.exe /nologo
|
||||
CXX := cl.exe /nologo
|
||||
CPP := cl.exe /nologo /EP
|
||||
LINK := link.exe /NOLOGO
|
||||
WINDRES := rc.exe /NOLOGO
|
||||
AR := lib.exe /NOLOGO $(MACH)
|
||||
ifndef CAT
|
||||
CAT := cat
|
||||
endif
|
||||
|
||||
# Set up the correct toolchain flags.
|
||||
OPTS := /DARCH=$(ARCH) \
|
||||
/D_CRT_SECURE_NO_WARNINGS \
|
||||
/D_CRT_NONSTDC_NO_DEPRECATE \
|
||||
/D_USE_MATH_DEFINES \
|
||||
/D_WINSOCK_DEPRECATED_NO_WARNINGS
|
||||
COPTS += /W3
|
||||
CXXOPTS += /EHsc
|
||||
LOPTS := $(MACH)
|
||||
ifndef VCRUNTIME
|
||||
VCRUNTIME := MD
|
||||
endif
|
||||
ARFLAGS :=
|
||||
LFLAGS :=
|
||||
RCOPTS := /r /n /dRC_INVOKED /d_MSC_VER /fo
|
||||
|
||||
|
||||
# General build options.
|
||||
ifeq ($(DEBUG), y)
|
||||
OPTS += -D_DEBUG
|
||||
VCRUNTIME := $(VCRUNTIME)d
|
||||
DOPTS = /Gs /Zi
|
||||
RCOPTS := -D_DEBUG $(RCOPTS)
|
||||
LOPTS += /DEBUG
|
||||
ifndef COPTIM
|
||||
COPTIM := /Od /Ob3
|
||||
endif
|
||||
else
|
||||
LOPTS += /DEBUG:NONE #/LTCG
|
||||
DOPTS = #/GL
|
||||
ifndef COPTIM
|
||||
COPTIM := /Ox /Ob3
|
||||
endif
|
||||
endif
|
||||
COPTS += /$(VCRUNTIME)
|
||||
ifeq ($(PROFILER), y)
|
||||
LOPTS += /MAP
|
||||
endif
|
||||
MSVC_API_SHARED := -DSHARED
|
||||
MSVC_API_STATIC := -DSTATIC
|
||||
|
||||
|
||||
ifndef MSVC_NO_ISO_WIDE_SPECIFIERS
|
||||
OPTS += /D_CRT_STDIO_ISO_WIDE_SPECIFIERS
|
||||
endif
|
||||
|
||||
# Final versions of the toolchain flags.
|
||||
CFLAGS = $(OPTS) $(DFLAGS) $(COPTIM) $(AOPTIM) \
|
||||
$(AFLAGS) $(INCS) $(DEFS)
|
||||
LFLAGS := $(LOPTS) $(DFLAGS) $(LDIR)
|
||||
ARFLAGS := $(AOPTS)
|
||||
RCFLAGS = $(RCOPTS)
|
||||
|
||||
|
||||
# Build module rules.
|
||||
.SUFFIXES: .c .cpp .obj .rc .res
|
||||
|
||||
ifeq ($(AUTODEP), y)
|
||||
%.obj: %.c
|
||||
@$(CC) $(CFLAGS) -Fo$@ $(MSVC_API_SHARED) -c $<
|
||||
|
||||
%.dbj: %.c
|
||||
@$(CC) $(CFLAGS) -Fo$@ $(MSVC_API_STATIC) -c $<
|
||||
|
||||
%.obj: %.cpp
|
||||
@$(CXX) $(CXXFLAGS) -Fo$@ $(MSVC_API_SHARED) -c $<
|
||||
|
||||
%.dbj: %.cpp
|
||||
@$(CXX) $(CXXFLAGS) -Fo$@ $(MSVC_API_STATIC) -c $<
|
||||
else
|
||||
%.obj: %.c
|
||||
@$(CC) $(CFLAGS) -Fo$@ $(MSVC_API_SHARED) -c $<
|
||||
|
||||
%.dbj: %.c
|
||||
@$(CC) $(CFLAGS) -Fo$@ $(MSVC_API_STATIC) -c $<
|
||||
|
||||
%.obj: %.cpp
|
||||
@$(CXX) $(CXXFLAGS) -Fo$@ $(MSVC_API_SHARED) -c $<
|
||||
|
||||
%.dbj: %.cpp
|
||||
@$(CXX) $(CXXFLAGS) -Fo$@ $(MSVC_API_STATIC) -c $<
|
||||
|
||||
%.d: %.c $(wildcard $*.d)
|
||||
@$(CXX) $(CXXFLAGS) -Fo$@ $(MSVC_API_SHARED) -c $<
|
||||
endif
|
||||
|
||||
# For systems that use these, compile a resource file.
|
||||
.rc.res: $<
|
||||
@echo Processing $<
|
||||
@$(WINDRES) $(RCFLAGS) $@ $<
|
||||
|
||||
|
||||
#########################################################################
|
||||
# Nothing should need changing from here on.. #
|
||||
#########################################################################
|
||||
|
||||
# Final fixups.
|
||||
INCS += -Iwin
|
||||
|
||||
VPATH := win . targets
|
||||
|
||||
#LIBS :=
|
||||
#LOBJ :=
|
||||
|
||||
PROG := vasm.exe
|
||||
SYSOBJ := vasm.res getopt.obj
|
||||
OBJ := $(SYSOBJ) \
|
||||
main.obj symbol.obj expr.obj func.obj input.obj output.obj \
|
||||
list.obj parse.obj pseudo.obj \
|
||||
target.obj \
|
||||
mos6502.obj
|
||||
LDLIBS += #advapi32.lib shell32.lib user32.lib kernel32.lib winmm.lib
|
||||
|
||||
|
||||
all: $(LIBS) $(PROG)
|
||||
|
||||
|
||||
libfoo.lib libfoo.dll: $(LOBJ)
|
||||
@echo Linking shared library $@ ..
|
||||
@$(LINK) $(LFLAGS) $(LOPTS_W) /DLL /OUT:$@ \
|
||||
/IMPLIB:$@.lib $(LOBJ) $(LDLIBS)
|
||||
|
||||
libfoo_s.lib: $(LOBJ)
|
||||
@echo Creating static library $@ ..
|
||||
@$(AR) $(ARFLAGS) /OUT:$@ $(LOBJ)
|
||||
|
||||
|
||||
vasm.exe: $(SYSOBJ) $(OBJ)
|
||||
@echo Linking $@ ..
|
||||
@$(LINK) $(LFLAGS) /SUBSYSTEM:CONSOLE$(LOPTS_OS) \
|
||||
-OUT:$@ $(OBJ) $(LIBS) $(LDLIBS)
|
||||
|
||||
clean:
|
||||
@echo Cleaning objects..
|
||||
@-del *.obj 2>NUL
|
||||
@-del *.d 2>NUL
|
||||
@echo Cleaning resources..
|
||||
@-del *.res 2>NUL
|
||||
|
||||
|
||||
clobber: clean
|
||||
@echo Removing executables..
|
||||
@-del *.exe 2>NUL
|
||||
@echo Cleaning libraries..
|
||||
# @-del *.dll 2>NUL
|
||||
@-del *.lib 2>NUL
|
||||
@-del *.manifest 2>NUL
|
||||
# @-del $(DEPFILE) 2>NUL
|
||||
|
||||
depclean:
|
||||
@-del $(DEPFILE)
|
||||
@echo Creating dependencies..
|
||||
@echo # Run "make depends" to re-create this file. >$(DEPFILE)
|
||||
|
||||
depends: DEPOBJ=$(OBJ:%.obj=%.d)
|
||||
depends: depclean $(DEPOBJ)
|
||||
@$(CAT) $(DEPOBJ) >>$(DEPFILE)
|
||||
@-del $(DEPOBJ)
|
||||
|
||||
$(DEPFILE):
|
||||
|
||||
|
||||
# Module dependencies.
|
||||
ifeq ($(AUTODEP), y)
|
||||
-include *.d
|
||||
else
|
||||
ifneq ($(wildcard $(DEPFILE)), )
|
||||
include $(wildcard $(DEPFILE))
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
# End of Makefile.MSVC.
|
||||
288
src/win/Makefile.MinGW
Normal file
288
src/win/Makefile.MinGW
Normal file
@@ -0,0 +1,288 @@
|
||||
#
|
||||
# VASM VARCem Multi-Target Assembler.
|
||||
# A simple table-driven assembler for several 8-bit target
|
||||
# devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
# code originated from Bernd B”ckmann's "asm6502" project.
|
||||
#
|
||||
# This file is part of the VARCem Project.
|
||||
#
|
||||
# Makefile for Windows systems using the MinGW-w64 environment.
|
||||
#
|
||||
# Version: @(#)Makefile.MinGW 1.1.0 2023/04/24
|
||||
#
|
||||
# Author: Fred N. van Kempen, <waltje@varcem.com>
|
||||
#
|
||||
# Copyright 2023 Fred N. van Kempen.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with
|
||||
# or without modification, are permitted provided that the
|
||||
# following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the entire
|
||||
# above notice, this list of conditions and the following
|
||||
# disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the
|
||||
# following disclaimer in the documentation and/or other
|
||||
# materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names
|
||||
# of its contributors may be used to endorse or promote
|
||||
# products derived from this software without specific
|
||||
# prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
ifndef ARCH
|
||||
ARCH := x86
|
||||
endif
|
||||
|
||||
ifndef DEBUG
|
||||
DEBUG := n
|
||||
endif
|
||||
|
||||
|
||||
# Where is the VARCem tree?
|
||||
VARCEM := ../../../..
|
||||
|
||||
# Where is our Ihex support library?
|
||||
IHEX := $(VARCEM)/contrib/Ihex
|
||||
INCS += -I$(IHEX)/include -DUSE_HEX=2
|
||||
LDIR += -L$(IHEX)/lib/$(ARCH)
|
||||
|
||||
|
||||
DEFS := -DALLOW_UNDEFINED_IF
|
||||
|
||||
|
||||
#########################################################################
|
||||
# Nothing should need changing from here on.. #
|
||||
#########################################################################
|
||||
|
||||
# Definitions for this enivonment.
|
||||
DEVENV := mingw
|
||||
DEPS = -MMD -MF $*.d
|
||||
DEPFILE := .depends-$(DEVENV)
|
||||
|
||||
|
||||
# Compilation for X86.
|
||||
ifeq ($(ARCH), x86)
|
||||
TARGET := 32
|
||||
PREFIX :=
|
||||
RCTARGET := pe-i386
|
||||
|
||||
AFLAGS := -msse2 -mfpmath=sse
|
||||
ifeq ($(OPTIM), y)
|
||||
DFLAGS := -march=native
|
||||
else
|
||||
DFLAGS := -march=i686
|
||||
endif
|
||||
endif
|
||||
|
||||
# Compilation for X64.
|
||||
ifeq ($(ARCH), x64)
|
||||
TARGET := 64
|
||||
PREFIX :=
|
||||
RCTARGET := pe-x86-64
|
||||
|
||||
ifeq ($(OPTIM), y)
|
||||
DFLAGS := -march=native
|
||||
endif
|
||||
endif
|
||||
|
||||
# Compilation for ARM.
|
||||
ifeq ($(ARCH), armv7)
|
||||
error Target ARM7 not supported for Windows !
|
||||
endif
|
||||
|
||||
# Compilation for ARM64.
|
||||
ifeq ($(ARCH), aarch64)
|
||||
error Target ARM64 not supported for Windows !
|
||||
endif
|
||||
|
||||
|
||||
# The various toolchain programs.
|
||||
CC := gcc -m$(TARGET)
|
||||
CXX := g++ -m$(TARGET)
|
||||
CPP := cpp -P
|
||||
LINK := gcc -m$(TARGET)
|
||||
WINDRES := windres
|
||||
AR := ar
|
||||
RANLIB := ranlib
|
||||
STRIP := strip
|
||||
ifndef CAT
|
||||
CAT := cat
|
||||
endif
|
||||
|
||||
# Set up the correct toolchain flags.
|
||||
OPTS := -DARCH=$(ARCH) \
|
||||
-D_CRT_NON_CONFORMING_SWPRINTFS \
|
||||
-D__USE_MINGW_ANSI_STDIO_X
|
||||
ifndef VCRUNTIME
|
||||
# MinGW does not provide MD/MT yet.
|
||||
VCRUNTIME := MD
|
||||
endif
|
||||
RCOPTS := --input-format=rc -O coff
|
||||
ifdef RCTARGET
|
||||
RCOPTS += --target=$(RCTARGET)
|
||||
endif
|
||||
RCOPTS += -D RC_INVOKED -o
|
||||
AOPTS := r
|
||||
LOPTS := -mconsole
|
||||
|
||||
# General build options.
|
||||
ifeq ($(DEBUG), y)
|
||||
VCRUNTIME := $(VCRUNTIME)d
|
||||
DFLAGS += -ggdb -D_DEBUG
|
||||
RCOPTS := -D_DEBUG $(RCOPTS)
|
||||
AOPTIM :=
|
||||
ifndef COPTIM
|
||||
COPTIM := -Og
|
||||
endif
|
||||
else
|
||||
ifeq ($(OPTIM), y)
|
||||
AOPTIM := -mtune=native
|
||||
ifndef COPTIM
|
||||
COPTIM := -O3
|
||||
endif
|
||||
else
|
||||
ifndef COPTIM
|
||||
COPTIM := -O3
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
OPTS += #/$(VCRUNTIME)
|
||||
ifeq ($(PROFILER), y)
|
||||
LOPTS += -Xlinker -Map=$(PROG).map
|
||||
endif
|
||||
|
||||
|
||||
# Final versions of the toolchain flags.
|
||||
CFLAGS = $(OPTS) $(DFLAGS) $(COPTIM) $(AOPTIM) \
|
||||
$(AFLAGS) $(INCS) $(DEFS) \
|
||||
-mstackrealign \
|
||||
-fomit-frame-pointer -fno-strict-aliasing \
|
||||
-Wall -Wundef #-Wmissing-declarations
|
||||
LDFLAGS := $(LOPTS) $(DFLAGS) $(LDIR)
|
||||
ARFLAGS := $(AOPTS)
|
||||
RCFLAGS = $(RCOPTS)
|
||||
|
||||
|
||||
# Build module rules.
|
||||
.SUFFIXES: .c .cpp .o .rc .res
|
||||
|
||||
ifeq ($(AUTODEP), y)
|
||||
%.o: %.c
|
||||
@echo Compiling $<
|
||||
@$(CC) $(CFLAGS) $(DEPS) -c $<
|
||||
else
|
||||
%.o: %.c
|
||||
@echo Compiling $<
|
||||
@$(CC) $(CFLAGS) -c $<
|
||||
|
||||
%.d: %.c $(wildcard $*.d)
|
||||
@echo Compiling $<
|
||||
@$(CC) $(CFLAGS) $(DEPS) -E $< >NUL
|
||||
endif
|
||||
|
||||
# For systems that use these, compile a resource file.
|
||||
.rc.res: $<
|
||||
@echo Processing $<
|
||||
@$(WINDRES) $(RCFLAGS) $@ $<
|
||||
|
||||
|
||||
#########################################################################
|
||||
# Nothing should need changing from here on.. #
|
||||
#########################################################################
|
||||
|
||||
# Final fixups.
|
||||
INCS += -Iwin
|
||||
|
||||
VPATH := win . targets
|
||||
|
||||
#LIBS :=
|
||||
#LOBJ :=
|
||||
|
||||
PROG := vasm.exe
|
||||
SYSOBJ := vasm.res getopt.o
|
||||
OBJ := $(SYSOBJ) \
|
||||
main.o symbol.o expr.o func.o input.o output.o \
|
||||
list.o parse.o pseudo.o \
|
||||
target.o \
|
||||
mos6502.o
|
||||
|
||||
|
||||
all: $(LIBS) $(PROG)
|
||||
|
||||
|
||||
libfoo.dll.a libfoo.dll: $(LOBJ)
|
||||
@echo Linking shared library $@ ..
|
||||
@$(LINK) $(LDFLAGS) -shared -o $@ \
|
||||
-Wl,--subsystem=console \
|
||||
-Wl,--out-implib,$@.a $(LOBJ)
|
||||
$(if $(filter $(DEBUG),y),,@$(STRIP) --strip-unneeded $@)
|
||||
|
||||
libfoo.a: $(LOBJ)
|
||||
@echo Creating static library $@ ..
|
||||
@$(AR) $(ARFLAGS) $@ $(LOBJ)
|
||||
@$(RANLIB) $@
|
||||
|
||||
|
||||
vasm.exe: $(SYSOBJ) $(OBJ)
|
||||
@echo Linking $@ ..
|
||||
@$(LINK) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) $(LDLIBS)
|
||||
$(if $(filter $(DEBUG),y),,@$(STRIP) $@)
|
||||
|
||||
|
||||
clean:
|
||||
@echo Cleaning objects..
|
||||
@-del *.o 2>NUL
|
||||
@-del *.d 2>NUL
|
||||
@echo Cleaning resources..
|
||||
@-del *.res 2>NUL
|
||||
|
||||
|
||||
clobber: clean
|
||||
@echo Removing executables..
|
||||
@-del *.exe 2>NUL
|
||||
@echo Cleaning libraries..
|
||||
@-del *.dll 2>NUL
|
||||
@-del *.a 2>NUL
|
||||
@-del *.manifest 2>NUL
|
||||
# @-del $(DEPFILE) 2>NUL
|
||||
|
||||
depclean:
|
||||
@-del $(DEPFILE)
|
||||
@echo Creating dependencies..
|
||||
@echo # Run "make depends" to re-create this file. >$(DEPFILE)
|
||||
|
||||
depends: DEPOBJ=$(OBJ:%.o=%.d)
|
||||
depends: depclean $(DEPOBJ)
|
||||
@$(CAT) $(DEPOBJ) >>$(DEPFILE)
|
||||
@-del $(DEPOBJ)
|
||||
|
||||
$(DEPFILE):
|
||||
|
||||
|
||||
# Module dependencies.
|
||||
ifeq ($(AUTODEP), y)
|
||||
-include *.d
|
||||
else
|
||||
ifneq ($(wildcard $(DEPFILE)), )
|
||||
include $(wildcard $(DEPFILE))
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
# End of Makefile.MinGW.
|
||||
110
src/win/getopt.c
Normal file
110
src/win/getopt.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* VARCem Virtual ARchaeological Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Portable GETOPT(3) function.
|
||||
*
|
||||
* This is a simple version of the UNIX-standard GetOpt(3)
|
||||
* library routine. We don't support any of the GNU LibC
|
||||
* enhancements such as long-name options, double-dash
|
||||
* options and such. We keep it simple and small here.
|
||||
*
|
||||
* Version: @(#)getopt.c 1.0.1 2002/08/13
|
||||
*
|
||||
* Author: Fred N. van Kempen, <waltje@varcem.com>
|
||||
*
|
||||
* Copyright 1998-2018 MicroWalt Corporation
|
||||
* Copyright 2018-2023 The VARCem Team
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "getopt.h"
|
||||
|
||||
|
||||
char *optarg;
|
||||
int optind = 0;
|
||||
int opterr = 1;
|
||||
int optopt;
|
||||
|
||||
|
||||
static char *scan = (char *)NULL;
|
||||
|
||||
|
||||
int
|
||||
getopt(int argc, char **argv, const char *optstring)
|
||||
{
|
||||
char c;
|
||||
char *place;
|
||||
|
||||
optarg = (char *)NULL;
|
||||
|
||||
if (scan == (char *)NULL || *scan == '\0') {
|
||||
if (optind == 0) optind++;
|
||||
|
||||
if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
|
||||
return(EOF);
|
||||
if (strcmp(argv[optind], "--") == 0) {
|
||||
optind++;
|
||||
return(EOF);
|
||||
}
|
||||
scan = argv[optind] + 1;
|
||||
optind++;
|
||||
}
|
||||
optopt = c = *scan++;
|
||||
place = strchr(optstring, c);
|
||||
|
||||
if (place == (char *)NULL || c == ':') {
|
||||
if (opterr) fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
|
||||
return('?');
|
||||
}
|
||||
place++;
|
||||
if (*place == ':') {
|
||||
if (*scan != '\0') {
|
||||
optarg = scan;
|
||||
scan = (char *)NULL;
|
||||
} else if (optind < argc) {
|
||||
optarg = argv[optind];
|
||||
optind++;
|
||||
} else {
|
||||
if (opterr)
|
||||
fprintf(stderr,
|
||||
"%s: -%c argument missing\n", argv[0], c);
|
||||
return('?');
|
||||
}
|
||||
}
|
||||
return(c);
|
||||
}
|
||||
68
src/win/getopt.h
Normal file
68
src/win/getopt.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* VARCem Virtual ARchaeological Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Portable GETOPT(3) function.
|
||||
*
|
||||
* Version: @(#)getopt.h 1.0.1 2002/08/13
|
||||
*
|
||||
* Author: Fred N. van Kempen, <waltje@varcem.com>
|
||||
*
|
||||
* Copyright 1998-2018 MicroWalt Corporation
|
||||
* Copyright 2018-2023 The VARCem Team
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef GETOPT_H
|
||||
# define GETOPT_H
|
||||
|
||||
|
||||
extern int optind,
|
||||
opterr;
|
||||
extern char *optarg;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int getopt(int ac, char *av[], const char *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /*GETOPT_H*/
|
||||
BIN
src/win/varcem.ico
Normal file
BIN
src/win/varcem.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
98
src/win/vasm.rc
Normal file
98
src/win/vasm.rc
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* VASM VARCem Multi-Target Assembler.
|
||||
* A simple table-driven assembler for several 8-bit target
|
||||
* devices, like the 6502, 6800, 80x, Z80 et al series. The
|
||||
* code originated from Bernd B”ckmann's "asm6502" project.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Application resource script for Windows.
|
||||
*
|
||||
* Version: @(#)vasm.rc 1.0.2 2023/04/24
|
||||
*
|
||||
* Author: Fred N. van Kempen, <waltje@varcem.com>
|
||||
*
|
||||
* Copyright 2023 Fred N. van Kempen.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <windows.h>
|
||||
#include "../version.h"
|
||||
|
||||
|
||||
100 ICON "win/varcem.ico"
|
||||
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
#ifdef APP_VER_PATCH
|
||||
FILEVERSION APP_VER_MAJOR,APP_VER_MINOR,APP_VER_REV,APP_VER_PATCH
|
||||
PRODUCTVERSION APP_VER_MAJOR,APP_VER_MINOR,APP_VER_REV,APP_VER_PATCH
|
||||
#else
|
||||
FILEVERSION APP_VER_MAJOR,APP_VER_MINOR,APP_VER_REV,0
|
||||
PRODUCTVERSION APP_VER_MAJOR,APP_VER_MINOR,APP_VER_REV,0
|
||||
#endif
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifndef RELEASE_BUILD
|
||||
# ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_SPECIALBUILD | VS_FF_DEBUG
|
||||
# else
|
||||
FILEFLAGS VS_FF_SPECIALBUILD
|
||||
# endif
|
||||
#else
|
||||
# ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
# else
|
||||
FILEFLAGS 0x0L
|
||||
# endif
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "0409fde9"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "The VARCem Group LLC"
|
||||
VALUE "LegalCopyright", "See LICENSE for legal information."
|
||||
VALUE "ProductName", "VARCem Support Tools"
|
||||
VALUE "ProductVersion", APP_VERSION
|
||||
VALUE "InternalName", APP_NAME
|
||||
VALUE "FileDescription", APP_NAME
|
||||
VALUE "FileVersion", APP_VERSION
|
||||
VALUE "OriginalFilename", "vasm.exe"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x0409, 65001
|
||||
END
|
||||
END
|
||||
@@ -1,4 +1,12 @@
|
||||
; C64 Hello World
|
||||
|
||||
.ifdef C64
|
||||
.include "tests/c64_prg.asm"
|
||||
.else
|
||||
.cpu 6502
|
||||
.org $0400
|
||||
.endif
|
||||
|
||||
; assemble to .PRG file: vasm -o hello.prg c64.asm c64_hello.asm
|
||||
|
||||
CHROUT = $FFD2 ; kernal function address
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
VARCem VASM version 1.0.10 (Windows, x86) 04/11/23 00:34:32 Page 1
|
||||
File: h1.asm
|
||||
|
||||
1: ; Preamble to create a C64 .PRG file.
|
||||
2:
|
||||
3: SYS = $9E ; basic SYS token number
|
||||
4:
|
||||
5: LOAD = $0801 ; load address
|
||||
6:
|
||||
0000 0000 01 08 7: .word LOAD ; .PRG header: load address
|
||||
8: .org LOAD
|
||||
9:
|
||||
10: basic: ; BASIC code: 10 SYS 2062
|
||||
0002 0801 0C 08 0A 11: .word @end, 10 ; ptr to next basic line and line number 10
|
||||
0006 0805 9E 20 32 ... 12: .byte SYS, " 2062", 0 ; SYS token and address string of subroutine
|
||||
000D 080C 00 00 13: @end .word 0 ; null ptr to indicate end of basic text
|
||||
14:
|
||||
15: ; End of preamble code.
|
||||
1: ; C64 Hello World
|
||||
2: ; assemble to .PRG file: vasm -o hello.prg c64.asm c64_hello.asm
|
||||
3:
|
||||
4: CHROUT = $FFD2 ; kernal function address
|
||||
5: CR = 13 ; carrige return character
|
||||
6: LF = %1010 ; line feed character
|
||||
7:
|
||||
8: main: ; this is at address 2062 ($080E)
|
||||
000F 080E A2 00 9: ldx #0
|
||||
0011 0810 BD 1C 08 10: @l lda msg, x
|
||||
0014 0813 20 D2 FF 11: jsr CHROUT
|
||||
0017 0816 E8 12: inx
|
||||
0018 0817 E0 0F 13: cpx #len
|
||||
001A 0819 D0 F5 14: bne @l
|
||||
001C 081B 60 15: rts
|
||||
16:
|
||||
001D 081C 48 45 4C ... 17: msg .byte "HELLO, WORLD!", CR, LF
|
||||
18: len = @ - msg
|
||||
19:
|
||||
20: ; End of file.
|
||||
VARCem VASM version 1.0.10 (Windows, x86) 04/11/23 00:34:32 Page 2
|
||||
** SYMBOL TABLE ** File: h2.asm
|
||||
|
||||
basic L 0801 W h1.asm:10
|
||||
@end 080C h1.asm:10
|
||||
CHROUT V FFD2 W h2.asm:4
|
||||
CR V 000D B h2.asm:5
|
||||
len V 000F W h2.asm:18
|
||||
LF V 000A B h2.asm:6
|
||||
LOAD V 0801 W h1.asm:5
|
||||
main L 080E W h2.asm:8
|
||||
@l 0810 h2.asm:8
|
||||
msg L 081C W h2.asm:17
|
||||
SYS V 009E B h1.asm:3
|
||||
Binary file not shown.
@@ -4,8 +4,11 @@ SYS = $9E ; basic SYS token number
|
||||
|
||||
LOAD = $0801 ; load address
|
||||
|
||||
.cpu 6510 ; set processor for C64
|
||||
|
||||
.word LOAD ; .PRG header: load address
|
||||
.org LOAD
|
||||
|
||||
.org LOAD ; we start at this address
|
||||
|
||||
basic: ; BASIC code: 10 SYS 2062
|
||||
.word @end, 10 ; ptr to next basic line and line number 10
|
||||
760
tests/kow-test-65c02.asm
Normal file
760
tests/kow-test-65c02.asm
Normal file
@@ -0,0 +1,760 @@
|
||||
;
|
||||
; Michal Kowalski
|
||||
;
|
||||
; All documented 650X, 651X, 65F11, 65F12, 65C00/21, 65C29,
|
||||
; 65C02, 65C102, and 65C112 instructions with proper AS6500 syntax.
|
||||
;
|
||||
.title 6500 Assembler Test
|
||||
; .cpu r65f11
|
||||
; .cpu r65c02
|
||||
; .cpu r65c00
|
||||
|
||||
extext = $0000 ; zero, but force it to a word
|
||||
extdir = 0
|
||||
|
||||
dir = $33
|
||||
ext = $1122
|
||||
offset = $44
|
||||
|
||||
.org $1000
|
||||
|
||||
adc #$12 ; 69 12
|
||||
;---
|
||||
adc $1234 ; 6D 34 12
|
||||
adc ext ; 6D 22 11
|
||||
adc extext ; 6Du00v00
|
||||
;---
|
||||
adc $12 ; 65 12
|
||||
adc dir ; 65 33
|
||||
adc extext ; 65 00
|
||||
;---
|
||||
adc $12,x ; 75 12
|
||||
adc dir,x ; 75 33
|
||||
adc offset,x ; 75 44
|
||||
adc extdir,x ; 75 00
|
||||
;---
|
||||
adc $1234,x ; 7D 34 12
|
||||
adc ext,x ; 7D 22 11
|
||||
adc extext,x ; 7Du00v00
|
||||
;---
|
||||
adc $1234,y ; 79 34 12
|
||||
adc dir,y ; 79 33 00
|
||||
adc extdir,y ; 79u00v00
|
||||
adc ext,y ; 79 22 11
|
||||
adc extext,y ; 79u00v00
|
||||
;---
|
||||
adc ($12,x) ; 61 12
|
||||
adc (dir,x) ; 61 33
|
||||
adc (offset,x) ; 61 44
|
||||
adc (extdir,x) ; 61 00
|
||||
adc (extext,x) ; 61 00
|
||||
;---
|
||||
adc ($12),y ; 71 12
|
||||
adc (dir),y ; 71 33
|
||||
adc (offset),y ; 71 44
|
||||
adc (extdir),y ; 71 00
|
||||
adc (extext),y ; 71 00
|
||||
;---
|
||||
.ifdef P65C02
|
||||
adc ($12) ; 72 12
|
||||
adc (dir) ; 72 33
|
||||
adc (offset) ; 72 44
|
||||
adc (extdir) ; 72 00
|
||||
adc (extext) ; 72 00
|
||||
.endif
|
||||
and #$12 ; 29 12
|
||||
;---
|
||||
and $1234 ; 2D 34 12
|
||||
and ext ; 2D 22 11
|
||||
and extext ; 2Du00v00
|
||||
;---
|
||||
and $12 ; 25 12
|
||||
and dir ; 25 33
|
||||
and extext ; 25 00
|
||||
;---
|
||||
and $12,x ; 35 12
|
||||
and dir,x ; 35 33
|
||||
and offset,x ; 35 44
|
||||
and extdir,x ; 35 00
|
||||
;---
|
||||
and $1234,x ; 3D 34 12
|
||||
and ext,x ; 3D 22 11
|
||||
and extext,x ; 3Du00v00
|
||||
;---
|
||||
and $1234,y ; 39 34 12
|
||||
and dir,y ; 39 33 00
|
||||
and extdir,y ; 39u00v00
|
||||
and ext,y ; 39 22 11
|
||||
and extext,y ; 39u00v00
|
||||
;---
|
||||
and ($12,x) ; 21 12
|
||||
and (dir,x) ; 21 33
|
||||
and (offset,x) ; 21 44
|
||||
and (extdir,x) ; 21 00
|
||||
and (extext,x) ; 21 00
|
||||
;---
|
||||
and ($12),y ; 31 12
|
||||
and (dir),y ; 31 33
|
||||
and (offset),y ; 31 44
|
||||
and (extdir),y ; 31 00
|
||||
and (extext),y ; 31 00
|
||||
;---
|
||||
.ifdef P65C02
|
||||
and ($12) ; 32 12
|
||||
and (dir) ; 32 33
|
||||
and (offset) ; 32 44
|
||||
and (extdir) ; 32 00
|
||||
and (extext) ; 32 00
|
||||
.endif
|
||||
asl a ; 0A
|
||||
asl ; 0A
|
||||
;---
|
||||
asl $1234 ; 0E 34 12
|
||||
asl ext ; 0E 22 11
|
||||
asl extext ; 0Eu00v00
|
||||
;---
|
||||
asl $12 ; 06 12
|
||||
asl dir ; 06 33
|
||||
asl extext ; 06 00
|
||||
;---
|
||||
asl $12,x ; 16 12
|
||||
asl dir,x ; 16 33
|
||||
asl offset,x ; 16 44
|
||||
asl extdir,x ; 16 00
|
||||
;---
|
||||
asl $1234,x ; 1E 34 12
|
||||
asl ext,x ; 1E 22 11
|
||||
asl extext,x ; 1Eu00v00
|
||||
;.if r65f11+r65c00+r65c02
|
||||
.ifdef P65C02
|
||||
bbr 0,$12,* ; 0F 12 FD
|
||||
bbr 1,$12,* ; 1F 12 FD
|
||||
bbr 2,$12,* ; 2F 12 FD
|
||||
bbr 3,$12,* ; 3F 12 FD
|
||||
bbr 4,$12,* ; 4F 12 FD
|
||||
bbr 5,$12,* ; 5F 12 FD
|
||||
bbr 6,$12,* ; 6F 12 FD
|
||||
bbr 7,$12,* ; 7F 12 FD
|
||||
bbs 0,$12,* ; 8F 12 FD
|
||||
bbs 1,$12,* ; 9F 12 FD
|
||||
bbs 2,$12,* ; AF 12 FD
|
||||
bbs 3,$12,* ; BF 12 FD
|
||||
bbs 4,$12,* ; CF 12 FD
|
||||
bbs 5,$12,* ; DF 12 FD
|
||||
bbs 6,$12,* ; EF 12 FD
|
||||
bbs 7,$12,* ; FF 12 FD
|
||||
@1: bbr #0,$12,@3 ; 0F 12 03
|
||||
@2: bbr #0,dir,@2 ; 0F 33 FD
|
||||
@3: bbr #0,extext,@1 ; 0F 00 F7
|
||||
@4: bbs #0,$12,@6 ; 8F 12 03
|
||||
@5: bbs #0,dir,@5 ; 8F 33 FD
|
||||
@6: bbs #0,extext,@4 ; 8F 00 F7
|
||||
.endif
|
||||
bcc @ ; 90 FE
|
||||
bcs @ ; B0 FE
|
||||
beq @ ; F0 FE
|
||||
;---
|
||||
.ifdef P65C02
|
||||
bit #$12 ; 89 12
|
||||
.endif
|
||||
bit $1234 ; 2C 34 12
|
||||
bit ext ; 2C 22 11
|
||||
bit extext ; 2Cu00v00
|
||||
;---
|
||||
bit $12 ; 24 12
|
||||
bit dir ; 24 33
|
||||
bit extext ; 24 00
|
||||
;---
|
||||
.ifdef P65C02
|
||||
bit $12,x ; 34 12
|
||||
bit dir,x ; 34 33
|
||||
bit offset,x ; 34 44
|
||||
bit extdir,x ; 34 00
|
||||
;---
|
||||
bit $1234,x ; 3C 34 12
|
||||
bit ext,x ; 3C 22 11
|
||||
bit extext,x ; 3Cu00v00
|
||||
.endif
|
||||
bmi @ ; 30 FE
|
||||
bne @ ; D0 FE
|
||||
bpl @ ; 10 FE
|
||||
;.if r65c00+r65c02
|
||||
.ifdef P65C02
|
||||
bra @ ; 80 FE
|
||||
.endif
|
||||
brk ; 00
|
||||
bvc @ ; 50 FE
|
||||
bvs @ ; 70 FE
|
||||
clc ; 18
|
||||
cld ; D8
|
||||
cli ; 58
|
||||
clv ; B8
|
||||
cmp #$12 ; C9 12
|
||||
;---
|
||||
cmp $1234 ; CD 34 12
|
||||
cmp ext ; CD 22 11
|
||||
cmp extext ; CDu00v00
|
||||
;---
|
||||
cmp $12 ; C5 12
|
||||
cmp dir ; C5 33
|
||||
cmp extext ; C5 00
|
||||
;---
|
||||
cmp $12,x ; D5 12
|
||||
cmp dir,x ; D5 33
|
||||
cmp offset,x ; D5 44
|
||||
cmp extdir,x ; D5 00
|
||||
;---
|
||||
cmp $1234,x ; DD 34 12
|
||||
cmp ext,x ; DD 22 11
|
||||
cmp extext,x ; DDu00v00
|
||||
;---
|
||||
cmp $1234,y ; D9 34 12
|
||||
cmp dir,y ; D9 33 00
|
||||
cmp extdir,y ; D9u00v00
|
||||
cmp ext,y ; D9 22 11
|
||||
cmp extext,y ; D9u00v00
|
||||
;---
|
||||
cmp ($12,x) ; C1 12
|
||||
cmp (dir,x) ; C1 33
|
||||
cmp (offset,x) ; C1 44
|
||||
cmp (extdir,x) ; C1 00
|
||||
cmp (extext,x) ; C1 00
|
||||
;---
|
||||
cmp ($12),y ; D1 12
|
||||
cmp (dir),y ; D1 33
|
||||
cmp (offset),y ; D1 44
|
||||
cmp (extdir),y ; D1 00
|
||||
cmp (extext),y ; D1 00
|
||||
;---
|
||||
.ifdef P65C02
|
||||
cmp ($12) ; D2 12
|
||||
cmp (dir) ; D2 33
|
||||
cmp (offset) ; D2 44
|
||||
cmp (extdir) ; D2 00
|
||||
cmp (extext) ; D2 00
|
||||
.endif
|
||||
;---
|
||||
.ifdef P65C02
|
||||
cpx #$12 ; E0 12
|
||||
.endif
|
||||
cpx $12 ; E4 12
|
||||
cpx dir ; E4 33
|
||||
cpx extdir ; E4 00
|
||||
;---
|
||||
cpx $1234 ; EC 34 12
|
||||
cpx ext ; EC 22 11
|
||||
cpx extext ; ECu00v00
|
||||
.ifdef P65C02
|
||||
cpy #$12 ; C0 12
|
||||
.endif
|
||||
;---
|
||||
cpy $12 ; C4 12
|
||||
cpy dir ; C4 33
|
||||
cpy extdir ; C4 00
|
||||
;---
|
||||
cpy $1234 ; CC 34 12
|
||||
cpy ext ; CC 22 11
|
||||
cpy extext ; CCu00v00
|
||||
.ifdef P65C02
|
||||
; dec a ; 3A
|
||||
dea ; 3A
|
||||
.endif
|
||||
;---
|
||||
dec $1234 ; CE 34 12
|
||||
dec ext ; CE 22 11
|
||||
dec extext ; CEu00v00
|
||||
;---
|
||||
dec $12 ; C6 12
|
||||
dec dir ; C6 33
|
||||
dec extext ; C6 00
|
||||
;---
|
||||
dec $12,x ; D6 12
|
||||
dec dir,x ; D6 33
|
||||
dec offset,x ; D6 44
|
||||
dec extdir,x ; D6 00
|
||||
;---
|
||||
dec $1234,x ; DE 34 12
|
||||
dec ext,x ; DE 22 11
|
||||
dec extext,x ; DEu00v00
|
||||
dex ; CA
|
||||
dey ; 88
|
||||
eor #$12 ; 49 12
|
||||
;---
|
||||
eor $1234 ; 4D 34 12
|
||||
eor ext ; 4D 22 11
|
||||
eor extext ; 4Du00v00
|
||||
;---
|
||||
eor $12 ; 45 12
|
||||
eor dir ; 45 33
|
||||
eor extext ; 45 00
|
||||
;---
|
||||
eor $12,x ; 55 12
|
||||
eor dir,x ; 55 33
|
||||
eor offset,x ; 55 44
|
||||
eor extdir,x ; 55 00
|
||||
;---
|
||||
eor $1234,x ; 5D 34 12
|
||||
eor ext,x ; 5D 22 11
|
||||
eor extext,x ; 5Du00v00
|
||||
;---
|
||||
eor $1234,y ; 59 34 12
|
||||
eor dir,y ; 59 33 00
|
||||
eor extdir,y ; 59u00v00
|
||||
eor ext,y ; 59 22 11
|
||||
eor extext,y ; 59u00v00
|
||||
;---
|
||||
eor ($12,x) ; 41 12
|
||||
eor (dir,x) ; 41 33
|
||||
eor (offset,x) ; 41 44
|
||||
eor (extdir,x) ; 41 00
|
||||
eor (extext,x) ; 41 00
|
||||
;---
|
||||
eor ($12),y ; 51 12
|
||||
eor (dir),y ; 51 33
|
||||
eor (offset),y ; 51 44
|
||||
eor (extdir),y ; 51 00
|
||||
eor (extext),y ; 51 00
|
||||
;---
|
||||
.ifdef P65C02
|
||||
eor ($12) ; 52 12
|
||||
eor (dir) ; 52 33
|
||||
eor (offset) ; 52 44
|
||||
eor (extdir) ; 52 00
|
||||
eor (extext) ; 52 00
|
||||
.endif
|
||||
;---
|
||||
.ifdef P65C02
|
||||
inc a ; 1A
|
||||
ina ; 1A
|
||||
.endif
|
||||
;---
|
||||
inc $1234 ; EE 34 12
|
||||
inc ext ; EE 22 11
|
||||
inc extext ; EEu00v00
|
||||
;---
|
||||
inc $12 ; E6 12
|
||||
inc dir ; E6 33
|
||||
inc extext ; E6 00
|
||||
;---
|
||||
inc $12,x ; F6 12
|
||||
inc dir,x ; F6 33
|
||||
inc offset,x ; F6 44
|
||||
inc extdir,x ; F6 00
|
||||
;---
|
||||
inc $1234,x ; FE 34 12
|
||||
inc ext,x ; FE 22 11
|
||||
inc extext,x ; FEu00v00
|
||||
inx ; E8
|
||||
iny ; C8
|
||||
jmp $12 ; 4C 12 00
|
||||
jmp dir ; 4C 33 00
|
||||
jmp extext ; 4Cu00v00
|
||||
;---
|
||||
jmp $1234 ; 4C 34 12
|
||||
jmp ext ; 4C 22 11
|
||||
jmp extext ; 4Cu00v00
|
||||
;---
|
||||
jmp ($1234) ; 6C 34 12
|
||||
jmp (ext) ; 6C 22 11
|
||||
jmp (extext) ; 6Cu00v00
|
||||
;---
|
||||
.ifdef P65C02
|
||||
jmp ($1234,x) ; 7C 34 12
|
||||
jmp (ext,x) ; 7C 22 11
|
||||
; jmp (extext,x) ; 7Cu00v00
|
||||
.endif
|
||||
jsr dir ; 20 33 00
|
||||
jsr extdir ; 20u00v00
|
||||
;---
|
||||
jsr $1234 ; 20 34 12
|
||||
jsr ext ; 20 22 11
|
||||
jsr extext ; 20u00v00
|
||||
lda #$12 ; A9 12
|
||||
;---
|
||||
lda $1234 ; AD 34 12
|
||||
lda ext ; AD 22 11
|
||||
lda extext ; ADu00v00
|
||||
;---
|
||||
lda $12 ; A5 12
|
||||
lda dir ; A5 33
|
||||
lda extext ; A5 00
|
||||
;---
|
||||
lda $12,x ; B5 12
|
||||
lda dir,x ; B5 33
|
||||
lda offset,x ; B5 44
|
||||
lda extdir,x ; B5 00
|
||||
;---
|
||||
lda $1234,x ; BD 34 12
|
||||
lda ext,x ; BD 22 11
|
||||
lda extext,x ; BDu00v00
|
||||
;---
|
||||
lda $1234,y ; B9 34 12
|
||||
lda dir,y ; B9 33 00
|
||||
lda extdir,y ; B9u00v00
|
||||
lda ext,y ; B9 22 11
|
||||
lda extext,y ; B9u00v00
|
||||
;---
|
||||
lda ($12,x) ; A1 12
|
||||
lda (dir,x) ; A1 33
|
||||
lda (offset,x) ; A1 44
|
||||
lda (extdir,x) ; A1 00
|
||||
lda (extext,x) ; A1 00
|
||||
;---
|
||||
lda ($12),y ; B1 12
|
||||
lda (dir),y ; B1 33
|
||||
lda (offset),y ; B1 44
|
||||
lda (extdir),y ; B1 00
|
||||
lda (extext),y ; B1 00
|
||||
;---
|
||||
.ifdef P65C02
|
||||
lda ($12) ; B2 12
|
||||
lda (dir) ; B2 33
|
||||
lda (offset) ; B2 44
|
||||
lda (extdir) ; B2 00
|
||||
lda (extext) ; B2 00
|
||||
.endif
|
||||
ldx #$12 ; A2 12
|
||||
;---
|
||||
ldx $12 ; A6 12
|
||||
ldx dir ; A6 33
|
||||
ldx extdir ; A6 00
|
||||
;---
|
||||
ldx $12,y ; B6 12
|
||||
ldx dir,y ; B6 33
|
||||
ldx extdir,y ; B6 00
|
||||
;---
|
||||
ldx $1234 ; AE 34 12
|
||||
ldx ext ; AE 22 11
|
||||
ldx extext ; AEu00v00
|
||||
;---
|
||||
ldx $1234,y ; BE 34 12
|
||||
ldx ext,y ; BE 22 11
|
||||
ldx extext,y ; BEu00v00
|
||||
ldy #$12 ; A0 12
|
||||
;---
|
||||
ldy $12 ; A4 12
|
||||
ldy dir ; A4 33
|
||||
ldy extdir ; A4 00
|
||||
;---
|
||||
ldy $12,x ; B4 12
|
||||
ldy dir,x ; B4 33
|
||||
ldy extdir,x ; B4 00
|
||||
;---
|
||||
ldy $1234 ; AC 34 12
|
||||
ldy ext ; AC 22 11
|
||||
ldy extext ; ACu00v00
|
||||
;---
|
||||
ldy $1234,x ; BC 34 12
|
||||
ldy ext,x ; BC 22 11
|
||||
ldy extext,x ; BCu00v00
|
||||
lsr a ; 4A
|
||||
lsr ; 4A
|
||||
;---
|
||||
lsr $1234 ; 4E 34 12
|
||||
lsr ext ; 4E 22 11
|
||||
lsr extext ; 4Eu00v00
|
||||
;---
|
||||
lsr $12 ; 46 12
|
||||
lsr dir ; 46 33
|
||||
lsr extext ; 46 00
|
||||
;---
|
||||
lsr $12,x ; 56 12
|
||||
lsr dir,x ; 56 33
|
||||
lsr offset,x ; 56 44
|
||||
lsr extdir,x ; 56 00
|
||||
;---
|
||||
lsr $1234,x ; 5E 34 12
|
||||
lsr ext,x ; 5E 22 11
|
||||
lsr extext,x ; 5Eu00v00
|
||||
.ifdef PR65C00
|
||||
mul ; 02
|
||||
.endif
|
||||
nop ; EA
|
||||
ora #$12 ; 09 12
|
||||
;---
|
||||
ora $1234 ; 0D 34 12
|
||||
ora ext ; 0D 22 11
|
||||
ora extext ; 0Du00v00
|
||||
;---
|
||||
ora $12 ; 05 12
|
||||
ora dir ; 05 33
|
||||
ora extext ; 05 00
|
||||
;---
|
||||
ora $12,x ; 15 12
|
||||
ora dir,x ; 15 33
|
||||
ora offset,x ; 15 44
|
||||
ora extdir,x ; 15 00
|
||||
;---
|
||||
ora $1234,x ; 1D 34 12
|
||||
ora ext,x ; 1D 22 11
|
||||
ora extext,x ; 1Du00v00
|
||||
;---
|
||||
ora $1234,y ; 19 34 12
|
||||
ora dir,y ; 19 33 00
|
||||
ora extdir,y ; 19u00v00
|
||||
ora ext,y ; 19 22 11
|
||||
ora extext,y ; 19u00v00
|
||||
;---
|
||||
ora ($12,x) ; 01 12
|
||||
ora (dir,x) ; 01 33
|
||||
ora (offset,x) ; 01 44
|
||||
ora (extdir,x) ; 01 00
|
||||
ora (extext,x) ; 01 00
|
||||
;---
|
||||
ora ($12),y ; 11 12
|
||||
ora (dir),y ; 11 33
|
||||
ora (offset),y ; 11 44
|
||||
ora (extdir),y ; 11 00
|
||||
ora (extext),y ; 11 00
|
||||
;---
|
||||
.ifdef P65C02
|
||||
ora ($12) ; 12 12
|
||||
ora (dir) ; 12 33
|
||||
ora (offset) ; 12 44
|
||||
ora (extdir) ; 12 00
|
||||
ora (extext) ; 12 00
|
||||
.endif
|
||||
pha ; 48
|
||||
php ; 08
|
||||
;.if r65c00+r65c02
|
||||
.ifdef P65C02
|
||||
phx ; DA
|
||||
phy ; 5A
|
||||
.endif
|
||||
pla ; 68
|
||||
plp ; 28
|
||||
;.if r65c00+r65c02
|
||||
.ifdef P65C02
|
||||
plx ; FA
|
||||
ply ; 7A
|
||||
.endif
|
||||
;.if r65f11+r65c00+r65c02
|
||||
.ifdef P65C02
|
||||
rmb 0,$12 ; 07 12
|
||||
rmb 1,$12 ; 17 12
|
||||
rmb 2,$12 ; 27 12
|
||||
rmb 3,$12 ; 37 12
|
||||
rmb 4,$12 ; 47 12
|
||||
rmb 5,$12 ; 57 12
|
||||
rmb 6,$12 ; 67 12
|
||||
rmb 7,$12 ; 77 12
|
||||
rmb 0,dir ; 07 33
|
||||
rmb 0,extdir ; 07 00
|
||||
.endif
|
||||
.ifdef P65C02
|
||||
rol a ; 2A
|
||||
rol ; 2A
|
||||
.endif
|
||||
;---
|
||||
rol $1234 ; 2E 34 12
|
||||
rol ext ; 2E 22 11
|
||||
rol extext ; 2Eu00v00
|
||||
;---
|
||||
rol $12 ; 26 12
|
||||
rol dir ; 26 33
|
||||
rol extext ; 26 00
|
||||
;---
|
||||
rol $12,x ; 36 12
|
||||
rol dir,x ; 36 33
|
||||
rol offset,x ; 36 44
|
||||
rol extdir,x ; 36 00
|
||||
;---
|
||||
rol $1234,x ; 3E 34 12
|
||||
rol ext,x ; 3E 22 11
|
||||
rol extext,x ; 3Eu00v00
|
||||
ror a ; 6A
|
||||
ror ; 6A
|
||||
;---
|
||||
ror $1234 ; 6E 34 12
|
||||
ror ext ; 6E 22 11
|
||||
ror extext ; 6Eu00v00
|
||||
;---
|
||||
ror $12 ; 66 12
|
||||
ror dir ; 66 33
|
||||
ror extext ; 66 00
|
||||
;---
|
||||
ror $12,x ; 76 12
|
||||
ror dir,x ; 76 33
|
||||
ror offset,x ; 76 44
|
||||
ror extdir,x ; 76 00
|
||||
;---
|
||||
ror $1234,x ; 7E 34 12
|
||||
ror ext,x ; 7E 22 11
|
||||
ror extext,x ; 7Eu00v00
|
||||
rti ; 40
|
||||
rts ; 60
|
||||
sbc #$12 ; E9 12
|
||||
;---
|
||||
sbc $1234 ; ED 34 12
|
||||
sbc ext ; ED 22 11
|
||||
sbc extext ; EDu00v00
|
||||
;---
|
||||
sbc $12 ; E5 12
|
||||
sbc dir ; E5 33
|
||||
sbc extext ; E5 00
|
||||
;---
|
||||
sbc $12,x ; F5 12
|
||||
sbc dir,x ; F5 33
|
||||
sbc offset,x ; F5 44
|
||||
sbc extdir,x ; F5 00
|
||||
;---
|
||||
sbc $1234,x ; FD 34 12
|
||||
sbc ext,x ; FD 22 11
|
||||
sbc extext,x ; FDu00v00
|
||||
;---
|
||||
sbc $1234,y ; F9 34 12
|
||||
sbc dir,y ; F9 33 00
|
||||
sbc extdir,y ; F9u00v00
|
||||
sbc ext,y ; F9 22 11
|
||||
sbc extext,y ; F9u00v00
|
||||
;---
|
||||
sbc ($12,x) ; E1 12
|
||||
sbc (dir,x) ; E1 33
|
||||
sbc (offset,x) ; E1 44
|
||||
sbc (extdir,x) ; E1 00
|
||||
sbc (extext,x) ; E1 00
|
||||
;---
|
||||
sbc ($12),y ; F1 12
|
||||
sbc (dir),y ; F1 33
|
||||
sbc (offset),y ; F1 44
|
||||
sbc (extdir),y ; F1 00
|
||||
sbc (extext),y ; F1 00
|
||||
;---
|
||||
.ifdef P65C02
|
||||
sbc ($12) ; F2 12
|
||||
sbc (dir) ; F2 33
|
||||
sbc (offset) ; F2 44
|
||||
sbc (extdir) ; F2 00
|
||||
sbc (extext) ; F2 00
|
||||
.endif
|
||||
sec ; 38
|
||||
sed ; F8
|
||||
sei ; 78
|
||||
;.if r65f11+r65c00+r65c02
|
||||
.ifdef P65C02
|
||||
smb 0,$12 ; 87 12
|
||||
smb 1,$12 ; 97 12
|
||||
smb 2,$12 ; A7 12
|
||||
smb 3,$12 ; B7 12
|
||||
smb 4,$12 ; C7 12
|
||||
smb 5,$12 ; D7 12
|
||||
smb 6,$12 ; E7 12
|
||||
smb 7,$12 ; F7 12
|
||||
smb 0,dir ; 87 33
|
||||
smb 0,extdir ; 87 00
|
||||
.endif
|
||||
;sta #$12 ; 89 12
|
||||
;---
|
||||
sta $1234 ; 8D 34 12
|
||||
sta ext ; 8D 22 11
|
||||
sta extext ; 8Du00v00
|
||||
;---
|
||||
sta $12 ; 85 12
|
||||
sta dir ; 85 33
|
||||
sta extext ; 85 00
|
||||
;---
|
||||
sta $12,x ; 95 12
|
||||
sta dir,x ; 95 33
|
||||
sta offset,x ; 95 44
|
||||
sta extdir,x ; 95 00
|
||||
;---
|
||||
sta $1234,x ; 9D 34 12
|
||||
sta ext,x ; 9D 22 11
|
||||
sta extext,x ; 9Du00v00
|
||||
;---
|
||||
sta $1234,y ; 99 34 12
|
||||
sta dir,y ; 99 33 00
|
||||
sta extdir,y ; 99u00v00
|
||||
sta ext,y ; 99 22 11
|
||||
sta extext,y ; 99u00v00
|
||||
;---
|
||||
sta ($12,x) ; 81 12
|
||||
sta (dir,x) ; 81 33
|
||||
sta (offset,x) ; 81 44
|
||||
sta (extdir,x) ; 81 00
|
||||
sta (extext,x) ; 81 00
|
||||
;---
|
||||
sta ($12),y ; 91 12
|
||||
sta (dir),y ; 91 33
|
||||
sta (offset),y ; 91 44
|
||||
sta (extdir),y ; 91 00
|
||||
sta (extext),y ; 91 00
|
||||
;---
|
||||
.ifdef P65C02
|
||||
sta ($12) ; 92 12
|
||||
sta (dir) ; 92 33
|
||||
sta (offset) ; 92 44
|
||||
sta (extdir) ; 92 00
|
||||
sta (extext) ; 92 00
|
||||
.endif
|
||||
stx $12 ; 86 12
|
||||
stx dir ; 86 33
|
||||
stx extdir ; 86 00
|
||||
;---
|
||||
stx $1234 ; 8E 34 12
|
||||
stx ext ; 8E 22 11
|
||||
stx extext ; 8Eu00v00
|
||||
;---
|
||||
stx $12,y ; 96 12
|
||||
stx dir,y ; 96 33
|
||||
stx extdir,y ; 96 00
|
||||
sty $12 ; 84 12
|
||||
sty dir ; 84 33
|
||||
sty extdir ; 84 00
|
||||
;---
|
||||
sty $1234 ; 8C 34 12
|
||||
sty ext ; 8C 22 11
|
||||
sty extext ; 8Cu00v00
|
||||
;---
|
||||
sty $12,x ; 94 12
|
||||
sty dir,x ; 94 33
|
||||
sty extdir,x ; 94 00
|
||||
.ifdef P65C02
|
||||
stz $12 ; 64 12
|
||||
stz dir ; 64 33
|
||||
stz extdir ; 64 00
|
||||
;---
|
||||
stz $1234 ; 9C 34 12
|
||||
stz ext ; 9C 22 11
|
||||
stz extext ; 9Cu00v00
|
||||
;---
|
||||
stz $12,x ; 74 12
|
||||
stz dir,x ; 74 33
|
||||
stz extdir,x ; 74 00
|
||||
;---
|
||||
stz $1234,x ; 9E 34 12
|
||||
stz ext,x ; 9E 22 11
|
||||
stz extext,x ; 9Eu00v00
|
||||
.endif
|
||||
tax ; AA
|
||||
tay ; A8
|
||||
;---
|
||||
.ifdef P65C02
|
||||
trb $1234 ; 1C 34 12
|
||||
trb ext ; 1C 22 11
|
||||
trb extext ; 1Cu00v00
|
||||
;---
|
||||
trb $12 ; 14 12
|
||||
trb dir ; 14 33
|
||||
trb extdir ; 14 00
|
||||
tsb $1234 ; 0C 34 12
|
||||
tsb ext ; 0C 22 11
|
||||
tsb extext ; 0Cu00v00
|
||||
;---
|
||||
tsb $12 ; 04 12
|
||||
tsb dir ; 04 33
|
||||
tsb extdir ; 04 00
|
||||
;---
|
||||
.endif
|
||||
tsx ; BA
|
||||
txa ; 8A
|
||||
txs ; 9A
|
||||
tya ; 98
|
||||
|
||||
.ifdef PW65C02
|
||||
;---
|
||||
stp ; DB
|
||||
wai ; CB
|
||||
.endif
|
||||
|
||||
.end
|
||||
55
tests/kow-test-asm.asm
Normal file
55
tests/kow-test-asm.asm
Normal file
@@ -0,0 +1,55 @@
|
||||
;KOWALSKI ASSEMBLER LOGICAL, BITWISE & ARITHMETIC OPERATORS
|
||||
;
|
||||
;
|
||||
; number radices...
|
||||
;
|
||||
; % binary, e.g., %01011010
|
||||
; $ hex, e.g., $5a
|
||||
; none decimal
|
||||
;
|
||||
|
||||
; .opt proc65c02,caseinsensitive
|
||||
|
||||
test0001 =%00001111
|
||||
test0002 =test0001 << 4 ;logical shift left 4 bits
|
||||
test0003 =test0002 >> 4 ;logical shift right 4 bits
|
||||
test0004 =test0001 & test0002 ;bitwise AND
|
||||
test0005 =test0001 | test0002 ;bitwise OR
|
||||
test0006 =test0001 && test0002 ;logical AND
|
||||
test0007 =test0001 || test0002 ;logical OR
|
||||
test0008 =!0 ;bitwise NOT
|
||||
test0009 =$5a ^ test0005 ;bitwise XOR
|
||||
test0010 =4 == 3 ;equality test
|
||||
test0011 =4 == 4 ;equality test
|
||||
test0012 =4 != 3 ;inequality test
|
||||
test0013 =4 != 4 ;inequality test
|
||||
test0014 =4 > 3 ;greater-than test
|
||||
test0015 =4 < 3 ;lesser-than test
|
||||
test0016 =~1 ;2s complement
|
||||
|
||||
;
|
||||
;
|
||||
; arithmetic operators...
|
||||
;
|
||||
; + addition
|
||||
; - subtraction
|
||||
; * multiplication
|
||||
; / division
|
||||
; % modulo
|
||||
;
|
||||
sum = 5 + 6 ;evaluates to 11
|
||||
diff = sum - 6 ;evaluates to 5
|
||||
prod = 5 * 6 ;evaluates to 30
|
||||
quot =prod / diff ;evaluates to 6
|
||||
mod =prod % sum ;evaluates to 8
|
||||
;
|
||||
;
|
||||
; example using square brackets to alter evaluation precedence...
|
||||
;
|
||||
test0017 =5 + 6 * 2 ;strictly left-to-right: evaluates to 17
|
||||
test0018 =(5 + 6) * 2 ;sum of 5 & 6 computed 1st: evaluates to 22
|
||||
;
|
||||
|
||||
nop
|
||||
|
||||
.end
|
||||
Reference in New Issue
Block a user