mirror of
https://github.com/RevCurtisP/C02.git
synced 2025-02-19 19:31:04 +00:00
Added #pragma rambase & writebase directives
This commit is contained in:
parent
265eb513cc
commit
ba25988b31
30
doc/c02.txt
30
doc/c02.txt
@ -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
|
||||
|
@ -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
|
||||
----------------
|
||||
|
||||
|
@ -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/");
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
35
src/stmnt.c
35
src/stmnt.c
@ -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 */
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
13
work/rambase.c02
Normal 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
13
work/wrtbase.c02
Normal 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;
|
Loading…
x
Reference in New Issue
Block a user