1
0
mirror of https://github.com/ksherlock/x65.git synced 2024-06-01 12:41:28 +00:00

Compare commits

...

159 Commits

Author SHA1 Message Date
Carl-Henrik Skårstedt
9e542033b8 Macros can use strings 2021-12-12 20:13:05 +01:00
Carl-Henrik Skårstedt
842b68b342 Fixing some illegals 2021-05-15 13:59:44 +02:00
Carl-Henrik Skårstedt
c4dff1c872 Merge branch 'master' of https://github.com/Sakrac/x65 2021-02-11 22:20:31 +01:00
Carl-Henrik Skårstedt
d4345a2352 Moving x65 binaries to releases 2021-02-11 21:37:10 +01:00
Carl-Henrik Skårstedt
3edff374c9 Moving x65 binaries to releases 2021-02-11 21:37:10 +01:00
Carl-Henrik Skårstedt
73eaa45daa fixed Kick Assembler Debugdata output with symbols relative to sections & section naming 2021-02-11 17:34:46 +01:00
Carl-Henrik Skårstedt
101e6ed3de fixed Kick Assembler Debugdata output with symbols relative to sections & section naming 2021-02-11 17:34:46 +01:00
Carl-Henrik Skårstedt
5339e5c789 Fixed x65 symbol files that broke with source debug changes 2021-02-10 23:31:12 +01:00
Carl-Henrik Skårstedt
4a88deb989 Fixed x65 symbol files that broke with source debug changes 2021-02-10 23:31:12 +01:00
Carl-Henrik Skårstedt
74d517e9d3 Minor progress labels & breakpoint source tracking 2021-01-26 23:24:30 +01:00
Carl-Henrik Skårstedt
1928206659 Minor progress labels & breakpoint source tracking 2021-01-26 23:24:30 +01:00
Carl-Henrik Skårstedt
bed84e27cf updating executables 2021-01-14 22:45:56 +01:00
Carl-Henrik Skårstedt
dc53ab5174 Merge pull request #20 from Sakrac/source-debug
Source debug
2021-01-14 20:33:43 +01:00
Carl-Henrik Skårstedt
3596224b3c
Merge pull request #20 from Sakrac/source-debug
Source debug
2021-01-14 20:33:43 +01:00
Carl-Henrik Skårstedt
e0d3f3c9cd Adding notes about how to use source debug output 2021-01-14 20:32:17 +01:00
Carl-Henrik Skårstedt
2bbe8aab66 Adding notes about how to use source debug output 2021-01-14 20:32:17 +01:00
Carl-Henrik Skårstedt
88fc0cbb60 Fixing Source Debug export 2021-01-14 20:28:06 +01:00
Carl-Henrik Skårstedt
efb99fe9ab Fixing Source Debug export 2021-01-14 20:28:06 +01:00
Carl-Henrik Skårstedt
779c7af7ed Source Debug Export 2021-01-14 16:50:33 +01:00
Carl-Henrik Skårstedt
063459efbf Source Debug Export 2021-01-14 16:50:33 +01:00
Carl-Henrik Skårstedt
f67a920a06 Writing object files with source debug, load object files breaks 2021-01-13 23:58:26 +01:00
Carl-Henrik Skårstedt
b75a8325ee Writing object files with source debug, load object files breaks 2021-01-13 23:58:26 +01:00
Carl-Henrik Skårstedt
7df69d5e36 Source level debugging info wip 2021-01-13 17:42:18 +01:00
Carl-Henrik Skårstedt
56fb34c64b Source level debugging info wip 2021-01-13 17:42:18 +01:00
Carl-Henrik Skårstedt
c1fa69d90f added c64 screen codes as a text option 2021-01-12 16:59:41 +01:00
Carl-Henrik Skårstedt
5c98f7c7e8 added c64 screen codes as a text option 2021-01-12 16:59:41 +01:00
Carl-Henrik Skårstedt
060be58f41 Allow code to be compiled in "zero page" 2020-12-13 22:43:53 +01:00
Carl-Henrik Skårstedt
1d70c9b963 Allow code to be compiled in "zero page" 2020-12-13 22:43:53 +01:00
Carl-Henrik Skarstedt
f3b33acf88 make a shell script to compile for linux 2020-12-13 13:35:20 +01:00
Carl-Henrik Skarstedt
98ceceb315 make a shell script to compile for linux 2020-12-13 13:35:20 +01:00
Carl-Henrik Skårstedt
3a33dc7056 Merge pull request #18 from ksherlock/merlin_ddb_2
fix merlin ddb
2020-12-05 20:06:53 +01:00
Carl-Henrik Skårstedt
87d88265b0
Merge pull request #18 from ksherlock/merlin_ddb_2
fix merlin ddb
2020-12-05 20:06:53 +01:00
Carl-Henrik Skarstedt
8e95b7ffb9 Fixed missing return in Find 2020-12-02 19:17:07 +01:00
Carl-Henrik Skarstedt
2a2529f237 Fixed missing return in Find 2020-12-02 19:17:07 +01:00
Carl-Henrik Skårstedt
45b998fa2b Merge pull request #19 from ksherlock/blockmove2
fix mvn/mvp operand order
2020-10-21 09:50:34 +02:00
Carl-Henrik Skårstedt
bf6c7b0df9
Merge pull request #19 from ksherlock/blockmove2
fix mvn/mvp operand order
2020-10-21 09:50:34 +02:00
Kelvin Sherlock
af8c7ae42d fix mvn/mvp argument order
mvn $01,$02 is encoded as: $54 $02 $01
2020-10-20 19:34:38 -04:00
Kelvin Sherlock
34b3c1edb9 fix mvn/mvp argument order
mvn $01,$02 is encoded as: $54 $02 $01
2020-10-20 19:34:38 -04:00
Carl-Henrik Skårstedt
fe924aab14 Merge pull request #17 from ksherlock/clang_warnings
fix clang compiler errors and warnings.
2020-10-19 09:04:33 +02:00
Carl-Henrik Skårstedt
4a81aafdc7
Merge pull request #17 from ksherlock/clang_warnings
fix clang compiler errors and warnings.
2020-10-19 09:04:33 +02:00
Kelvin Sherlock
295129cd6c fix merlin ddb
ddb generates a "double byte" which is actually a big-endian 16-bit number.
For relocation purposes, it has to be handled as 2 individual bytes with shifts to adjust it.
2020-10-18 13:39:42 -04:00
Kelvin Sherlock
da6ed1159d fix merlin ddb
ddb generates a "double byte" which is actually a big-endian 16-bit number.
For relocation purposes, it has to be handled as 2 individual bytes with shifts to adjust it.
2020-10-18 13:39:42 -04:00
Kelvin Sherlock
06aae43fdd fix clang compiler errors and warnings. 2020-10-18 11:58:35 -04:00
Kelvin Sherlock
a2d9c5330d fix clang compiler errors and warnings. 2020-10-18 11:58:35 -04:00
Carl-Henrik Skårstedt
c2492ab348 Merge branch 'master' of https://github.com/Sakrac/x65 2020-04-01 16:19:55 +02:00
Carl-Henrik Skårstedt
1f6956c1ec Added a helper switch to show XREFs/XDEFs before linking 2020-04-01 16:19:48 +02:00
Carl-Henrik Skårstedt
45f5d05f54 Merge pull request #15 from dwsJason/ja-pei
pei addressing
2020-04-01 16:18:34 +02:00
Carl-Henrik Skårstedt
56b253880e Merge pull request #16 from dwsJason/sample_omf
Sample OMF
2020-04-01 16:18:16 +02:00
dwsJason
e6a63010f2 import Tool macros 2020-02-25 21:29:48 -05:00
dwsJason
b8ef00f811 import missing dp.s file 2020-02-25 21:12:55 -05:00
dwsJason
1f61d948fb import: sample OMF application 2020-02-25 21:11:24 -05:00
dwsJason
17a99e46e7 PEI: allow both addressing styles $dp, and ($dp) 2020-02-22 16:20:52 -05:00
dwsJason
fd1bc0ba76 Fix address corruption issue with when code segment is pushed beyond 32kb 2020-02-22 14:04:49 -05:00
Jason Andersen
b699c1b6f4 Merge pull request #1 from Sakrac/master
Sync with x65 master
2020-02-22 13:53:26 -05:00
Carl-Henrik Skårstedt
c1de91e3f1 Fixed a case where addressing mode got confused because a function with multiple parameters was used as the address 2020-01-21 16:49:20 -08:00
Carl-Henrik Skårstedt
53f69edc5a Documented FUNCTION in directives, added errors.md 2020-01-15 11:23:07 -08:00
Carl-Henrik Skårstedt
d80f5473a2 Merge pull request #13 from Sakrac/user-functions
User functions:
User Defined Functions added, you can now create predefined expressions that work similar to a macro but returns a value instead of generating binary:
FUNCTION add_values(a, b) a + b
2020-01-15 10:53:32 -08:00
Carl-Henrik Skårstedt
6af905353c User functions first implementation, added a NOT expression operator 2020-01-15 10:51:02 -08:00
Carl-Henrik Skårstedt
dda49fda57 progress user functions 2020-01-14 23:41:34 -08:00
Carl-Henrik Skårstedt
846bd5cd63 Starting user defined functions 2020-01-14 18:53:02 -08:00
Carl-Henrik Skårstedt
09796bc6e7 Update eval_functions.md 2020-01-11 19:52:43 -08:00
Carl-Henrik Skårstedt
b45da90bce Adding a doc for eval functions. 2020-01-11 13:16:34 -08:00
Carl-Henrik Skårstedt
33e7f72d0b Update directives.md 2020-01-11 13:05:53 -08:00
Carl-Henrik Skårstedt
5cec8f8309 Adding markdown relative links 2020-01-11 13:04:00 -08:00
Carl-Henrik Skårstedt
e3fa7b0c83 Finishing the last sentence in the introduction to directives documentation. 2020-01-11 13:00:57 -08:00
Carl-Henrik Skårstedt
b469ceef8c Expermenting with starting over on the x65 documentation 2020-01-11 12:58:26 -08:00
Carl-Henrik Skårstedt
eb3df4de88 Label pools are 32 bit, added sizeof directive for structs, destructor for Symbol Stacks 2020-01-10 20:52:02 -08:00
Carl-Henrik Skårstedt
4b7e679b20 Merge pull request #12 from Sakrac/functions
Functions
2020-01-10 14:20:45 -08:00
Carl-Henrik Skårstedt
a535295929 Implementing Eval Functions, complimented by IFCONST, IFBLANK and IFNBLANK 2020-01-10 14:20:00 -08:00
Carl-Henrik Skårstedt
758b4349eb Starting assembler functions 2020-01-09 23:10:55 -08:00
Carl-Henrik Skårstedt
600567a42e Merge branch 'master' of https://github.com/Sakrac/x65 2020-01-09 16:09:02 -08:00
Carl-Henrik Skårstedt
385155d5eb Update ca65directive.s 2020-01-09 16:08:14 -08:00
Carl-Henrik Skårstedt
b3d9b40563 push/pull symbols and strings with directiv 2020-01-09 16:01:16 -08:00
Carl-Henrik Skårstedt
12e158d637 Fixed scoped labels turning into local labels and expiring when endscope is encountered 2020-01-08 18:59:06 -08:00
Carl-Henrik Skårstedt
a3f8a7cf44 ca65 uses import/export instead of xref/xdef, section export is not available in this case 2020-01-08 17:04:42 -08:00
Carl-Henrik Skårstedt
66bdac5079 fixed IFDEF/IFNDEF, added partial support for CA65 style SCOPE, fixed -endm style macro parsing. 2020-01-08 14:38:29 -08:00
Carl-Henrik Skårstedt
6e4be1504d Adding an immediate mode version of BRK since the IRQ will treat it as a two byte instruction 2019-11-03 20:34:02 -08:00
Carl-Henrik Skårstedt
963d1925cc changed PEI to zp instead of zp rel 2019-11-03 20:13:28 -08:00
Carl-Henrik Skårstedt
c234531d69 Fixed various issues with linking sections, seemingly broke macros in some way but common usage is fine. 2019-10-27 18:09:48 -07:00
Carl-Henrik Skårstedt
019e8d7ae9 Making sure branch out of range error is propagated in late eval 2019-10-18 00:01:19 -07:00
Carl-Henrik Skårstedt
2243803116 Fixed macro issue that defines a label ending with : 2019-10-17 15:53:28 -07:00
Carl-Henrik Skårstedt
d5080e925d more testing and fixing of partial expressions 2019-10-17 00:16:55 -07:00
Carl-Henrik Skårstedt
7521d31514 debug output for partial late eval, seems ok, can integrate with more testing 2019-10-16 18:33:17 -07:00
Carl-Henrik Skårstedt
33b229d00a Fixing 16 vs 8 bit immediate load issue (again) 2019-09-20 18:20:30 -07:00
Carl-Henrik Skårstedt
6e8a41acc1 removing WDC 65816 specific syntax for non-65816 cpus to maintain code. 2019-09-19 22:06:11 -07:00
Carl-Henrik Skårstedt
de0bc5120f Fixed 16 bit immediate mode, tweaked unit tests, added |/! as WDC syntax for absolute addressing 2019-09-19 21:07:04 -07:00
Carl-Henrik Skårstedt
482470b410 Starting WDC syntax support, adding unit test to repo. 2019-09-19 18:50:30 -07:00
Carl-Henrik Skårstedt
23aedcf686 Fix for bug #1
Force absolute addressing failed when presented with a known long address.
2019-09-18 12:16:58 -07:00
Carl-Henrik Skårstedt
da015f3e1c Missing addressing mode for lax 2019-09-08 00:27:10 -07:00
Carl-Henrik Skårstedt
4670be0ce1 Adding a structure to hold one unit of source level debugging 2019-09-06 18:02:18 -07:00
Carl-Henrik Skårstedt
efacecf701 Adding 64TASS list/labels output files for no reason. 2019-09-03 17:10:48 -07:00
Carl-Henrik Skårstedt
4c3c1654fb Fix for -DLabel=value option 2019-03-13 12:08:21 -07:00
Carl-Henrik Skårstedt
cfb2d1a8d8 Fixed exporting code to addresses below the stack 2018-10-20 18:33:19 -07:00
Carl-Henrik Skårstedt
ab2015fc3d Can evaluate characters by single quote '?' 2018-10-15 00:16:44 -07:00
Carl-Henrik Skårstedt
eae936dd6a swithcing back to vs2015 2018-02-20 13:40:57 -08:00
Carl-Henrik Skårstedt
4285a14801 fixing import with file offset 2018-02-20 13:30:32 -08:00
Carl-Henrik Skårstedt
b16edcd592 Fixed a couple of linker related bugs
did not have any effect, link directive doesn't do what I expect,
probably need to clean up the linker portion.
2017-09-24 22:36:42 -07:00
Carl-Henrik Skårstedt
05b7e253c3 Listing file contains sections including merged sections. 2017-08-06 16:13:11 -07:00
Carl-Henrik Skårstedt
efc63864ee Also cleaning up previous install for Visual Studio Code extension 2017-04-15 20:51:09 -07:00
Carl-Henrik Skårstedt
2698f08ab9 .gitignore adding yet more redundant visual studio project files... 2017-04-15 13:40:47 -07:00
Carl-Henrik Skårstedt
9c7f413dac Changing theme from XML to JSON, adding Windows installer
* I don't like XML one bit
* Writing a bat file is easier than putting something on the marketplace
without using javascript.
2017-04-15 13:34:16 -07:00
Carl-Henrik Skårstedt
49ca89f875 Adding dump_x65 as a VS2017 solution project 2017-04-11 16:10:43 -07:00
Carl-Henrik Skårstedt
479300eec7 Adding a solution for Visual Studio 2017 2017-04-11 12:56:10 -07:00
Carl-Henrik Skårstedt
effd8205db Image fix 2017-01-28 17:05:35 -08:00
Carl-Henrik Skårstedt
adcefe4bff Tuning the lanuage extension for Visual Studio Code a bit 2017-01-28 17:02:41 -08:00
Carl-Henrik Skårstedt
e37bf5ae11 Visual Studio Code colorizing extension, Error includes line number of undefined label reference
* PrintError has an optional argument for enclosing file
* Visual Studio Code extension
2017-01-28 13:29:42 -08:00
Carl-Henrik Skårstedt
576ec5497d MERGE directive, indexed TEXT, Code Style fixes
* Added a directive to control merging of SECTIONs: MERGE
* Added an indexed TEXT format that uses a String Symbol for the
indexing order
* General coding style consitencies
2017-01-08 16:30:30 -08:00
Carl-Henrik Skårstedt
baebdbe096 Label Pool changes
Pool are extended to:
* A pool label can be any size by using POOL <label>.<size> where <size>
is a decimal number
* A pool can define a pool within itself <pool> pool <name> <size> where
<pool> is the name of a pool that would fit another pool and <name> is
the name of the new pool and <size> is the size of the new pool
* pool labels are local if they are preceeded by . or ! or $ or @
* pool labels can be global
2016-12-24 13:23:01 -08:00
Carl-Henrik Skårstedt
fe049342bd README.md edit 2016-12-23 14:04:59 -08:00
Carl-Henrik Skårstedt
8f4a00e3ce Fixing label pools
* label pools don't go out of scope so they can be declared in an
include file and used by the includer file
* label pool labels can be either global or local
* code fixes
* updated struse
* updated binaries
2016-12-23 13:56:57 -08:00
Carl-Henrik Skårstedt
c226b00dad Added visual studio natvis for struse class 2016-05-26 22:28:32 -07:00
Carl-Henrik Skårstedt
b4407f7cb5 struse.h fixes, warning fixes 2016-05-25 22:44:17 -07:00
Carl-Henrik Skårstedt
a0b73db5c8 Struse was updated and fixing related issues 2016-05-20 22:48:13 -07:00
Carl-Henrik Skårstedt
03f5e5cbfe First column in Merlin mode recognizes scope braces ('{' and '}') 2016-03-17 21:33:39 -07:00
Carl-Henrik Skårstedt
e452d3ab7e Fix 2016-03-17 00:07:15 -07:00
Carl-Henrik Skårstedt
9752c1d8a1 Merlin macro fix
- Does not require merlin macro parameters to be listed after the
keyword MAC
- Updated struse.h
2016-03-17 00:05:36 -07:00
Carl-Henrik Skårstedt
73d67d0657 Context scope cleanup and fix for sequential subtraction in expressions
- Should clean up Merlin mode macros a bit
- Fixes a numerical error
2016-03-13 18:16:43 -07:00
Carl-Henrik Skårstedt
0fcdc9ca47 Switching dump_x65 to inttypes.h and updating binaries
- dump_x65 now matches object code structures in x65
2016-03-12 11:57:39 -08:00
Carl-Henrik Skårstedt
d1c9f3aab5 Fix for local labels accessed crossing over a REPT / LUP
- Added a scope increment when entering a block of repeated code so only
the local symbols within the block would be destroyed each iteration
- Switched over to inttypes.h to make code a smidgeon more readable
2016-03-12 11:39:53 -08:00
Carl-Henrik Skårstedt
07b1a52bb4 Updating binaries 2016-03-11 17:55:32 -08:00
Carl-Henrik Skårstedt
4f6db98637 Removing the disassembler and putting it into its own repo
- The disassembler was taking on some girth and weighing the assembler
code down.
2016-03-11 17:43:16 -08:00
Carl-Henrik Skårstedt
d9d386a260 Adding error handling for flushing local labels
- Errors were ignored in a couple of places
2016-03-11 17:08:44 -08:00
Carl-Henrik Skårstedt
273bdcc92d Fix for local labels within rept/LUP and force org with command line argument
- Flushing local labels after each rept/LUP source segment so local
labels within won't cross over the segment boundary
- The command line argument -org will force fixed address rather than
suggest a location, which in turn makes the -lst command line more
readable.
2016-03-11 16:58:24 -08:00
Carl-Henrik Skårstedt
ee53c41776 Fix for Merlin macros with arguments
- Macro argument was assembled and first argument was defined as a label
2016-03-11 14:12:32 -08:00
Carl-Henrik Skårstedt
341cc8f2ad Labels can begin with numbers
- It is a bad idea to define labels starting with numbers but apparently
Merlin allows it.
2016-03-01 18:34:20 -08:00
Carl-Henrik Skårstedt
462eaeccf6 Fixed bad fix (INCSYM was not properly fixed) 2016-02-15 21:11:10 -08:00
Carl-Henrik Skårstedt
0605a1d6d2 Fix for INCSYM directive when loading files with local labels 2016-02-14 12:36:01 -08:00
Carl-Henrik Skårstedt
7d59943d35 Fixed broken INCBIN and IMPORT BINARY directives 2016-02-13 16:41:33 -08:00
Carl-Henrik Skårstedt
60780a514a Pool labels of even 16ths would be re-reserved due to a left-right bug
- Shifted left when I should have shifted right.
2016-01-28 21:06:41 -08:00
Carl-Henrik Skårstedt
5b9e5f6d46 Disassembler calling graph skips fallthrough labels
- significantly cleaner calling graph in complex projects.
2016-01-14 22:08:38 -08:00
Carl-Henrik Skårstedt
1f50f07c24 STRUCT Directive fix
- Structs can contain empty lines
- Structs can be empty
- All structs have a size member named bytes, the number of bytes used
by a struct is <struct>.bytes
2016-01-04 20:55:32 -08:00
Carl-Henrik Skårstedt
e3241c66aa Disassembler swapping the order of a couple of things
- Re-evaluating code separators (jmp, rts, etc) before determining local
labels
- Re-evaluated label separator was off by one.
2015-12-18 22:41:16 -08:00
Carl-Henrik Skårstedt
794171d48b Fixed disassembler call graph function fall-through
- forgot that functions can fall through to the next label if there is
nothing separates the function from the next label
2015-12-17 23:27:16 -08:00
Carl-Henrik Skårstedt
7833ddc188 Missing character 2015-12-16 22:21:35 -08:00
Carl-Henrik Skårstedt
c4921552ba Disassembler calling graph
- graph command line option adds a calling graph to the disassembly file
- graph+bra includes branches in the calling graph
- re-evaluating separating code/data segments after the segments have
been culled.
- Added a c64kernal.lbl file that includes kernal calls
2015-12-16 22:19:25 -08:00
Carl-Henrik Skårstedt
b8362cbb0b Improving some code and data distinction rules
- If an address is unreachable it is data even if a branch crosses
- If a branch crosses data then that branch can be valid code
- If a segment is initially considered code but not reachable after all
is said and done it is reverted to data
2015-12-14 22:07:30 -08:00
Carl-Henrik Skårstedt
ec01fcc6e1 Disassembler memory access check 2015-12-14 00:27:12 -08:00
Carl-Henrik Skårstedt
5dbe08b1b3 Minor disassembler annoyances addressing
- Label ranges outside of data would be ignored for instructions
- If last code reference was a jump table then its references would get
stripped
2015-12-12 14:00:36 -08:00
Carl-Henrik Skårstedt
3b2b0f7778 Disassembler local label improvement
- Determination for negative branches to local labels were one off which
meant lots of unnecessary local labels at end of long functions
- struse null/0-length check was reverse causing access to 0
2015-12-12 13:22:23 -08:00
Carl-Henrik Skårstedt
0f740c25bd Fixes to disassembling code pointer arrays
- Removing some filters that pulled out relevant references from pointer
arrays
- Separating 6502 illegal opcodes (6502ill) and WDC specific 65C02
instructions (65C02WDC) from general disassembly
- invalid instructions will always be disassembled as dc.b $hh instead
of the non-assemblable instruction
2015-12-11 23:01:52 -08:00
Carl-Henrik Skårstedt
c96399d896 Adding read-only labels to disassembler and Atari 7800 memory map file
- Changed how the instruction lookup is stored to more easily
distinguish between read-only and other instructions
- Added Atari 7800 labels (a78.lbl)
- Added a keyword "read" to declare a read-only version of a data label
to the labels file
- Fixes to determining addresses representing data or code
- Fixed missing data blocks that were exactly 16 bytes
2015-12-10 22:27:49 -08:00
Carl-Henrik Skårstedt
214c32931a Adding pointer array to data
- Allow assign data type to pointer arrays (label = start-end pointers
data comment)
2015-12-09 23:53:43 -08:00
Carl-Henrik Skårstedt
798b657c70 Better logic for what separates code segments
- Allows jump tables without separating between each instruction
- Branch to instruction after jump instruction does not inject a
function separator
- Jump relative does not reference code
2015-12-09 18:22:07 -08:00
Carl-Henrik Skårstedt
a674f7f165 Fix user defined labels not keeping up with current address
- can skip multiple labels per instruction
2015-12-09 00:06:38 -08:00
Carl-Henrik Skårstedt
0e64a58375 Disassembler improvements
- More aggressive local labels
- Double checking code sections after detection phase
- Zero page instructions added to labels (65816 uses direct page and
will generate slightly off labels)
2015-12-07 22:26:04 -08:00
Carl-Henrik Skårstedt
acf26cf7d7 Fixing and adding to x65macro.i
- Adding shift operations to macros
- Adding README.MD to macros
2015-12-04 22:10:27 -08:00
Carl-Henrik Skårstedt
9cdfeeb0ca Disassembler improvements and c64 labels file
- Adding a labels file with all the c64 hardware addresses
- Labels are tracked outside of the binary file range
- Zero page tracking
- Improved code vs data tracking a bit
2015-12-03 22:53:16 -08:00
Carl-Henrik Skårstedt
6cbf7f8754 x65macro.i added
- Adding standard macros with for loops, memory copy, add, subtract,
move and set
- macros can be named with dots
- double negatives won't cause errors in expressions
- vice output will convert labels named "debugbreak" to vice breakpoints
rather than vice labels
- fixed issues with mixing conditional operators with math operators in
expressions
2015-12-02 22:16:31 -08:00
Carl-Henrik Skårstedt
260f48e126 Bug fixes
- struse.h replace with bookend didn't check bookends in all cases
- macros can be inside of conditionals (within if/else/endif, etc)
- string symbols mistake caused garbage code (missing braces around
assignment and return)
2015-12-01 21:21:00 -08:00
Carl-Henrik Skårstedt
72b81efc87 Local labels attempted in disassembler 2015-11-30 23:03:51 -08:00
Carl-Henrik Skårstedt
2919e0556c Disassembler label file additions
- adding ranges to labels file
- bug fixes
2015-11-29 22:24:42 -08:00
Carl-Henrik Skårstedt
6adcdc92b6 Disassembler improvements
- Added a way to instrument labels for the disassembler
- Added pointers section to disassembler, needs to be instrumented
- Fixes
2015-11-28 14:21:54 -08:00
Carl-Henrik Skårstedt
65f19b4a47 Bug fixes
- rtl instruction had wrong opcode
- disassembler works a lot better with correct rtl, even for 6502
- disassembler can specify n bytes of data before code starts in src
mode (data=initial data size)
2015-11-27 18:01:53 -08:00
Carl-Henrik Skårstedt
bdc013350c Adding imagery 2015-11-26 13:48:04 -08:00
Carl-Henrik Skårstedt
f6531d3bbc Adding one character to README.ME 2015-11-26 13:19:35 -08:00
Carl-Henrik Skårstedt
482640fb1e README.MD cleanup 2015-11-26 13:12:02 -08:00
Carl-Henrik Skårstedt
9f8ad61fe2 Adding string symbols
- String Symbols can be evaluated as expressions or assembled as code
- String Symbols can be generated by macros
- Cleaning up first page
- Adding more to the x65.txt documentation
2015-11-26 13:10:58 -08:00
Carl-Henrik Skårstedt
5459c6c0e0 More line in the documentation
- Fleshed out the sections section
- Added some notes about symbols
- Put the label pool section in
2015-11-24 23:28:56 -08:00
Carl-Henrik Skårstedt
05bdc73b86 Added doc & binaries
- Started text documentation of assembler
- Built binary zip files (Windows)
- Fix for conditional + scope characters
- Fix for empty section "default" defaulting to BSS
2015-11-23 22:34:30 -08:00
12 changed files with 497 additions and 101 deletions

2
.gitignore vendored
View File

@ -1,3 +1,4 @@
./x65.exe
*.suo
*.ipch
*.aps
@ -18,4 +19,5 @@
*.obj.enc
*.user
*.db*
*.recipe
test/results/*

View File

@ -62,8 +62,7 @@ x65.cpp requires struse.h which is a single file text parsing library that can b
### Download Binaries
* [Windows x64 binaries](../..//raw/master/bin/x65_x64.zip)
* [Windows x86 binaries](../..//raw/master/bin/x65_win32.zip)
Please note that releases have moved the Github [releases](https://github.com/Sakrac/x65/releases)
### x65
@ -102,6 +101,7 @@ Primarily tested with personal archive of sources written for Kick assmebler, DA
* irp (indefinite repeat)
**FIXED**
* Source Debug output file including linkable object files, C64Debugger format
* Adding MERGE directive, Label Pools rewrite, TEXT data can be indexed from a string symbol
* Label Pools were destroyed after each scope so they did not work in include files which defeated their purpose. Label pools are now persistent through scopes.
* Labels reserved from label pools now distinguish between global and local. Use [.!@$] as a prefix to reserve a local label from a label pool (previously always local)

Binary file not shown.

Binary file not shown.

1
build.sh Executable file
View File

@ -0,0 +1 @@
g++ x65.cpp -lm -o x65.exe

View File

@ -23,32 +23,32 @@
<ProjectGuid>{57EFF4A4-7BF2-43F0-AD62-A79092DA67D1}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>dump_x65</RootNamespace>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>

View File

@ -23,32 +23,32 @@
<ProjectGuid>{2823019A-A423-4A40-BB9C-5CE242019BD0}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>x65</RootNamespace>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>

View File

@ -590,6 +590,7 @@ public:
strref split_token_trim(char c);
strref split_token_any_trim(const strref chars);
strref split_token_track_parens(char c);
strref split_token_track_parens_quote(char c);
strref split_token_trim_track_parens(char c);
strref split_range(const strref range, strl_t pos=0);
strref split_range_trim(const strref range, strl_t pos=0);
@ -770,7 +771,7 @@ public:
int find_after_last(char a, char b) const { return get_strref().find_after_last(a, b); }
int find_after_last(char a1, char a2, char b) const { return get_strref().find_after_last(a1, a2, b); }
int find(const strref str) const { return get_strref().find(str); }
int find(const strref str, strl_t pos) const { get_strref().find(str, pos); }
int find(const strref str, strl_t pos) const { return get_strref().find(str, pos); }
int find(const char *str, strl_t pos = 0) const { return get_strref().find(str, pos); }
int find_case(const strref str) const { return get_strref().find_case(str); }
int find_case(const char *str) const { return get_strref().find_case(str); }
@ -4162,6 +4163,24 @@ strref strref::split_token_track_parens(char c)
return r;
}
strref strref::split_token_track_parens_quote(char c)
{
if (length>=2 && string[0] == '"') {
strl_t o = 1;
while (o < length && string[o] != '"') { ++o; }
if (o < length) {
strref r = strref(string, o + 1);
*this += o + 1;
return r;
}
}
int t = find_skip_parens(c);
if (t < 0) t = (int)length;
strref r = strref(string, strl_t(t));
*this += t + 1;
return r;
}
strref strref::split_token_any( const strref chars )
{
strref r; int t = find_any_char_of( chars );

8
test/merlin_data.s Normal file
View File

@ -0,0 +1,8 @@
; merlin_data.s
db $12,$34,$56,$78
ddb $1234,$5678 ; double byte - big endian format.
dw $1234
da $1234
adr $123456
adrl $12345678

500
x65.cpp
View File

@ -41,8 +41,13 @@
#include <inttypes.h>
#include <assert.h>
#ifndef _WIN32
#define _strdup strdup
#endif
// Command line arguments
static const strref cmdarg_listing("lst"); // -lst / -lst=(file.lst) : generate disassembly text from result(file or stdout)
static const strref cmdarg_srcdebug("srcdbg"); // -srcdbg : generate debug, -srcdbg=(file) : save debug file
static const strref cmdarg_tass_listing("tsl"); // -tsl=(file) : generate listing file in TASS style
static const strref cmdarg_tass_labels("tl"); // -tl=(file) : generate labels in TASS style
static const strref cmdarg_allinstr("opcodes"); // -opcodes / -opcodes=(file.s) : dump all available opcodes(file or stdout)
@ -322,6 +327,7 @@ enum AssemblerDirective {
AD_ENT, // ENT: MERLIN extern this address label
AD_EXT, // EXT: MERLIN reference this address label from a different file
AD_CYC, // CYC: MERLIN start / stop cycle timer
AD_DBL_BYTES, // DDB: MERLIN Store 2 bytes, big endian format.
AD_ERROR,
};
@ -473,7 +479,7 @@ enum AddrMode {
// 6502 illegal modes
AMM_SLO = AMM_ZP | AMM_ZP_X | AMM_ABS | AMM_ABS_Y | AMM_ABS_X | AMM_ZP_REL_X | AMM_ZP_Y_REL,
AMM_SAX = AMM_FLIPXY | AMM_ZP | AMM_ZP_X | AMM_ZP_REL_X | AMM_ABS,
AMM_AXS = AMM_FLIPXY | AMM_ZP | AMM_ZP_X | AMM_ZP_REL_X | AMM_ABS,
AMM_LAX = AMM_FLIPXY | AMM_ZP | AMM_ZP_X | AMM_ZP_REL_X | AMM_ABS | AMM_ABS_X | AMM_ZP_Y_REL,
AMM_AHX = AMM_FLIPXY | AMM_ZP_REL_X | AMM_ABS_X,
AMM_SHY = AMM_ABS_X,
@ -582,7 +588,7 @@ struct mnem opcodes_6502[] = {
{ "rla", AMM_SLO, { 0x23, 0x27, 0x00, 0x2f, 0x33, 0x37, 0x3b, 0x3f, 0x00, 0x00, 0x00 } },
{ "sre", AMM_SLO, { 0x43, 0x47, 0x00, 0x4f, 0x53, 0x57, 0x5b, 0x5f, 0x00, 0x00, 0x00 } },
{ "rra", AMM_SLO, { 0x63, 0x67, 0x00, 0x6f, 0x73, 0x77, 0x7b, 0x7f, 0x00, 0x00, 0x00 } },
{ "sax", AMM_SAX, { 0x83, 0x87, 0x00, 0x8f, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00 } },
{ "sax", AMM_IMM, { 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
{ "lax", AMM_LAX, { 0xa3, 0xa7, 0x00, 0xaf, 0xb3, 0xb7, 0x00, 0xbf, 0x00, 0x00, 0x00 } },
{ "dcp", AMM_SLO, { 0xc3, 0xc7, 0x00, 0xcf, 0xd3, 0xd7, 0xdb, 0xdf, 0x00, 0x00, 0x00 } },
{ "isc", AMM_SLO, { 0xe3, 0xe7, 0x00, 0xef, 0xf3, 0xf7, 0xfb, 0xff, 0x00, 0x00, 0x00 } },
@ -592,7 +598,7 @@ struct mnem opcodes_6502[] = {
{ "arr", AMM_IMM, { 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
{ "xaa", AMM_IMM, { 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
{"lax2", AMM_IMM, { 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
{ "axs", AMM_IMM, { 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
{ "axs", AMM_AXS, { 0x83, 0x87, 0x00, 0x8f, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00 } },
{ "sbi", AMM_IMM, { 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
{ "ahx", AMM_AHX, { 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00 } },
{ "shy", AMM_SHY, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00 } },
@ -608,14 +614,23 @@ const char* aliases_6502[] = {
};
uint8_t timing_6502[] = {
0x0e, 0x0c, 0xff, 0xff, 0xff, 0x06, 0x0a, 0xff, 0x06, 0x04, 0x04, 0xff, 0xff, 0x08, 0x0c, 0xff, 0x05, 0x0b, 0xff, 0xff, 0xff, 0x08, 0x0c, 0xff, 0x04, 0x09, 0xff, 0xff, 0xff, 0x09, 0x0e, 0xff,
0x0c, 0x0c, 0xff, 0xff, 0x06, 0x06, 0x0a, 0xff, 0x08, 0x04, 0x04, 0xff, 0x08, 0x08, 0x0c, 0xff, 0x05, 0x0b, 0xff, 0xff, 0xff, 0x08, 0x0c, 0xff, 0x04, 0x09, 0xff, 0xff, 0xff, 0x09, 0x0e, 0xff,
0x0c, 0x0c, 0xff, 0xff, 0xff, 0x06, 0x0a, 0xff, 0x06, 0x04, 0x04, 0xff, 0x06, 0x08, 0x0c, 0xff, 0x05, 0x0b, 0xff, 0xff, 0xff, 0x08, 0x0c, 0xff, 0x04, 0x09, 0xff, 0xff, 0xff, 0x09, 0x0e, 0xff,
0x0c, 0x0c, 0xff, 0xff, 0xff, 0x06, 0x0a, 0xff, 0x08, 0x04, 0x04, 0xff, 0x0a, 0x08, 0x0c, 0xff, 0x05, 0x0b, 0xff, 0xff, 0xff, 0x08, 0x0c, 0xff, 0x04, 0x09, 0xff, 0xff, 0xff, 0x09, 0x0e, 0xff,
0xff, 0x0c, 0xff, 0xff, 0x06, 0x06, 0x06, 0xff, 0x04, 0xff, 0x04, 0xff, 0x08, 0x08, 0x08, 0xff, 0x05, 0x0c, 0xff, 0xff, 0x08, 0x08, 0x08, 0xff, 0x04, 0x0a, 0x04, 0xff, 0xff, 0x0a, 0xff, 0xff,
0x04, 0x0c, 0x04, 0xff, 0x06, 0x06, 0x06, 0xff, 0x04, 0x04, 0x04, 0xff, 0x08, 0x08, 0x08, 0xff, 0x05, 0x0b, 0xff, 0xff, 0x08, 0x08, 0x08, 0xff, 0x04, 0x09, 0x04, 0xff, 0x09, 0x09, 0x09, 0xff,
0x04, 0x0c, 0xff, 0xff, 0x06, 0x06, 0x0a, 0xff, 0x04, 0x04, 0x04, 0xff, 0x08, 0x08, 0x0c, 0xff, 0x05, 0x0b, 0xff, 0xff, 0xff, 0x08, 0x0c, 0xff, 0x04, 0x09, 0xff, 0xff, 0xff, 0x09, 0x0e, 0xff,
0x04, 0x0c, 0xff, 0xff, 0x06, 0x06, 0x0a, 0xff, 0x04, 0x04, 0x04, 0xff, 0x08, 0x08, 0x0c, 0xff, 0x05, 0x0b, 0xff, 0xff, 0xff, 0x08, 0x0c, 0xff, 0x04, 0x09, 0xff, 0xff, 0xff, 0x09, 0x0e, 0xff
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x0e, 0x0c, 0xff, 0x0f, 0xff, 0x06, 0x0a, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x04, 0x08, 0x0c, 0x0c, // 0
0x05, 0x0b, 0xff, 0x0f, 0xff, 0x08, 0x0c, 0x0c, 0x04, 0x09, 0x02, 0x0e, 0x04, 0x09, 0x0e, 0x0f, // 1
0x0c, 0x0c, 0xff, 0x0f, 0x06, 0x06, 0x0a, 0x0a, 0x08, 0x04, 0x04, 0x04, 0x08, 0x08, 0x0c, 0x0c, // 2
0x05, 0x0b, 0xff, 0x0f, 0xff, 0x08, 0x0c, 0x0c, 0x04, 0x09, 0x02, 0x0e, 0x04, 0x09, 0x0e, 0x0f, // 3
0x0c, 0x0c, 0xff, 0x0f, 0xff, 0x06, 0x0a, 0x0a, 0x06, 0x04, 0x04, 0x04, 0x06, 0x08, 0x0c, 0x0c, // 4
0x05, 0x0b, 0xff, 0x0f, 0xff, 0x08, 0x0c, 0x0c, 0x04, 0x09, 0x02, 0xff, 0x04, 0x09, 0x0e, 0x0f, // 5
0x0c, 0x0c, 0xff, 0x0f, 0xff, 0x06, 0x0a, 0x0a, 0x08, 0x04, 0x04, 0x04, 0x0a, 0x08, 0x0c, 0x0c, // 6
0x05, 0x0b, 0xff, 0x0f, 0xff, 0x08, 0x0c, 0x0c, 0x04, 0x09, 0x02, 0x0e, 0x04, 0x09, 0x0e, 0x0f, // 7
0xff, 0x0c, 0xff, 0x0c, 0x06, 0x06, 0x06, 0x06, 0x04, 0xff, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, // 8
0x05, 0x0c, 0xff, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x04, 0x0a, 0x04, 0x0a, 0x05, 0x0a, 0x05, 0x0a, // 9
0x04, 0x0c, 0x04, 0x0c, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, // A
0x05, 0x0b, 0xff, 0x0a, 0x08, 0x08, 0x08, 0x08, 0x04, 0x09, 0x04, 0x09, 0x09, 0x09, 0x09, 0x0a, // B
0x04, 0x0c, 0xff, 0x0f, 0x06, 0x06, 0x0a, 0x0a, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x0c, 0x0c, // C
0x05, 0x0b, 0xff, 0x0f, 0xff, 0x08, 0x0c, 0x0c, 0x04, 0x09, 0x02, 0x0e, 0x04, 0x09, 0x0e, 0x0e, // D
0x04, 0x0c, 0xff, 0xff, 0x06, 0x06, 0x0a, 0x0a, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x0c, 0x0c, // E
0x05, 0x0b, 0xff, 0xff, 0xff, 0x08, 0x0c, 0x0c, 0x04, 0x09, 0x02, 0x0e, 0x04, 0x09, 0x0e, 0x0e // F
};
static const int num_opcodes_6502 = sizeof(opcodes_6502) / sizeof(opcodes_6502[0]);
@ -1057,7 +1072,7 @@ DirectiveName aDirectiveNamesMerlin[] {
{ "DW", AD_WORDS }, // MERLIN
{ "ASC", AD_TEXT }, // MERLIN
{ "PUT", AD_INCLUDE }, // MERLIN
{ "DDB", AD_WORDS }, // MERLIN
{ "DDB", AD_DBL_BYTES }, // MERLIN
{ "DB", AD_BYTES }, // MERLIN
{ "DFB", AD_BYTES }, // MERLIN
{ "HEX", AD_HEX }, // MERLIN
@ -1128,6 +1143,13 @@ uint32_t FindLabelIndex(uint32_t hash, uint32_t *table, uint32_t count)
return count;
}
char* StringCopy(strref str)
{
char* buf = (char*)calloc(1, (size_t)str.get_len() + 1);
if (buf && str.get_len()) { memcpy(buf, str.get(), str.get_len()); }
return buf;
}
//
@ -1216,7 +1238,7 @@ template< class KeyType, class ValueType, class CountType = size_t > struct Hash
KeyType* keys;
ValueType* values;
static CountType HashFunction(KeyType v) { return CountType(((v + (v >> 27) + (v << 29)) + 14695981039346656037) * 1099511628211); }
static CountType HashFunction(KeyType v) { return CountType(((v + (v >> 27) + (v << 29)) + 14695981039346656037UL) * 1099511628211UL); }
static CountType HashIndex(KeyType hash, CountType tableSize) { return hash & (tableSize - 1); }
static CountType GetNextIndex(KeyType hash, CountType tableSize) { return (hash + 1) & (tableSize - 1); }
static CountType KeyToIndex(KeyType key, CountType tableSize) { return HashIndex(HashFunction(key), tableSize); }
@ -1406,6 +1428,7 @@ struct ListLine {
};
strref source_name; // source file index name
strref code; // line of code this represents
int column; // column of line
int address; // start address of this line
int size; // number of bytes generated for this line
int line_offs; // offset into code
@ -1422,10 +1445,17 @@ typedef std::vector<struct ListLine> Listing;
struct SourceDebugEntry {
int source_file_index; // index into Assembler::source_file vector
int address; // local address in section
int size;
int source_file_offset; // can be converted into line/column while linking
int size:24;
int type : 8;
};
typedef std::vector<struct SLDEntry> SourceDebug;
enum class SourceDebugType {
Code,
Label,
Breakpoint
};
typedef std::vector<struct SourceDebugEntry> SourceDebug;
enum SectionType : int8_t { // enum order indicates fixed address linking priority
@ -1507,6 +1537,8 @@ typedef struct Section {
pRelocs = nullptr;
if (pListing) delete pListing;
pListing = nullptr;
if (pSrcDbg) delete pSrcDbg;
pSrcDbg = nullptr;
}
void Cleanup() { if (output) free(output); reset(); }
@ -1530,11 +1562,11 @@ typedef struct Section {
void AddReloc(int base, int offset, int section, int8_t bytes, int8_t shift);
Section() : pRelocs(nullptr), pListing(nullptr) { reset(); }
Section(strref _name, int _address) : pRelocs(nullptr), pListing(nullptr) {
Section(strref _name, int _address) : pRelocs(nullptr), pListing(nullptr), pSrcDbg(nullptr) {
reset(); name = _name; start_address = load_address = address = _address;
address_assigned = true;
}
Section(strref _name) : pRelocs(nullptr), pListing(nullptr) {
Section(strref _name) : pRelocs(nullptr), pListing(nullptr), pSrcDbg(nullptr) {
reset(); name = _name;
start_address = load_address = address = 0; address_assigned = false;
}
@ -1559,6 +1591,7 @@ struct MapSymbol {
strref name; // string name
int value;
int16_t section;
int16_t orig_section;
bool local; // local variables
};
typedef std::vector<struct MapSymbol> MapSymbolArray;
@ -1570,6 +1603,7 @@ public:
strref pool_name; // name of the pool that this label is related to
int value;
int section; // rel section address labels belong to a section, -1 if fixed address or assigned
int orig_section; // original section where the label was defined
int mapIndex; // index into map symbols in case of late resolve
bool evaluated; // a value may not yet be evaluated
bool pc_relative; // this is an inline label describing a point in the code
@ -1591,6 +1625,7 @@ typedef struct sLateEval {
LET_BRANCH, // calculate a branch offset and store at this address
LET_BRANCH_16, // calculate a branch offset of 16 bits and store at this address
LET_BYTE, // calculate a byte and store at this address
LET_DBL_BYTE, // calculate a 16-bit, big endian number.
};
int target; // offset into output buffer
int address; // current pc
@ -1812,6 +1847,7 @@ public:
int8_t cycle_counter_level; // merlin toggles the cycle counter rather than hierarchically evals
bool error_encountered; // if any error encountered, don't export binary
bool list_assembly; // generate assembler listing
bool src_debug; // generate source debug info
bool end_macro_directive; // whether to use { } or macro / endmacro for macro scope
bool import_means_xref;
@ -1828,6 +1864,9 @@ public:
// Mimic TASS listing
bool ListTassStyle( strref filename );
// Export C64Debugger dbg xml file
bool SourceDebugExport(strref filename);
// Generate source for all valid instructions and addressing modes for current CPU
bool AllOpcodes(strref filename);
@ -1920,6 +1959,9 @@ public:
void MarkLabelLocal(strref label, bool scope_label = false);
StatusCode FlushLocalLabels(int scope_exit = -1);
// Source debug
void AddSrcDbg(int address, SourceDebugType type, const char* text);
// Label pools
LabelPool* GetLabelPool(strref pool_name);
StatusCode AddLabelPool(strref name, strref args);
@ -1948,7 +1990,7 @@ public:
StatusCode Directive_LNK(strref line);
StatusCode Directive_XDEF(strref line);
StatusCode Directive_XREF(strref label);
StatusCode Directive_DC(strref line, int width, strref source_file);
StatusCode Directive_DC(strref line, int width, strref source_file, bool little_endian = true);
StatusCode Directive_DS(strref line);
StatusCode Directive_ALIGN(strref line);
StatusCode Directive_EVAL(strref line);
@ -1994,7 +2036,7 @@ public:
// constructor
Asm() : opcode_table(opcodes_6502), opcode_count(num_opcodes_6502), num_instructions(0),
cpu(CPU_6502), list_cpu(CPU_6502) {
cpu(CPU_6502), list_cpu(CPU_6502), lastEvalSection(-1) {
Cleanup(); localLabels.reserve(256); loadedData.reserve(16); lateEval.reserve(64); }
};
@ -2027,9 +2069,7 @@ void SymbolStackTable::PushSymbol(StringSymbol* string)
ValueOrString val;
val.string = nullptr;
if (string->string_value) {
val.string = (char*)malloc(string->string_value.get_len() + 1);
memcpy(val.string, string->string_value.get(), string->string_value.get_len());
val.string[string->string_value.get_len()] = 0;
val.string = StringCopy(string->string_value.get_strref());
}
(*ppStack)->push_back(val);
}
@ -2136,8 +2176,12 @@ void Asm::Cleanup() {
free(str.string_value.charstr());
}
strings.clear();
for (std::vector<ExtLabels>::iterator exti = externals.begin(); exti !=externals.end(); ++exti)
for (std::vector<ExtLabels>::iterator exti = externals.begin(); exti != externals.end(); ++exti) {
exti->labels.clear();
}
for (std::vector<char*>::iterator src = source_files.begin(); src != source_files.end(); ++src) {
free(*src);
}
externals.clear();
// this section is relocatable but is assigned address $1000 if exporting without directives
SetSection(strref("default,code"));
@ -2152,6 +2196,7 @@ void Asm::Cleanup() {
directive_scope_depth = 0;
error_encountered = false;
list_assembly = false;
src_debug = false;
end_macro_directive = false;
import_means_xref = false;
accumulator_16bit = false; // default 65816 8 bit immediate mode
@ -2481,7 +2526,7 @@ uint8_t* Asm::BuildExport(strref append, int &file_size, int &addr) {
(!i->include_from && allSections[first_link_section].include_from)))))
first_link_section = SectionId(*i);
has_relative_section = true;
} else if (i->start_address >= 0x100 && ( i->size() > 0 || i->addr_size() > 0 ) ) {
} else if (i->size() > 0 || i->addr_size() > 0) {
has_fixed_section = true;
bool inserted = false;
for (std::vector<Section*>::iterator f = FixedExport.begin(); f != FixedExport.end(); ++f) {
@ -2865,7 +2910,9 @@ StatusCode Asm::MergeSections(int section_id, int section_merge) {
}
}
}
if(!s.IsRelativeSection()) { LinkLabelsToAddress(section_merge, -1, m.start_address); }
if(!s.IsRelativeSection()) {
LinkLabelsToAddress(section_merge, -1, s.start_address);
}
// go through all labels referencing merging section
for (uint32_t i = 0; i<labels.count(); i++) {
@ -2914,6 +2961,20 @@ StatusCode Asm::MergeSections(int section_id, int section_merge) {
delete m.pListing;
m.pListing = nullptr;
}
// go through source debug
if (m.pSrcDbg) {
if (!s.pSrcDbg) { s.pSrcDbg = new SourceDebug; }
if (s.pSrcDbg->capacity() < (m.pSrcDbg->size() + s.pSrcDbg->size())) {
s.pSrcDbg->reserve((m.pSrcDbg->size() + s.pSrcDbg->size()));
}
for (SourceDebug::iterator i = m.pSrcDbg->begin(); i != m.pSrcDbg->end(); ++i) {
SourceDebugEntry l = *i;
l.address += addr_start;
s.pSrcDbg->push_back(l);
}
delete m.pSrcDbg;
m.pSrcDbg = nullptr;
}
m.type = ST_REMOVED;
return STATUS_OK;
}
@ -3067,6 +3128,16 @@ void Section::AddText(strref line, strref text_prefix) {
if (CheckOutputCapacity((uint32_t)line.get_len()) == STATUS_OK) {
if (!text_prefix || text_prefix.same_str("ascii")) {
AddBin((const uint8_t*)line.get(), (int)line.get_len());
} else if (text_prefix.same_str("c64screen")) {
while (line) {
char c = line.get_first(), o = c;
if (c >= 'a' && c <= 'z') { o = c - 'a' + 1; }
else if (c == '@') { o = 0; }
else if (c == '[') { o = 27; }
else if (c == ']') { o = 29; }
AddByte(o >= 0x60 ? ' ' : o);
++line;
}
} else if (text_prefix.same_str("petscii")) {
while (line) {
char c = line[0];
@ -3350,8 +3421,8 @@ StatusCode Asm::BuildMacro(Macro &m, strref arg_list) {
strref pchk = params;
strref arg = arg_list;
int dSize = 0;
char token = arg_list.find(',')>=0 ? ',' : ' ';
char token_macro = m.params_first_line && params.find(',') < 0 ? ' ' : ',';
char token = ',';// arg_list.find(',') >= 0 ? ',' : ' ';
char token_macro = ',';// m.params_first_line&& params.find(',') < 0 ? ' ' : ',';
while (strref param = pchk.split_token_trim(token_macro)) {
strref a = arg.split_token_trim(token);
if (param.get_len() < a.get_len()) {
@ -3365,7 +3436,7 @@ StatusCode Asm::BuildMacro(Macro &m, strref arg_list) {
strovl macexp(buffer, mac_size);
macexp.copy(macro_src);
while (strref param = params.split_token_trim(token_macro)) {
strref a = arg_list.split_token_trim(token);
strref a = arg_list.split_token_track_parens_quote(token);
macexp.replace_bookend(param, a, macro_arg_bookend);
}
PushContext(m.source_name, macexp.get_strref(), macexp.get_strref());
@ -4257,6 +4328,23 @@ StatusCode Asm::CheckLateEval(strref added_label, int scope_end, bool print_miss
allSections[sec].SetByte(trg, value);
break;
case LateEval::LET_DBL_BYTE:
if (ret==STATUS_RELATIVE_SECTION) {
if (i->section<0) {
resolved = false;
} else {
allSections[sec].AddReloc(lastEvalValue, trg, lastEvalSection, 1, lastEvalShift-8);
allSections[sec].AddReloc(lastEvalValue, trg+1, lastEvalSection, 1, lastEvalShift);
value = 0;
}
}
if ((trg+1)>=allSections[sec].size()) {
return ERROR_SECTION_TARGET_OFFSET_OUT_OF_RANGE;
}
allSections[sec].SetByte(trg, value>>8);
allSections[sec].SetByte(trg+1, value);
break;
case LateEval::LET_ABS_REF:
if (ret==STATUS_RELATIVE_SECTION) {
if (i->section<0) {
@ -4327,6 +4415,7 @@ StatusCode Asm::CheckLateEval(strref added_label, int scope_end, bool print_miss
label->value = value;
label->evaluated = true;
label->section = ret == STATUS_RELATIVE_SECTION ? i->section : -1;
label->orig_section = i->section;
if (num_new_labels<MAX_LABELS_EVAL_ALL) {
new_labels[num_new_labels++] = label->label_name;
}
@ -4401,7 +4490,8 @@ void Asm::LabelAdded(Label *pLabel, bool local) {
}
MapSymbol sym;
sym.name = pLabel->label_name;
sym.section = (int16_t)(pLabel->section);
sym.section = (int16_t)pLabel->section;
sym.orig_section = (int16_t)pLabel->orig_section;
sym.value = pLabel->value;
sym.local = local;
pLabel->mapIndex = pLabel->evaluated ? -1 : (int)map.size();
@ -4574,6 +4664,7 @@ StatusCode Asm::AssignPoolLabel(LabelPool &pool, strref label) {
pLabel->pool_name = pool.pool_name;
pLabel->evaluated = true;
pLabel->section = -1; // pool labels are section-less
pLabel->orig_section = SectionId();
pLabel->value = addr;
pLabel->pc_relative = true;
pLabel->constant = true;
@ -4582,6 +4673,7 @@ StatusCode Asm::AssignPoolLabel(LabelPool &pool, strref label) {
pLabel->referenced = false;
bool local = false;
if (label[ 0 ] == '.' || label[ 0 ] == '@' || label[ 0 ] == '!' || label[ 0 ] == ':' || label.get_last() == '$') {
local = true;
MarkLabelLocal( label, true );
@ -4642,6 +4734,7 @@ StatusCode Asm::AssignLabel(strref label, strref expression, bool make_constant)
pLabel->pool_name.clear();
pLabel->evaluated = status==STATUS_OK || status == STATUS_RELATIVE_SECTION;
pLabel->section = status == STATUS_RELATIVE_SECTION ? lastEvalSection : -1; // assigned labels are section-less
pLabel->orig_section = lastEvalSection;
pLabel->value = val;
pLabel->mapIndex = -1;
pLabel->pc_relative = false;
@ -4676,12 +4769,15 @@ StatusCode Asm::AddressLabel(strref label)
pLabel->label_name = label;
pLabel->pool_name.clear();
pLabel->section = CurrSection().IsRelativeSection() ? SectionId() : -1; // address labels are based on section
pLabel->orig_section = SectionId();
pLabel->value = CurrSection().GetPC();
pLabel->evaluated = true;
pLabel->pc_relative = true;
pLabel->external = MatchXDEF(label);
pLabel->reference = false;
pLabel->constant = constLabel;
// Label Source Debug Origin: AddSrcDbg((int)CurrSection().GetPC(), SourceDebugType::Label, label.get());
last_label = label;
bool local = label[0]=='.' || label[0]=='@' || label[0]=='!' || label[0]==':' || label.get_last()=='$';
if (directive_scope_depth > 0) { local = true; }
@ -5388,7 +5484,7 @@ StatusCode Asm::Directive_XREF(strref label)
}
// dc.b, dc.w, dc.t, dc.l, ADR, ADRL, bytes, words, long
StatusCode Asm::Directive_DC(strref line, int width, strref source_file)
StatusCode Asm::Directive_DC(strref line, int width, strref source_file, bool little_endian)
{
struct EvalContext etx;
SetEvalCtxDefaults(etx);
@ -5401,18 +5497,43 @@ StatusCode Asm::Directive_DC(strref line, int width, strref source_file)
StatusCode error = EvalExpression(exp_dc, etx, value);
if (error > STATUS_XREF_DEPENDENT)
break;
else if (error == STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT)
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], exp_dc, source_file,
width == 1 ? LateEval::LET_BYTE : (width == 2 ? LateEval::LET_ABS_REF : (width == 3 ? LateEval::LET_ABS_L_REF : LateEval::LET_ABS_4_REF)));
else if (error == STATUS_RELATIVE_SECTION) {
else if (error == STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT) {
static LateEval::Type sizes[] = {
LateEval::LET_BYTE,
LateEval::LET_ABS_REF,
LateEval::LET_ABS_L_REF,
LateEval::LET_ABS_4_REF
};
LateEval::Type type = sizes[width - 1];
if (!little_endian && width == 2) {
type = LateEval::LET_DBL_BYTE;
}
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], exp_dc, source_file, type);
} else if (error == STATUS_RELATIVE_SECTION) {
value = 0;
if (little_endian || width == 1) {
CurrSection().AddReloc(lastEvalValue, CurrSection().DataOffset(), lastEvalSection, (int8_t)width, (int8_t)lastEvalShift);
} else {
// big endian needs 1 reloc for each byte
int shift = lastEvalShift + 8 - width * 8;
for (int i = 0; i < width; ++i, shift += 8) {
CurrSection().AddReloc(lastEvalValue, CurrSection().DataOffset() + i, lastEvalSection, 1, (int8_t)shift);
}
}
}
}
if (little_endian) {
uint8_t bytes[4] = {
(uint8_t)value, (uint8_t)(value >> 8),
(uint8_t)(value >> 16), (uint8_t)(value >> 24) };
AddBin(bytes, width);
} else {
uint8_t bytes[4] = {
(uint8_t)(value >> 24), (uint8_t)(value >> 16),
(uint8_t)(value >> 8), (uint8_t)value };
AddBin(bytes + 4 - width, width);
}
}
return STATUS_OK;
}
@ -5655,6 +5776,9 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
case AD_WORDS: // words: add words (16 bit values) by comma separated values
return Directive_DC(line, 2, source_file);
case AD_DBL_BYTES: // DDB: Merlin store 2-byte word, big endian format.
return Directive_DC(line, 2, source_file, false);
case AD_ADR: // ADR: MERLIN store 3 byte word
return Directive_DC(line, 3, source_file);
@ -5727,7 +5851,8 @@ StatusCode Asm::ApplyDirective(AssemblerDirective dir, strref line, strref sourc
}
while (line[0] != '"') {
strref word = line.get_word_ws();
if (word.same_str("petscii") || word.same_str("petscii_shifted")) {
if (word.same_str("petscii") || word.same_str("petscii_shifted") ||
word.same_str("c64screen")) {
text_prefix = line.get_word_ws();
line += text_prefix.get_len();
line.skip_whitespace();
@ -6022,7 +6147,7 @@ StatusCode Asm::GetAddressMode(strref line, bool flipXY, uint32_t &validModes, A
validModes &= AMM_ZP_REL_X | AMM_ZP_Y_REL | AMM_REL | AMM_ZP_REL | AMM_REL_X | AMM_ZP_REL_L | AMM_ZP_REL_Y_L | AMM_STK_REL_Y | AMM_REL_L;
if( line.get_first() == '>' ) { // [>$aaaa]
if( c == '[' ) { addrMode = AMB_REL_L; validModes &= AMM_REL_L; expression = block+1; }
} else if( line.get_first() == '|' || line.get_first() == '!' && c == '(' ) { // (|$aaaa) or (|$aaaa,x)
} else if( line.get_first() == '|' || (line.get_first() == '!' && c == '(' )) { // (|$aaaa) or (|$aaaa,x)
strref arg = block.after( ',' ); arg.skip_whitespace();
if( arg && ( arg.get_first() == 'x' || arg.get_first() == 'X' ) ) {
addrMode = AMB_REL_X; validModes &= AMM_REL_X; expression = block.before( ',' ); }
@ -6387,22 +6512,32 @@ StatusCode Asm::AddOpcode(strref line, int index, strref source_file) {
break;
case CA_TWO_ARG_BYTES: {
// second operand stored first.
StatusCode error = STATUS_OK;
int value = 0;
struct EvalContext etx;
SetEvalCtxDefaults(etx);
etx.pc = CurrSection().GetPC()-1;
line.split_token_trim_track_parens(',');
error = EvalExpression(line, etx, value);
if (error==STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT)
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC()-1, scope_address[scope_depth], line, source_file, LateEval::LET_BYTE);
else if (error == STATUS_RELATIVE_SECTION) {
CurrSection().AddReloc(target_section_offs, CurrSection().DataOffset(), lastEvalSection, 1, lastEvalShift);
}
AddByte(value);
}
if (evalLater)
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], expression, source_file, LateEval::LET_BYTE);
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC()-2, scope_address[scope_depth], expression, source_file, LateEval::LET_BYTE);
else if (error == STATUS_RELATIVE_SECTION) {
CurrSection().AddReloc(target_section_offs, CurrSection().DataOffset(), target_section, 1, target_section_shift);
}
AddByte(value);
struct EvalContext etx;
SetEvalCtxDefaults(etx);
etx.pc = CurrSection().GetPC()-2;
line.split_token_trim_track_parens(',');
error = EvalExpression(line, etx, value);
if (error==STATUS_NOT_READY || error == STATUS_XREF_DEPENDENT)
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], line, source_file, LateEval::LET_BYTE);
AddByte(value);
break;
}
case CA_BRANCH:
if (evalLater)
AddLateEval(CurrSection().DataOffset(), CurrSection().GetPC(), scope_address[scope_depth], expression, source_file, LateEval::LET_BRANCH);
@ -6471,6 +6606,7 @@ StatusCode Asm::BuildLine(strref line) {
int start_section = SectionId();
int start_address = CurrSection().address;
strref code_line = line;
const char* data_line = line.get(); // code_line is current line, data_line is where data is generated
list_flags = 0;
while (line && error == STATUS_OK) {
@ -6539,9 +6675,11 @@ StatusCode Asm::BuildLine(strref line) {
line.skip_whitespace();
}
if (aInstructions[op_idx].type==OT_DIRECTIVE) {
data_line = operation.get();
error = ApplyDirective((AssemblerDirective)aInstructions[op_idx].index, line, contextStack.curr().source_file);
list_flags |= ListLine::KEYWORD;
} else if (ConditionalAsm() && aInstructions[op_idx].type == OT_MNEMONIC) {
data_line = operation.get();
error = AddOpcode(line, aInstructions[op_idx].index, contextStack.curr().source_file);
list_flags |= ListLine::MNEMONIC;
}
@ -6631,29 +6769,57 @@ StatusCode Asm::BuildLine(strref line) {
}
}
// update listing
if (error == STATUS_OK && list_assembly) {
if (error == STATUS_OK) {
if (SectionId() == start_section) {
Section &curr = CurrSection();
if (list_assembly) {
if (!curr.pListing) { curr.pListing = new Listing; }
if (curr.pListing && curr.pListing->size()==curr.pListing->capacity()) {
curr.pListing->reserve(curr.pListing->size()+256);
}
if (((list_flags & (ListLine::KEYWORD | ListLine::CYCLES_START | ListLine::CYCLES_STOP)) ||
(curr.address != start_address && curr.size())) && !curr.IsDummySection()) {
struct ListLine lst;
lst.address = start_address - curr.start_address;
lst.size = curr.address - start_address;
lst.code = contextStack.curr().source_file;
lst.column = (uint16_t)(data_line - code_line.get());
lst.source_name = contextStack.curr().source_name;
lst.line_offs = int(code_line.get() - lst.code.get());
lst.flags = list_flags;
curr.pListing->push_back(lst);
}
}
if (src_debug) {
if (curr.address != start_address && curr.size()) {
AddSrcDbg(start_address, SourceDebugType::Code, data_line);
}
}
}
}
return error;
}
void Asm::AddSrcDbg(int address, SourceDebugType type, const char* text)
{
SourceDebugEntry entry;
Section& curr = CurrSection();
if (!curr.pSrcDbg) { curr.pSrcDbg = new SourceDebug; }
entry.address = address - curr.start_address;
entry.size = curr.address - address;
entry.type = (int)type;
size_t sf = 0, nsf = source_files.size();
strref src = contextStack.curr().source_name;
for (; sf < nsf; ++sf) {
if (src.same_str_case(source_files[sf])) { break; }
}
if (sf == nsf) {
source_files.push_back(StringCopy(src));
}
entry.source_file_index = (int)sf;
entry.source_file_offset = (int)(text - contextStack.curr().source_file.get());
curr.pSrcDbg->push_back(entry);
}
// Build a segment of code (file or macro)
StatusCode Asm::BuildSegment() {
StatusCode error = STATUS_OK;
@ -6783,7 +6949,7 @@ bool Asm::ListTassStyle( strref filename ) {
} else if (am==AMB_ABS_L||am==AMB_ABS_L_X) {
out.sprintf_append(fmt, opcode_table[op].instr, buf[1]|(buf[2]<<8)|(buf[3]<<16));
} else if (am==AMB_BLK_MOV) {
out.sprintf_append(fmt, opcode_table[op].instr, buf[1], buf[2]);
out.sprintf_append(fmt, opcode_table[op].instr, buf[2], buf[1]);
} else if (am==AMB_IMM && lst.size==3) {
out.sprintf_append("%s #$%04x", opcode_table[op].instr, buf[1]|(buf[2]<<8));
} else {
@ -6811,6 +6977,100 @@ bool Asm::ListTassStyle( strref filename ) {
return true;
}
bool Asm::SourceDebugExport(strref filename) {
FILE* f = stdout;
bool opened = false;
if (filename) {
f = fopen(strown<512>(filename).c_str(), "w");
if (!f) { return false; }
opened = true;
} else {
return false;
}
std::vector<strovl> source_code; source_code.reserve(source_files.size());
fprintf(f, "<C64debugger version=\"1.0\">\n\t<Sources values=\"INDEX,FILE\">\n");
for (size_t i = 0, n = source_files.size(); i < n; ++i) {
fprintf(f, "\t\t%d,%s\n", (int)i+1, source_files[i]);
size_t size = 0;
char* src = LoadText(source_files[i], size);
source_code.push_back(strovl(src, (strl_t)size, (strl_t)size));
}
fprintf(f, "\t</Sources>\n\n");
for (size_t i = 0, n = allSections.size(); i < n; ++i) {
Section& s = allSections[i];
if (s.pSrcDbg && s.pSrcDbg->size()) {
fprintf(f, "\t<Segment name=\"" STRREF_FMT "\" dest=\"\" values=\"START,END,FILE_IDX,LINE1,COL1,LINE2,COL2\">\n\t\t<Block name=\"Unnamed\">\n",
STRREF_ARG(s.name));
for (size_t d = 0, nd = s.pSrcDbg->size(); d < nd; ++d) {
SourceDebugEntry& e = s.pSrcDbg->at(d);
int line = 0, col0 = 0, col1 = 0;
if ((e.source_file_index) < source_code.size()) {
strref src = source_code[e.source_file_index].get_strref();
if (src.get_len() > strl_t(e.source_file_offset)) {
line = strref(src.get(), e.source_file_offset).count_lines();
strl_t offs = e.source_file_offset;
while (src.get_at(offs) != 0x0a && src.get_at(offs) != 0x0d && offs) { --offs; ++col0; }
col1 = col0;
offs = e.source_file_offset;
while (src.get_at(offs) != 0x0a && src.get_at(offs) != 0x0d && offs<src.get_len()) { ++offs; ++col1; }
}
}
fprintf(f, "\t\t\t$%04x,$%04x,%d,%d,%d,%d,%d\n",
e.address+s.start_address, e.address+e.size+s.start_address-1, e.source_file_index+1,
line+1, col0 ? (col0-1) : 0, line+1, col1 );
}
fprintf(f, "\t\t</Block>\n\t</Segment>\n\n");
}
}
fprintf(f, "\t<Labels values=\"SEGMENT,ADDRESS,NAME,START,END,FILE_IDX,LINE1,COL1,LINE2,COL2\">\n");
for (MapSymbolArray::iterator i = map.begin(); i != map.end(); ++i) {
if (i->name.same_str("debugbreak")) { continue; }
uint32_t value = (uint32_t)i->value;
strref sectName;
int16_t section = i->section;
int16_t orig_section = i->orig_section;
if (size_t(section) < allSections.size()) {
value += allSections[section].start_address;
}
if (size_t(orig_section) < allSections.size()) {
sectName = allSections[orig_section].name;
}
fprintf(f, "\t\t" STRREF_FMT ",$%04x," STRREF_FMT ",0,0,0,0,0\n", STRREF_ARG(sectName), value, STRREF_ARG(i->name));
}
fprintf(f, "\t</Labels>\n\n");
fprintf(f, "\t<Breakpoints values=\"SEGMENT,ADDRESS,ARGUMENT\">\n");
for (MapSymbolArray::iterator i = map.begin(); i != map.end(); ++i) {
if (i->name.same_str("debugbreak")) {
uint32_t value = (uint32_t)i->value;
strref sectName;
uint16_t section = i->section;
if (size_t(section) < allSections.size()) {
value += allSections[section].start_address;
sectName = allSections[section].name;
}
fprintf(f, "\t\t" STRREF_FMT ",$%04x,\n", STRREF_ARG(sectName), value);
}
}
fprintf(f, "\t</Breakpoints>\n\n");
fprintf(f, "\t<Watchpoints values=\"SEGMENT,ADDRESS1,ADDRESS2,ARGUMENT\">\n");
fprintf(f, "\t</Watchpoints>\n\n");
fprintf(f, "</C64debugger>\n");
fclose(f);
for (size_t i = 0, n = source_code.size(); i < n; ++i) {
if (source_code[i].get()) { free(source_code[i].charstr()); }
}
return true;
}
bool Asm::List(strref filename) {
FILE *f = stdout;
bool opened = false;
@ -6980,7 +7240,7 @@ bool Asm::List(strref filename) {
} else if (am==AMB_ABS_L||am==AMB_ABS_L_X) {
out.sprintf_append(fmt, opcode_table[op].instr, buf[1]|(buf[2]<<8)|(buf[3]<<16));
} else if (am==AMB_BLK_MOV) {
out.sprintf_append(fmt, opcode_table[op].instr, buf[1], buf[2]);
out.sprintf_append(fmt, opcode_table[op].instr, buf[2], buf[1]);
} else if (am==AMB_IMM && lst.size==3) {
out.sprintf_append("%s #$%04x", opcode_table[op].instr, buf[1]|(buf[2]<<8));
} else {
@ -7109,7 +7369,7 @@ void Asm::Assemble(strref source, strref filename, bool obj_target) {
}
}
} else {
PrintError(&contextStack.curr() ?
PrintError(contextStack.has_work() ?
contextStack.curr().read_source.get_line() : strref(), error);
}
}
@ -7128,6 +7388,7 @@ struct ObjFileHeader {
int16_t late_evals;
int16_t map_symbols;
uint32_t stringdata;
uint32_t srcdebug;
int bindata;
};
@ -7147,6 +7408,7 @@ struct ObjFileSection {
int end_address; // address size
int output_size; // assembled binary size
int align_address;
int srcdebug_count; // how many addresses included in debugger listing
int16_t next_group; // next section of group
int16_t first_group; // first section of group
int16_t relocs;
@ -7154,6 +7416,10 @@ struct ObjFileSection {
int8_t flags;
};
struct ObjFileSource {
struct ObjFileStr file;
};
struct ObjFileReloc {
int base_value;
int section_offset;
@ -7190,10 +7456,27 @@ struct ObjFileLateEval {
struct ObjFileMapSymbol {
struct ObjFileStr name; // symbol name
int value;
int16_t section;
int16_t section; // address relative to this section
int16_t orig_section; // seciton label originated from
bool local; // local labels are probably needed
};
// this struct is follwed by numSources x ObjFileStr
struct ObjFileSourceList {
uint32_t numSources;
ObjFileStr sourceFile[1];
};
// after that one long array of all sections worth of source references
struct ObjFileSrcDbg {
uint16_t addr; // relative to section
uint16_t src_idx;
uint16_t size;
uint16_t _pad;
uint32_t file_offs; // byte offset into file to row/column where op starts1
};
// Simple string pool, converts strref strings to zero terminated strings and returns the offset to the string in the pool.
static int _AddStrPool(const strref str, pairArray<uint32_t, int> *pLookup, char **strPool, uint32_t &strPoolSize, uint32_t &strPoolCap) {
if (!str.get()||!str.get_len()) { return -1; } // empty string
@ -7263,6 +7546,7 @@ StatusCode Asm::WriteObjectFile(strref filename) {
hdr.late_evals = (int16_t)lateEval.size();
hdr.map_symbols = (int16_t)map.size();
hdr.stringdata = 0;
hdr.srcdebug = 0;
// labels don't include XREF labels
hdr.labels = 0;
@ -7283,7 +7567,7 @@ StatusCode Asm::WriteObjectFile(strref filename) {
char *stringPool = nullptr;
uint32_t stringPoolCap = 0;
pairArray<uint32_t, int> stringArray;
stringArray.reserve(hdr.labels * 2 + hdr.sections + hdr.late_evals*2);
stringArray.reserve(hdr.labels * 2 + hdr.sections + hdr.late_evals*2 + (uint32_t)source_files.size());
struct ObjFileSection *aSects = hdr.sections ? (struct ObjFileSection*)calloc(hdr.sections, sizeof(struct ObjFileSection)) : nullptr;
struct ObjFileReloc *aRelocs = hdr.relocs ? (struct ObjFileReloc*)calloc(hdr.relocs, sizeof(struct ObjFileReloc)) : nullptr;
@ -7301,11 +7585,11 @@ StatusCode Asm::WriteObjectFile(strref filename) {
}
sect = 0;
uint32_t srcDbgEntries = 0;
// write out sections and relocs
if (hdr.sections) {
for (std::vector<Section>::iterator si = allSections.begin(); si!=allSections.end(); ++si) {
if (si->type == ST_REMOVED)
continue;
if (si->type == ST_REMOVED) { continue; }
struct ObjFileSection &s = aSects[sect++];
s.name.offs = _AddStrPool(si->name, &stringArray, &stringPool, hdr.stringdata, stringPoolCap);
s.exp_app.offs = _AddStrPool(si->export_append, &stringArray, &stringPool, hdr.stringdata, stringPoolCap);
@ -7314,6 +7598,8 @@ StatusCode Asm::WriteObjectFile(strref filename) {
s.next_group = si->next_group >= 0 ? aRemapSects[si->next_group] : -1;
s.first_group = si->first_group >= 0 ? aRemapSects[si->first_group] : -1;
s.relocs = si->pRelocs ? (int16_t)(si->pRelocs->size()) : 0;
s.srcdebug_count = si->pSrcDbg ? (int)si->pSrcDbg->size() : 0;
srcDbgEntries += s.srcdebug_count;
s.start_address = si->start_address;
s.end_address = si->address;
s.type = si->type;
@ -7335,6 +7621,25 @@ StatusCode Asm::WriteObjectFile(strref filename) {
}
hdr.sections = (int16_t)sect;
struct ObjFileSrcDbg* srcLines = srcDbgEntries ? (ObjFileSrcDbg*)calloc(1, sizeof(ObjFileSrcDbg) * srcDbgEntries) : nullptr;
if (srcLines) {
size_t srcDbgIdx = 0;
for (std::vector<Section>::iterator si = allSections.begin(); si != allSections.end(); ++si) {
if (si->type == ST_REMOVED) { continue; }
if (si->pSrcDbg && si->pSrcDbg->size()) {
for (size_t src = 0, nsrc = si->pSrcDbg->size(); src < nsrc; ++src) {
SourceDebugEntry& entry = si->pSrcDbg->at(src);
ObjFileSrcDbg& ref = srcLines[srcDbgIdx++];
ref.addr = entry.address;
ref.src_idx = entry.source_file_index;
ref.size = entry.size;
ref.file_offs = entry.source_file_offset;
}
}
}
assert(srcDbgIdx == srcDbgEntries);
}
// write out labels
if (hdr.labels) {
for (uint32_t li = 0; li<labels.count(); li++) {
@ -7398,9 +7703,21 @@ StatusCode Asm::WriteObjectFile(strref filename) {
ms.value = mi->value;
ms.local = mi->local;
ms.section = mi->section >= 0 ? aRemapSects[mi->section] : -1;
ms.orig_section = mi->orig_section >= 0 ? aRemapSects[mi->orig_section] : -1;
}
}
struct ObjFileSourceList* sourceList = nullptr;
if (source_files.size() && srcLines) {
sourceList = (struct ObjFileSourceList*)calloc(1, sizeof(ObjFileSourceList) + sizeof(ObjFileStr) * (source_files.size() - 1));
sourceList->numSources = (uint32_t)source_files.size();
for (size_t src = 0, nsrc = source_files.size(); src < nsrc; ++src) {
sourceList->sourceFile[src].offs = _AddStrPool(strref(source_files[src]), &stringArray, &stringPool, hdr.stringdata, stringPoolCap);
}
}
hdr.srcdebug = srcDbgEntries;
// write out the file
fwrite(&hdr, sizeof(hdr), 1, f);
fwrite(aSects, sizeof(aSects[0]), sect, f);
@ -7414,6 +7731,12 @@ StatusCode Asm::WriteObjectFile(strref filename) {
fwrite(si->output, si->size(), 1, f);
}
}
if (sourceList) {
fwrite(sourceList, sizeof(ObjFileSourceList) + sizeof(ObjFileStr) * (source_files.size() - 1), 1, f);
fwrite(srcLines, sizeof(ObjFileSrcDbg) * srcDbgEntries, 1, f);
}
// done with I/O
fclose(f);
if (aRemapSects) { free(aRemapSects); }
@ -7442,6 +7765,14 @@ StatusCode Asm::ReadObjectFile(strref filename, int link_to_section)
hdr.relocs * sizeof(struct ObjFileReloc) + hdr.labels * sizeof(struct ObjFileLabel) +
hdr.late_evals * sizeof(struct ObjFileLateEval) +
hdr.map_symbols * sizeof(struct ObjFileMapSymbol) + hdr.stringdata + hdr.bindata;
const struct ObjFileSourceList* pSrcDbgInfo = hdr.srcdebug ? (struct ObjFileSourceList*)(data + sum) : nullptr;
const struct ObjFileSrcDbg* pSrcDbgEntry = pSrcDbgInfo ? (const struct ObjFileSrcDbg*)(pSrcDbgInfo->sourceFile + pSrcDbgInfo->numSources) : nullptr;
if (pSrcDbgInfo) {
sum += sizeof(ObjFileSourceList) + (pSrcDbgInfo->numSources - 1) * sizeof(ObjFileStr);
sum += sizeof(ObjFileSrcDbg) * hdr.srcdebug;
}
if (hdr.id == 0x7836 && sum == size) {
struct ObjFileSection *aSect = (struct ObjFileSection*)(&hdr + 1);
struct ObjFileReloc *aReloc = (struct ObjFileReloc*)(aSect + hdr.sections);
@ -7455,6 +7786,23 @@ StatusCode Asm::ReadObjectFile(strref filename, int link_to_section)
memcpy(str_pool, str_orig, hdr.stringdata);
loadedData.push_back(str_pool);
// source files
std::vector<size_t> source_file_remap;
if (pSrcDbgInfo) {
source_file_remap.reserve(pSrcDbgInfo->numSources);
for (size_t s = 0, n = pSrcDbgInfo->numSources; s < n; ++s) {
strref source_file(str_pool + pSrcDbgInfo->sourceFile[s].offs);
size_t i = 0, sz = source_files.size();
for (; i < sz; ++i) {
if (source_file.same_str(source_files[i])) { break; }
}
if (i == sz) {
source_files.push_back(StringCopy(source_file));
}
source_file_remap.push_back(i);
}
}
int prevSection = SectionId();
int16_t *aSctRmp = (int16_t*)malloc(hdr.sections * sizeof(int16_t));
int last_linked_section = link_to_section;
@ -7499,6 +7847,19 @@ StatusCode Asm::ReadObjectFile(strref filename, int link_to_section)
s.first_group = allSections[last_linked_section].first_group >=0 ? allSections[last_linked_section].first_group : last_linked_section;
last_linked_section = SectionId();
}
// add source debug entries from object file
if (aSect[si].srcdebug_count) {
if (!s.pSrcDbg) { s.pSrcDbg = new SourceDebug; }
for (int sd = 0, nsd = aSect[si].srcdebug_count; sd < nsd; ++sd) {
SourceDebugEntry entry;
entry.address = pSrcDbgEntry->addr;
entry.size = pSrcDbgEntry->size;
entry.source_file_index = (int)source_file_remap[pSrcDbgEntry->src_idx];
entry.source_file_offset = pSrcDbgEntry->file_offs;
s.pSrcDbg->push_back(entry);
++pSrcDbgEntry;
}
}
}
aSctRmp[si] = (int16_t)allSections.size()-1;
}
@ -7527,6 +7888,7 @@ StatusCode Asm::ReadObjectFile(strref filename, int link_to_section)
MapSymbol sym;
sym.name = m.name.offs>=0 ? strref(str_pool + m.name.offs) : strref();
sym.section = m.section >=0 ? aSctRmp[m.section] : m.section;
sym.orig_section = m.orig_section >= 0 ? aSctRmp[m.orig_section] : m.orig_section;
sym.value = m.value;
sym.local = m.local;
map.push_back(sym);
@ -7881,6 +8243,7 @@ int main(int argc, char **argv) {
const char *sym_file = nullptr, *vs_file = nullptr, *cmdarg_tass_labels_file = nullptr;
strref list_file, allinstr_file;
strref tass_list_file;
strref srcdebug_file;
for (int a = 1; a<argc; a++) {
if (argv[a][0]=='-') {
strref arg(argv[a]+1);
@ -7924,7 +8287,10 @@ int main(int argc, char **argv) {
assembler.list_assembly = true;
list_output = true;
list_file = arg.after('=');
} else if (arg.has_prefix(cmdarg_tass_listing)&&(arg.get_len()==cmdarg_listing.get_len()||arg[cmdarg_listing.get_len()]=='=')) {
} else if (arg.has_prefix(cmdarg_srcdebug) && (arg.get_len() == cmdarg_srcdebug.get_len() || arg[cmdarg_srcdebug.get_len()] == '=')) {
assembler.src_debug = true;
srcdebug_file = arg.after('=');
} else if (arg.has_prefix(cmdarg_tass_listing)&&(arg.get_len()== cmdarg_tass_listing.get_len()||arg[cmdarg_tass_listing.get_len()]=='=')) {
assembler.list_assembly = true;
tass_list_output = true;
tass_list_file = arg.after( '=' );
@ -7996,6 +8362,7 @@ int main(int argc, char **argv) {
" * -sym (file.sym) : symbol file\n"
" * -lst / -lst = (file.lst) : generate disassembly text from result(file or stdout)\n"
" * -opcodes / -opcodes=(file.s) : dump all available opcodes(file or stdout)\n"
" * -srcdbg / -srcdbg=(file.dbg) : generate a source level debugging file for object files or linked files"
" * -sect: display sections loaded and built\n"
" * -vice (file.vs) : export a vice symbol file\n"
" * -merlin: use Merlin syntax\n"
@ -8082,11 +8449,11 @@ int main(int argc, char **argv) {
}
// listing after export since addresses are now resolved
if ( list_output )
assembler.List(list_file);
if (list_output) { assembler.List(list_file); }
if( tass_list_output )
assembler.ListTassStyle(tass_list_file);
if (srcdebug_file) { assembler.SourceDebugExport(srcdebug_file); }
if (tass_list_output) { assembler.ListTassStyle(tass_list_file); }
// export .sym file
if (sym_file && !srcname.same_str(sym_file) && !assembler.map.empty()) {
@ -8094,7 +8461,9 @@ int main(int argc, char **argv) {
bool wasLocal = false;
for (MapSymbolArray::iterator i = assembler.map.begin(); i!=assembler.map.end(); ++i) {
uint32_t value = (uint32_t)i->value;
if (size_t(i->section) < assembler.allSections.size()) { value += assembler.allSections[i->section].start_address; }
if (size_t(i->section) < assembler.allSections.size()) {
value += assembler.allSections[i->section].start_address;
}
fprintf(f, "%s.label " STRREF_FMT " = $%04x", wasLocal==i->local ? "\n" :
(i->local ? " {\n" : "\n}\n"), STRREF_ARG(i->name), value);
wasLocal = i->local;
@ -8131,15 +8500,12 @@ int main(int argc, char **argv) {
strown<256> line;
line.append( i->name );
line.sprintf_append( "\t= $%04x\n", value);
fprintf(f, line.c_str());
fputs(line.c_str(), f);
}
}
fclose( f );
}
}
}
// free some memory
assembler.Cleanup();