Dotneteer / spectnetide

ZX Spectrum IDE with Visual Studio 2017 and 2019 integration
MIT License
205 stars 27 forks source link

Add optional assembler listing output file #144

Closed QwazyWabbitWOS closed 5 years ago

QwazyWabbitWOS commented 5 years ago

With an integrated assembler and disassembler within the SpectNetIDE, one may not need or miss a listing file. Old school method was a two-pass assembler that produced binary file, either BIN format or Intel HEX format for loading into ROM/RAM on hardware. List files with a cross-reference were very typical for verifying assembler output.

New feature proposal is for optional .lst or .list output by the compiler/assembler showing assembled object code in hex representation along with source lines. Typical output is columnar output of address, hex opcode, source line number, source line, comments. Example: 0229 3E 50 214 ld a,50h 022B 06 25 215 ld b,25h 022D 80 216 add a,b 022E 27 217 DAA ; 4 Decimal adjust accumulator.

Dotneteer commented 5 years ago

@QwazyWabbitWOS, thanks for the feature suggestion :-). Right now the assembler is activated with a context menu command from Solution Explorer, so it does not allow any way to specify arguments. I'd add a switch to create list file to the Tools | Options dialog that would also let you set the file extension. Do you have any other idea or mind in your head?

QwazyWabbitWOS commented 5 years ago

You're welcome. This is an amazing project. Putting the control of file output in Tools | Options seems perfectly reasonable to me and is in line with Microsoft's usability recommendations. I've seen .lis, .lst, .list as file extensions but I see no reason to restrict it to ancient 8.3 conventions. Making it user configurable with a .list default would be the way I would probably implement it. I'd create another category folder in your file explorer interface for the list files and users can manipulate them as needed.

Dotneteer commented 5 years ago

@QwazyWabbitWOS, in many cases, the output is a result of compiling multiple files (e.g. the main file loads include files). How would you show in the output the individual files so that you know that a particular output comes from a specific source file?

QwazyWabbitWOS commented 5 years ago

There are almost as many answers to that question as there are assemblers. :) A simple two-pass assembler often can only accept one source file at a time and generates a list file for it. CP/M's ASM, MAC and Z80ASM were such as these. There were very primitive and often didn't accept file extensions. I don't remember ever invoking them on multi-file source. I'd have to re-read the documentation.

Where the assembler accepts multiple sources files it often outputs to a single list file and uses two columns of line numbers, one for the included code and another for the master list. ZZ80ASM is one such as this. I'm not sure I like that solution. I've never needed to refer back to it.

Softools C, and macro assembler on DOS hosts with Z80 target uses a single line number column and appends a lower case i to the line number for line numbers of include files and you have to refer back in the listing to see the name of the included file. The current line number is tracked stack-like, resetting to 1 at the beginning of the include file, reverting back to base source line number when the include file ends. In my past usage, I've never nested include calls so I can't tell you how deep this was allowed. The system was a C compiler that generated assembler source, an assembler and a linker. Debug information was also embedded in the list file.

One very common solution is to output a list file for every source input file. In those cases the unresolved addresses were filled with 0000 or ???? in the list file or marked in some way to be resolved by the linker which generates the .map file where the symbol, the segment it belongs to, it's address and the corresponding .obj file it came from are listed. (e.g. Microsoft's MASM)

I suppose your plan for your compiler will influence your decision on how to output list files and whether you're going to compile direct to object code or use an intermediate .asm file.

Dotneteer commented 5 years ago

@QwazyWabbitWOS, I'm aware of these facts about compilers, and this is why I asked you the question :-). A have a few contacts within the Z80 programming community, and most of them apply two very different techniques: some use single (long) file, others break down the code to small files. The current compiler in SpectNetIDE is a simple preprocessor with a semi-one-pass compiler using fixup to resolve addresses. It does some tricks to allow macros, statements, and structures. When evaluating expressions, the compiler provides late-evaluation (you can refer to a symbol/address defined at a later point of compilation), but for certain constructs (such as the ORG pragma) it requires immediate evaluation and raises an error if it is not possible. In the preprocessing phase, the compiler collects all the parsed assembly source code lines that will be used in the real compilation pass for code emission, and of course, it tracks the location of code lines.

I do not like the idea to emit separate list file for each source code file, as it might pollute the project with unnecessarily. In the first version, I would emit a single list file that contains short heading information for each source code file, and besides the line number, it would issue a file index for each output line. I would like to allow some freedom for developers to define the output format, so I plan to support an effortless template mechanism with a simple format string such as {A} {C} {F} {L} {S}, where the parts of the template string contain placeholders for address, operation codes, file index, line number, and source code, respectively. If you do not need file index, you can change the template to {A} {C} {L} {S}. If you'd like first to show line numbers, you can change it to {L} {A} {C} {S}, and so on. I'm also thinking of adding a switch that allows three different file information output:

Any opinion?

Dotneteer commented 5 years ago

@QwazyWabbitWOS, I've completed the version specified above. I'd be happy to send you a private build for beta testing. Please, contact me directly at dotneteer@hotmail.com!

You can read the first version of documentation here: https://dotneteer.github.io/spectnetide/documents/assembler-output

QwazyWabbitWOS commented 5 years ago

I don't have a problem with single list file output since that is the structure of your disassembler anyway so expectations would be for consistency. A build process driven by make file is often monolithic output even when it's an assemblage of modules. A list file gets include files for free since they become part of the input stream. I envisioned a list file to be very similar to your disassembly listing in your environment. I'm sure most projects targeted to your simulator or targeted to a real ZX would mostly be assembled from monolithic sources in any case. Since the list output is optional I didn't regard a multi-source file, multi-list file system as cluttered. Visual Studio always puts them in the Debug or Release folders and they were easily cleaned.

I like the template idea. Allows custom output to needs of user. Yes, page headers were typical in the old assemblers. No opinion on where the map goes. I've seen them as separate files and mostly at the ends of list files but one gets tired of scrolling if you have to refer to it often. My past practice with targeting embedded systems I checked the map at the end of a build and noted essential locations and worked from the list and the debugger but those days are long gone for me.

Dotneteer commented 5 years ago

Implemented, released in v1.19.0