Added #pragma rambase & writebase directives

This commit is contained in:
Curtis F Kaylor 2018-08-16 16:26:44 -04:00
parent 265eb513cc
commit ba25988b31
11 changed files with 192 additions and 15 deletions

View File

@ -141,15 +141,41 @@ Examples:
#pragma padding 1 //Add one empty byte to end of code
#pragma padding $FF //Add 255 empty bytes to end of code
PRAGMA RAMBASE
The #pragma rambase directive sets the base address for variables in RAM
(not declared const). This is normally used when the compiled code will be
stored in ROM (such as in an EPROM or Cartridge), but can be used any time
variables should be in a specific area of RAM.
Examples:
#pragma rambase $0200 //Define Variable RAM base address for NES
#pragma rambase 828 //Define Variable RAM in C64 Tape Buffer
#pragma rambase 4096 //Define RAM base for Vic 20 ROM cartridge
PRAGMA VARTABLE
The #pragma vartable directive forces the variable table to be written.
It should be used before any #include directives that need to generate
code following the table.
PRAGMA WRITEBASE
The #pragma writebase directive sets the base address for writing to variables
in RAM. This is used when target system uses different addresses for reading
and writing the same memory locations. This directive must be preceded by
#pragma rambase directive with a non-zero argument.
Examples:
#pragma rambase $F080 //Define Superchip RAM Read Base for Atari 2600
#pragma writebase $F000 //Define Superchip RAM Write Base for Atari 2600
Note: Setting a RAM write base causes the compiler to generate a write offset
which is concatenated to the variable name on all assignments.
PRAGMA ZEROPAGE
The #pragma zeropage variable sets the base address for variables declared
The #pragma zeropage directive sets the base address for variables declared
as zeropage.
Example:
@ -189,7 +215,7 @@ The " character and a subset of ASCII control characters can be specified
in a string literal by using escape sequences prefixed with the \ symbol:
\b $08 Backspace
\e $08 Escape
\e $1B Escape
\f $0C Form Feed
\n $0A Line Feed
\r $0D Carriage Return

View File

@ -1,5 +1,78 @@
C02 Design Considerations
Variable Storage
================
Zero Page
---------
The 6502 has a Zero Page addressing mode. This differs from the absolute
addressing mode in that the address operand is only one byte instead of
two and the instructions take less cycles to execute.
Also, some systems have very limited RAM, requiring all variables to be
stored in zero page. One example is the Atari 2600, which maps the 128
bytes of RAM in the RIOT chip to the range $80-$8F and mirrors it at
$180-$18F (for the machine stack).
To allow the use of zero page variables, the compiler recognizes the
"zeropage" declaration modifier and the "#pragma zeropage" directive,
the latter of which specifies a base address for allocating zero page
variables.
I may add a -Z command line option to allow the specification of the
zero page variable base address.
ROM Based Code
--------------
For compiled programs that will reside in ROM, such as an EPROM or a
cartridge, variables will need to reside in a separate memory area than
the program.
The compiler normally allocates all variables directly after the generated
code, const variables first and regular variables afterward. In addition,
the regular variables are all all allocated as zero bytes in the assembled
object code, which can unnecesarilly inflate the size of the generated
binary file.
The compiler allows the location of non-const variables to be specified
using the "#pragma rambase" directive.
I may add a -R command line option to allow the specification of the RAM
variable base address.
Read/Write Variables
--------------------
Some systems used different memory addresses for reading and writing to
RAM. One example is Atari 2600 catridges with RAM. The SARA Superchip
contained 128 bytes of RAM, which were written at addresses $F000 through
$F01F and read from addresses $F080 through $F0FF, while CBS RAM+ had 256
bytes which were written from $F000 though $F0FF and read from $F100
through $F1FF.
To allow for this, the compiler recognizes an additional directive,
"#pragma writebase" directive. In this case the "#pragma rambase"
will specify the base address for reads. When a write base address is
specified, the compiler will allocate all variables using the read base
address and generate an offset, which will be included in all variable
assignments. Thus the code
#pragma rambase $F100
#pragma writebase $F000
char b,c;
c = b;
would generate the assembly code
LDA B
STA C-256
B EQU $F100
C EQU $F101
I may add a -W command line option to allow the specification of the write
base address.
Variable Types
==============
@ -217,6 +290,7 @@ whereas the equivalent C02 code generates much simpler machine code:
Shift Operators
----------------

View File

@ -42,10 +42,13 @@ void init(void) {
nxtwrd[0] = 0; //Next Word (from DEFINE lookup)
nxtptr = 0; //Pointer to next character in nxtwrd
vrwrtn = FALSE; //Variables Written Flag
rambas = 0; //RAM Base Address
wrtbas = 0; //Write Base Address
zpaddr = 0; //Current Zero-Page Address
invasc = FALSE; //Invert ASCII Flag
mskasc = FALSE; //Set High Bit Flag
fcase = FALSE; //First Case Statement Flag
wrtofs[0] = 0; //Write Offset
xsnvar[0] = 0; //Assigned X Variable Name
ysnvar[0] = 0; //Assigned Y Variable Name
strcpy(incdir, "../include/");

View File

@ -28,6 +28,7 @@
#define BYTEOP "DC" //Define Byte Pseudo-Op
#define STROP "DS" //Define String Pseudo-Op
#define ALNOP "ALIGN" //Align Pseudo-Op
#define USEGOP "SEG.U" //Uninitalized Segment Pseudo-Op
#define LOCOP "SUBROUTINE" //Local Variable Boundary Pseudo-Op
#define ASMFMT "%-7s %-3s %-12s %s\n" //Assembly Language Line printf Format

View File

@ -90,8 +90,24 @@ void ppddng(void) {
DEBUG("Set padding to %d\n", padcnt)
}
/* Parse RamBase Subdirective */
void prambs(void) {
rambas = prsnum(0xFFFF); //Set Ram Base Address to Literal
DEBUG("Set ram base address to %d\n", rambas)
}
/* Parse WriteBase Subdirective */
void pwrtbs(void) {
if (!rambas) ERROR("RAM Base must be set prior to Write Base\n", 0, EXIT_FAILURE);
wrtbas = prsnum(0xFFFF); //Set Ram Base Address to Literal
DEBUG("Set write base address to %d ", wrtbas)
if (rambas && wrtbas) sprintf(wrtofs, "%+d", wrtbas - rambas);
else wrtofs[0] = 0;
DETAIL("and write offset to '%s'\n", wrtofs)
}
/* Parse Zeropage Subdirective */
void prszpg(void) {
void pzropg(void) {
zpaddr = prsnum(0xFF); //Set Zero Page Address to Literal
DEBUG("Set zero page address to %d\n", zpaddr)
}
@ -112,12 +128,17 @@ void pprgma(void) {
porign(); //Parse Origin
else if (wordis("PADDING"))
ppddng(); //Parse Origin
else if (wordis("RAMBASE"))
prambs(); //Parse RamBase
else if (wordis("VARTABLE"))
pvrtbl(); //Parse Vartable
pvrtbl(); //Parse VarTable
else if (wordis("WRITEBASE"))
pwrtbs(); //Parse RamBase
else if (wordis("ZEROPAGE"))
prszpg(); //Parse Origin
pzropg(); //Parse ZeroPage
else
ERROR("Illegal pragma subdirective '%s'\n", word, EXIT_FAILURE)
cmtlin(); //Write Comment Line
}
/* Process Include File Directive */

View File

@ -70,6 +70,13 @@ void prcidx(int idxtyp, char *name, char *index)
}
}
/* Set word to assignment variable *
* adding write offset (if set) */
void setasn(char *name) {
strcpy(word, name);
if (wrtofs[0]) strcat(word, wrtofs);
}
/* Process Assignment */
void prcasn(char trmntr) {
expect('=');
@ -77,20 +84,27 @@ void prcasn(char trmntr) {
else prsxpr(trmntr); //Parse Expression
DEBUG("Processing X assignment variable '%s'\n", xsnvar)
if (xsnvar[0]) {
setasn(xsnvar);
if (strlen(xsnidx)) { //Process X variable Index
asmlin("PHA", ""); //Save Accumulator
asmlin("TXA", ""); //Transfer Return Value to Accumulator
prcidx(xsnivt, xsnvar, xsnidx); //Process Index
asmlin("STA", xsnvar); //Store Return Value
asmlin("PLA", ""); //Restore Accumulator
if (xsnivt != LITERAL) {
asmlin("PHA", ""); //Save Accumulator
asmlin("TXA", ""); //Transfer Return Value to Accumulator
prcidx(xsnivt, word, xsnidx); //Process Index
asmlin("STA", word); //Store Return Value
asmlin("PLA", ""); //Restore Accumulator
} else {
prcidx(xsnivt, word, xsnidx); //Process Index
asmlin("STX", word); //Store Return Value
}
}
else asmlin("STX", xsnvar); //Store Return Value
else asmlin("STX", word); //Store Return Value
xsnvar[0] = 0;
}
DEBUG("Processing Y assignment variable '%s'\n", ysnvar)
if (ysnvar[0]) {
if (strlen(ysnidx)) prcidx(ysnivt, ysnvar, ysnidx); //Process Index
asmlin("STY", ysnvar); //Store Return Value
setasn(ysnvar);
if (strlen(ysnidx)) prcidx(ysnivt, word, ysnidx); //Process Index
asmlin("STY", word); //Store Return Value
ysnvar[0] = 0;
}
DEBUG("Checking if '%s' is a register\n", asnvar)
@ -98,8 +112,9 @@ void prcasn(char trmntr) {
else if (strcmp(asnvar, "Y")==0) asmlin("TAY", "");
else if (strcmp(asnvar, "A")==0) return;
DEBUG("Processing assignment variable '%s'\n", asnvar)
if (strlen(asnidx)) prcidx(asnivt, asnvar, asnidx); //Process Index
asmlin("STA", asnvar); //Store Return Value
setasn(asnvar);
if (asnidx[0]) prcidx(asnivt, word, asnidx); //Process Index
asmlin("STA", word); //Store Return Value
}
/* Parse and Return Array Index and Type */

View File

@ -318,6 +318,11 @@ void vartbl(void) {
vardef(MTCONST); //Write CONST Definitions
//Emit Segment Mnemonic for RAM Variables here
LCMNT("Writable Variables")
if (rambas) {
asmlin(USEGOP,"RAMVARS"); //Create Uninitialized Segment
sprintf(word, "$%X", rambas);
asmlin(ORGOP, word); //Set Origin to RAM Base Address
}
vardef(0); //Write All Other Variables
}

View File

@ -56,7 +56,10 @@ enum dtypes {DTBYTE, DTSTR, DTARRY}; //Variable Data Types
#define MTALGN 128 //Aligned
int symdef(char *name); //Is Variable defined (TRUE or FALSE)
int rambas; //RAM Base Address (0=None)
int wrtbas; //Write Base Address (0=None)
int zpaddr; //Current Zero-Page Address
char wrtofs[6]; //Write Address Offset
void addvar(int m, int t); //Parse and Compile Variable Declaration
void addstc(); //Parse and Compile Structure Declaration

View File

@ -23,4 +23,7 @@ b = s[func()];
b = s[0] & d[c-1] | n[i+2];
b = s[A] + b[X] + c[Y];
r[0], r[1], r[2] = func();
r[b], r[c], r[i] = func();
pop b, d[i], n[func()], s[c-n[i+3]];

13
work/rambase.c02 Normal file
View File

@ -0,0 +1,13 @@
/* Test RamBase Directive */
#pragma origin $F200
#pragma rambase $F000
char t[128];
const char s = "String";
strdst(&s);
strcpy(&t);
void strcpy() {}
void strdst() {}

13
work/wrtbase.c02 Normal file
View File

@ -0,0 +1,13 @@
/* Test WriteBase Directive */
#pragma origin $F100
#pragma rambase $F080
#pragma writebase $F000
char r[7];
char b,d,i;
const char c = 0;
b = d;
for (i=0;i<7;i++) r[i] = r[i] + i;
r[7]=7;