mirror of
https://github.com/ksherlock/x65.git
synced 2025-04-11 00:38:39 +00:00
Added type of sections
- x65 now has a type for each section
This commit is contained in:
parent
97dc0ad5e6
commit
5030d0be15
79
README.md
79
README.md
@ -23,6 +23,17 @@ There are no hard limits on binary size so if the address exceeds $ffff it will
|
||||
|
||||
There is a sublime package for coding/building in Sublime Text 3 in the *sublime* subfolder.
|
||||
|
||||
## Features
|
||||
|
||||
* **Code**
|
||||
* **Linking**
|
||||
* **Comments**
|
||||
* **Labels**
|
||||
* **Directives**
|
||||
* **Macros**
|
||||
* **Expressions**
|
||||
* **List File with Cycle Count**
|
||||
|
||||
## Prerequisite
|
||||
|
||||
x65.cpp requires struse.h which is a single file text parsing library that can be retrieved from https://github.com/Sakrac/struse.
|
||||
@ -65,16 +76,6 @@ x65 filename.s code.prg [options]
|
||||
* -vice (file.vs): export a vice symbol file
|
||||
* -endm: macro and rept end with endm/endr or endmacro/endrepeat instead of scoped ('{' - '}')
|
||||
|
||||
## Features
|
||||
|
||||
* **Code**
|
||||
* **Linking**
|
||||
* **Comments**
|
||||
* **Labels**
|
||||
* **Directives**
|
||||
* **Macros**
|
||||
* **Expressions**
|
||||
|
||||
### Code
|
||||
|
||||
Code is any valid mnemonic/opcode and addressing mode. At the moment only one opcode per line is assembled.
|
||||
@ -686,6 +687,63 @@ Define byte triplets (like **DA** but three bytes instead of 2)
|
||||
|
||||
Define values of four bytes.
|
||||
|
||||
## List File
|
||||
|
||||
This is a typical list file. Columns from left to right are:
|
||||
|
||||
* Address
|
||||
* Bytes (up to 4) generated by this line
|
||||
* Instruction (disassembled)
|
||||
* Cycles for this instruction, + indicates this instruction can be an extra cycle due to condition or for 65816 multiple extra cycles.
|
||||
* Source code that generated this line
|
||||
|
||||
For scope lines ('{' - '}') the sum of the cycles within the scope is added up as are the additional cycles.
|
||||
|
||||
```
|
||||
c>1 Sin {
|
||||
$0000 a2 03 ldx #$03 2 ldx #3
|
||||
c>2 {
|
||||
$0002 b5 e8 lda $e8,x 4 lda SinP.Ang,x
|
||||
$0004 95 ec sta $ec,x 4 sta SinP.R,x ; result starts with x
|
||||
$0006 95 e4 sta $e4,x 4 sta SinP.W0,x
|
||||
$0008 95 f4 sta $f4,x 4 sta Mul824.A,x
|
||||
$000a 95 f0 sta $f0,x 4 sta Mul824.B,x
|
||||
$000c ca dex 2 dex
|
||||
$000d 10 f3 bpl $0002 2+ bpl !
|
||||
c<2 = 24 + 1 }
|
||||
; x^2, copy to W1
|
||||
$000f a9 e0 lda #$e0 2 lda #SinP.W1
|
||||
$0011 20 00 00 jsr $0000 6 jsr Multiply824S_Copy
|
||||
; iterate value
|
||||
$0014 a0 00 ldy #$00 2 ldy #0
|
||||
.SinIterate
|
||||
c>2 {
|
||||
; W0 *= W1
|
||||
$0016 a2 03 ldx #$03 2 ldx #3
|
||||
c>3 {
|
||||
$0018 b5 e4 lda $e4,x 4 lda SinP.W0,x ; x^(1+2n)
|
||||
$001a 95 f4 sta $f4,x 4 sta Mul824.A,x
|
||||
$001c b5 e0 lda $e0,x 4 lda SinP.W1,x ; x^2
|
||||
$001e 95 f0 sta $f0,x 4 sta Mul824.B,x
|
||||
$0020 ca dex 2 dex
|
||||
$0021 10 f5 bpl $0018 2+ bpl !
|
||||
c<3 = 20 + 1 }
|
||||
$0023 a9 e4 lda #$e4 2 lda #SinP.W0 ; Copy to W0
|
||||
$0025 20 00 00 jsr $0000 6 jsr Multiply824S_Copy
|
||||
$0028 a2 e4 ldx #$e4 2 ldx #SinP.W0 ; Copy W0 to A
|
||||
$002a a9 f4 lda #$f4 2 lda #Mul824.A
|
||||
$002c 20 00 00 jsr $0000 6 jsr Cpy824Z
|
||||
$002f a2 00 ldx #$00 2 ldx #0
|
||||
c>3 {
|
||||
$0031 b9 00 00 lda $0000,y 4+ lda SinInvPermute,y
|
||||
$0034 95 f0 sta $f0,x 4 sta Mul824.B,x
|
||||
$0036 c8 iny 2 iny
|
||||
$0037 e8 inx 2 inx
|
||||
$0038 e0 04 cpx #$04 2 cpx #4
|
||||
$003a d0 f5 bne $0031 2+ bne !
|
||||
c<3 = 16 + 2 }
|
||||
```
|
||||
|
||||
## <a name="expressions">Expression syntax
|
||||
|
||||
Expressions contain values, such as labels or raw numbers and operators including +, -, \*, /, & (and), | (or), ^ (eor), << (shift left), >> (shift right) similar to how expressions work in C. Parenthesis are supported for managing order of operations where C style precedence needs to be overridden. In addition there are some special characters supported:
|
||||
@ -833,6 +891,7 @@ Fish food! Assembler has all important features and switching to make a 6502 pro
|
||||
* irp (indefinite repeat)
|
||||
|
||||
**FIXED**
|
||||
* Added section types, should cover most intuitive formats (seg.type; segment name; segment "name": type; etc. etc.)
|
||||
* Changed the data for relocs to better match Apple II GS OMF format which also changes the object file format.
|
||||
* Added a disassembler (disassembler/x65dsasm.s)
|
||||
* % evaluates to the current end of scope instead of whatever scope ends first
|
||||
|
@ -42,6 +42,14 @@
|
||||
//
|
||||
//
|
||||
|
||||
enum SectionType : char {
|
||||
ST_UNDEFINED, // not set
|
||||
ST_CODE, // default type
|
||||
ST_DATA, // data section (matters for GS/OS OMF)
|
||||
ST_BSS, // uninitialized data section
|
||||
ST_ZEROPAGE // ununitialized data section in zero page / direct page
|
||||
};
|
||||
|
||||
struct ObjFileHeader {
|
||||
short id; // 'x6'
|
||||
short sections;
|
||||
@ -69,7 +77,8 @@ struct ObjFileSection {
|
||||
int output_size; // assembled binary size
|
||||
int align_address;
|
||||
short relocs;
|
||||
short flags;
|
||||
SectionType type;
|
||||
char flags;
|
||||
};
|
||||
|
||||
struct ObjFileReloc {
|
||||
@ -161,6 +170,14 @@ static const char *reloc_type[] = {
|
||||
static const char *late_type[] = {
|
||||
"LABEL", "ABS_REF", "ABS_L_REF", "ABS_4_REF",
|
||||
"BRANCH", "BRANCH_16", "BYTE" };
|
||||
static const char *section_type[] = {
|
||||
"UNDEFINED", // not set
|
||||
"CODE", // default type
|
||||
"DATA", // data section (matters for GS/OS OMF)
|
||||
"BSS", // uninitialized data section
|
||||
"ZEROPAGE" // ununitialized data section in zero page / direct page
|
||||
};
|
||||
static const int section_type_str = sizeof(section_type) / sizeof(section_type[0]);
|
||||
|
||||
|
||||
void ReadObjectFile(const char *file, unsigned int show = SHOW_DEFAULT)
|
||||
@ -187,28 +204,29 @@ void ReadObjectFile(const char *file, unsigned int show = SHOW_DEFAULT)
|
||||
for (int si = 0; si < hdr.sections; si++) {
|
||||
struct ObjFileSection &s = aSect[si];
|
||||
short f = s.flags;
|
||||
const char *tstr = s.type > 0 && s.type < section_type_str ? section_type[s.type] : "error";
|
||||
if (f & (1 << ObjFileSection::OFS_MERGED)) {
|
||||
printf("Section %d: " STRREF_FMT "(Merged)\n",
|
||||
printf("Section %d: \"" STRREF_FMT "\": (Merged)\n",
|
||||
reloc_idx, STRREF_ARG(PoolStr(s.name, str_orig)));
|
||||
} else if (f & (1 << ObjFileSection::OFS_DUMMY)) {
|
||||
if (f&(1 << ObjFileSection::OFS_FIXED)) {
|
||||
printf("Section %d: " STRREF_FMT "(Dummy, fixed at $%04x)\n",
|
||||
reloc_idx, STRREF_ARG(PoolStr(s.name, str_orig)), s.start_address);
|
||||
printf("Section %d: \"" STRREF_FMT "\": (Dummy [%s], fixed at $%04x)\n",
|
||||
reloc_idx, STRREF_ARG(PoolStr(s.name, str_orig)), tstr, s.start_address);
|
||||
} else {
|
||||
printf("Section %d: " STRREF_FMT "(Dummy, relative)\n",
|
||||
reloc_idx, STRREF_ARG(PoolStr(s.name, str_orig)));
|
||||
printf("Section %d: \"" STRREF_FMT "\": (Dummy [%s], relative)\n",
|
||||
reloc_idx, STRREF_ARG(PoolStr(s.name, str_orig)), tstr);
|
||||
}
|
||||
} else {
|
||||
if (f&(1 << ObjFileSection::OFS_FIXED)) {
|
||||
printf("Section %d: " STRREF_FMT "(Fixed $%04x, $%x bytes)\n",
|
||||
reloc_idx, STRREF_ARG(PoolStr(s.name, str_orig)), s.start_address, s.output_size);
|
||||
printf("Section %d: \"" STRREF_FMT "\": (Fixed [%s] $%04x, $%x bytes)\n",
|
||||
reloc_idx, STRREF_ARG(PoolStr(s.name, str_orig)), tstr, s.start_address, s.output_size);
|
||||
} else {
|
||||
printf("Section %d: " STRREF_FMT "(Relative, $%x bytes, align to $%x)\n",
|
||||
reloc_idx, STRREF_ARG(PoolStr(s.name, str_orig)), s.output_size, s.align_address);
|
||||
printf("Section %d: \"" STRREF_FMT "\": (Relative [%s], $%x bytes, align to $%x)\n",
|
||||
reloc_idx, STRREF_ARG(PoolStr(s.name, str_orig)), tstr, s.output_size, s.align_address);
|
||||
}
|
||||
strref export_append = PoolStr(s.exp_app, str_orig);
|
||||
if (export_append)
|
||||
printf(" Export as: " STRREF_FMT "\n", STRREF_ARG(export_append));
|
||||
printf(" Export as: \"" STRREF_FMT "\"\n", STRREF_ARG(export_append));
|
||||
}
|
||||
reloc_idx++;
|
||||
}
|
||||
@ -270,7 +288,7 @@ void ReadObjectFile(const char *file, unsigned int show = SHOW_DEFAULT)
|
||||
}
|
||||
|
||||
if (show & SHOW_CODE_RANGE)
|
||||
printf("Code block: $%x - $%x (%d bytes)\n", (size_t)code_start, size, size - hdr.bindata);
|
||||
printf("Code block: $%x - $%x (%d bytes)\n", (int)code_start, (int)size, (int)(size - hdr.bindata));
|
||||
|
||||
// restore previous section
|
||||
} else
|
||||
|
66
x65.cpp
66
x65.cpp
@ -1125,6 +1125,14 @@ struct ListLine {
|
||||
};
|
||||
typedef std::vector<struct ListLine> Listing;
|
||||
|
||||
enum SectionType : char {
|
||||
ST_UNDEFINED, // not set
|
||||
ST_CODE, // default type
|
||||
ST_DATA, // data section (matters for GS/OS OMF)
|
||||
ST_BSS, // uninitialized data section
|
||||
ST_ZEROPAGE // ununitialized data section in zero page / direct page
|
||||
};
|
||||
|
||||
// start of data section support
|
||||
// Default is a relative section
|
||||
// Whenever org or dum with address is encountered => new section
|
||||
@ -1155,10 +1163,11 @@ typedef struct Section {
|
||||
|
||||
bool address_assigned; // address is absolute if assigned
|
||||
bool dummySection; // true if section does not generate data, only labels
|
||||
SectionType type; // distinguishing section type for relocatable output
|
||||
|
||||
void reset() { // explicitly cleaning up sections, not called from Section destructor
|
||||
name.clear(); export_append.clear();
|
||||
start_address = address = load_address = 0x0;
|
||||
start_address = address = load_address = 0x0; type = ST_CODE;
|
||||
address_assigned = false; output = nullptr; curr = nullptr;
|
||||
dummySection = false; output_capacity = 0; merged_offset = -1; merged_section = -1;
|
||||
align_address = 1; if (pRelocs) delete pRelocs;
|
||||
@ -1746,22 +1755,52 @@ void Asm::SetSection(strref name, int address)
|
||||
current_section = &allSections[allSections.size()-1];
|
||||
}
|
||||
|
||||
void Asm::SetSection(strref name)
|
||||
void Asm::SetSection(strref line)
|
||||
{
|
||||
if (link_all_section)
|
||||
LinkAllToSection();
|
||||
if (allSections.size()==allSections.capacity())
|
||||
allSections.reserve(allSections.size() + 16);
|
||||
|
||||
SectionType type = ST_UNDEFINED;
|
||||
|
||||
// SEG.U etc.
|
||||
if (line.get_first() == '.') {
|
||||
++line;
|
||||
switch (strref::tolower(line.get_first())) {
|
||||
case 'u': type = ST_BSS; break;
|
||||
case 'z': type = ST_ZEROPAGE; break;
|
||||
case 'd': type = ST_DATA; break;
|
||||
case 'c': type = ST_CODE; break;
|
||||
}
|
||||
}
|
||||
line.trim_whitespace();
|
||||
|
||||
int align = 1;
|
||||
strref align_str = name.after(',');
|
||||
align_str.trim_whitespace();
|
||||
if (align_str.get_first()=='$') {
|
||||
++align_str;
|
||||
align = align_str.ahextoui();
|
||||
} else
|
||||
align = align_str.atoi();
|
||||
Section newSection(name.before_or_full(','));
|
||||
strref name;
|
||||
while (strref arg = line.split_token_any_trim(",:")) {
|
||||
if (arg.get_first() == '$') { ++arg; align = arg.ahextoui(); }
|
||||
else if (arg.is_number()) align = arg.atoi();
|
||||
else if (arg.get_first() == '"') name = (arg + 1).before_or_full('"');
|
||||
else if (!name) name = arg;
|
||||
else if (arg.same_str("code")) type = ST_CODE;
|
||||
else if (arg.same_str("data")) type = ST_DATA;
|
||||
else if (arg.same_str("bss")) type = ST_BSS;
|
||||
else if (arg.same_str("zp") || arg.same_str("dp") ||
|
||||
arg.same_str("zeropage") || arg.same_str("direct")) type = ST_ZEROPAGE;
|
||||
}
|
||||
if (type == ST_UNDEFINED) {
|
||||
if (name.find("code") >= 0) type = ST_CODE;
|
||||
else if (name.find("data") >= 0) type = ST_DATA;
|
||||
else if (name.find("bss") >= 0) type = ST_BSS;
|
||||
else if (name.find("zp") >= 0 || name.find("zeropage") >= 0 || name.find("direct") >= 0)
|
||||
type = ST_ZEROPAGE;
|
||||
else type = ST_CODE;
|
||||
}
|
||||
|
||||
Section newSection(name);
|
||||
newSection.align_address = align;
|
||||
newSection.type = type;
|
||||
allSections.push_back(newSection);
|
||||
current_section = &allSections[allSections.size()-1];
|
||||
}
|
||||
@ -4049,7 +4088,7 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
|
||||
return Directive_LOAD(line);
|
||||
|
||||
case AD_SECTION:
|
||||
SetSection(line.get_trimmed_ws());
|
||||
SetSection(line);
|
||||
break;
|
||||
|
||||
case AD_LINK:
|
||||
@ -5360,7 +5399,8 @@ struct ObjFileSection {
|
||||
int output_size; // assembled binary size
|
||||
int align_address;
|
||||
short relocs;
|
||||
short flags;
|
||||
SectionType type;
|
||||
char flags;
|
||||
};
|
||||
|
||||
struct ObjFileReloc {
|
||||
@ -5490,6 +5530,7 @@ StatusCode Asm::WriteObjectFile(strref filename)
|
||||
s.align_address = si->align_address;
|
||||
s.relocs = si->pRelocs ? (short)(si->pRelocs->size()) : 0;
|
||||
s.start_address = si->start_address;
|
||||
s.type = si->type;
|
||||
s.flags =
|
||||
(si->IsDummySection() ? (1 << ObjFileSection::OFS_DUMMY) : 0) |
|
||||
(si->IsMergedSection() ? (1 << ObjFileSection::OFS_MERGED) : 0) |
|
||||
@ -5659,6 +5700,7 @@ StatusCode Asm::ReadObjectFile(strref filename)
|
||||
CurrSection().export_append = aSect[si].exp_app.offs>=0 ? strref(str_pool + aSect[si].name.offs) : strref();
|
||||
CurrSection().align_address = aSect[si].align_address;
|
||||
CurrSection().address = CurrSection().start_address + aSect[si].output_size;
|
||||
CurrSection().type = aSect[si].type;
|
||||
if (aSect[si].output_size) {
|
||||
CurrSection().output = (unsigned char*)malloc(aSect[si].output_size);
|
||||
memcpy(CurrSection().output, bin_data, aSect[si].output_size);
|
||||
|
Loading…
x
Reference in New Issue
Block a user