diff --git a/README.md b/README.md index 692ea17..57de0c0 100644 --- a/README.md +++ b/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 } +``` + ## 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 diff --git a/dump_x65/dump_x65.cpp b/dump_x65/dump_x65.cpp index b1b522f..f593cc1 100644 --- a/dump_x65/dump_x65.cpp +++ b/dump_x65/dump_x65.cpp @@ -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 diff --git a/x65.cpp b/x65.cpp index 09806ce..3c99466 100644 --- a/x65.cpp +++ b/x65.cpp @@ -1125,6 +1125,14 @@ struct ListLine { }; typedef std::vector 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);