-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
support for segments #60
Comments
Example: !segmentdef ZP {from: $02, to: $ff}
!segmentdef CODE {from: $0800, to: $0fff}
! segmentdef DATA {from $1000, to: $1fff}
...
; sub1.asm
!segment CODE
lda #0
!segment DATA
music: !byte sid_data |
Totally in 💪 of this feature. Been on my list for some time. The zp part is easy to do with just variables right now but all the others make a lot of sense. I like the object literal syntax for segment defs. :) Perhaps it could use the same keyword for both declaration and use. !segment with no from/to args could just start a new segment at the current pc. |
Cool! 😎
Do you mean something like this? !segment CODE { from: $0800, to: $0fff }
!segment DATA { from: $1000, to: $1fff }
; somewhere else, maybe in another .asm file
!segment CODE
a_sub_routine:
lda some_data
...
rts
!segment DATA
some_data: !byte 0,1,2,3 I think it looks intuitive enough, using the same keyword both for declaration and use. Another possibility could perhaps be to allow specifying a previously defined segment when declaring a scope for a label? Like this: !segment CODE { from: $0800, to: $0fff }
!segment DATA { from: $1000, to: $1fff }
; somewhere else, maybe in another .asm file
a_sub_routine: CODE {
lda some_data
...
rts
}
some_data: DATA {
!byte 0,1,2,3
} However I don't know how that would work with filescopes...and also it might not be as clear as using a specific keyword? |
@neochrome I guess in your idea of segments, the segments would always output whatever they contain into the output PRG? That doesn't seem to be the case in KickAssembler. Only the default segment goes into the output PRG by default. Any other segment needs to be explicitly written to an output file (or merged into the default segment). It's not a completely bad idea to support more general segments like in KA. This enables cartridge builds, multi-part demo builds, etc. Just need to think about implementation carefully. BTW agree that a specific keyword is better than somehow adding special label syntax for segments. |
@nurpax I believe your right about KA's default behavior and also, my thoughts was to have a slightly different default, where the output ends up in the same file. |
@neochrome BTW, I didn't give up on this. I've just been on a bit of a coding break, playing Zelda: Link's awakening and learning Rust lang. Will certainly work on this at some point. The easiest implementation would be where all segments are declared with a fixed starting address (and maybe size). But KA supports segments where you can say segment B starts after segment A. It's of course possible to support this, but it will automatically mean more compilation passes to work out the starting address for those "start from" segments. |
No worries at all! I've kept busy toying around with a dsl-like solution in ruby for constructing 6502 machine language just to try out some stuff :)
I think the easier route is the way to go on this - both to get something going, but also because it's probably not that hard to choose segment range up front anyway... |
I wake up this issue as it would be a great improvement as complex application requiring detailed and fine memory organization is hard to design without segments. |
Said the author in September 2019. :) But I'm starting to pull this into my cache again, hopefully with better results this time. |
I actually went ahead and implemented segment support. If there's anyone still around in this GitHub issue that cares, I could post my design up here for a quick review.. Currently it looks like below. The syntax is kind of arbitrary, just what felt ok when I started looking at the parser. start/end arguments can take on any expressions, so you could even load the values from a JSON file if you wanted to somehow externally configure memory layout. But most likely the expressions used for start/end must be values that do not depend on label values. Because I think that will probably make the multi-pass forward reference label address resolver never converge. Or so it feels like, didn't think it through. !segment code(start=$810, end=$820)
!segment data(start=$830, end=$840)
* = $801
lda #0
!segment code ; use code segment
lda #1 ; should be at address $810
lda #2
!segment data
!byte 0,1,2,3 ; data, should go into address $830
!segment code ; emit to code segment
lda #3
lda #4 This yields the following disassembly:
|
Even if I'm not currently developing for the ol bread box, I'd be happy to
take a look and compare notes :)
…On Sat, Jan 30, 2021, 02:46 Janne Hellsten ***@***.***> wrote:
I actually went ahead and implemented segment support. If there's anyone
still around in this GitHub issue that cares, I could post my design up
here for a quick review..
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#60 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACR6UXWPD24YW23AW6J2PLS4NQGTANCNFSM4ISTTO4A>
.
|
I like the fact you can split a segment and continue to append code to it :D Even if I have no clue what could be the usage. In terms of syntax and behavior, I'm pretty pleased with the proposal. Usecases / GoalsGoal 1: avoid the Tetris game (or should I say Bintris ???) when coding a one-file demo which trying to maximize memory usage while respecting C64 memory constraints (banks, alignment, screen mem, i/o,...) Goal 2: simplify the design of a multi-parts demo using OMG's Sparkle Usecase 1 detailsLet's start with the most obvious one (Goal 1).
Using segments, I'm quite sure the Tetris game will be easier, at least, no need to physically move part of the listing up and down. Usecase 2 detailsNow, the second goal which may also have an impact on the PRG generation. In brief, Sparkle is an IRQ Loader which takes care of building a disk image and depacking/loading into data in memory (code or other) when requested. Sparkle doesn't require to change the code or adapt it, is a a second pass process. Using the
Without going into all the details of a sls script, let's have a look at how the 2 demo parts are defined . Part I: BigSpritethis part consists of:
Part 2: Multiplexerthis part consists of:
Fortunately, Sparkle can manage offsets when the cross-assembler don't manage segment assembling and will extract from any file (in my case the prg which aggregates the various segments) the required slice. This is the meaning of the 2 additional parameters:
=> From So using a python script and the labels file generated from c64jasm, I could automatically generate those offset/size parameters for each segment. That works but that would be soooo better if c64jasm could generate one prg (as Sparkle can use the 2 first bytes to get the start address) or any binary file for each segment. I hope my 2 use-cases make sense, fell free t comment if not clear or anything. CommentsLast point, not (yet) a requirement but something I found interesting while trying CC65 relocatable segments linker is that it gave me the possibility to split my code in different files (and avoid the 10km code in one file) and using the |
As the
Should the entry point be defined as an org or cold it be a parameter or |
The start of the segment is tricker to figure out. For example something like this: !segment code () ; neither start or end specified
!segment data () ; data implicitly starts after code Figuring out the start of |
@shazz how do you feel about the keyword arg syntax? I realize that it is a bit inconsistent with older features like !binary:
I've been coding so much Python lately that this !segment code(start=$810, end=$820)
!segment data(start=$830, end=$840) felt like the obvious first choice. But @neochrome above used JS object notation. In some sense that's more in the spirit of c64jasm and JS.. Feels like this keyword syntax might in fact be something that could be retrofitted for things like !binary, like:
@shazz another q: re multiple output files. So something like this: !segment code(start=$810, end=$1000)
!segment code_b(output="b.bin", start=$810) With I think overlapping segment address ranges would be forbidden. But probably only if the overlap happens within a single output? |
About !binaryI really prefer the keyword syntax, I always thought you kept the SegmentsAbout the segment porposal, I like the optional Dict vs Function notationAbout dict notation vs function notation... I would say I prefer the function notation when it is an action (like
It looks fine to me but the segment split/append becomes more complicated (even if I don't think I will use it). In my python meta-cross-assembler, here how I define a segment, using context manager. with segment(0x0801, "CODE") as s:
... But really, dict or function, both are ok for me. Your call. |
I like the function syntax better too. Re def vs. use. Kickassembler made a distinction between declaring a segment and using it. I also definitely see use for being able to be alternating between segments (like my example code -> data -> code), even though I guess you didn't quite see the point. Neochrome's first comment indicates that he was specifically looking for this type of alternating segment support, and I've had a need for this myself. I thought the Alternatively it could be that the first occurrence of something like !segment code(start=$810, end=$820) both defines a new segment, and marks it active. So it'd be equivalent to:
Maybe? OTOH, this will have the problem that if someone does this: !segment code(start=$810, end=$820)
!segment data(start=$1000)
; ok time to code
main: lda #0 their code would go into the data segment.. |
I think is first idea is fine, |
Question raised under the shower this morning. Segments are also useful to split huge codebase (particularly unmanageable in assembly) into small chunks. Will it be possible to include the segments definition in each segment file ? |
If the segments are split in multiple files, how the cli will look like ? Something like that?
|
Good question. I actually always thought the segments would still be included through some common .asm file. But if multiple files on the command line feels good (I haven't decided), this could be treated as the same as including all of the listed files in a single (implicit) asm file. This brings out another questions which is: should there be some sort of |
Sorry @neochrome and @shazz, the below update is a bit long. I tried to summarize the current design in case you have some suggestions on how to improve it. It feels pretty good to me so far. I checked in some work on segments.. ea95e02 It still has some bugs and missing features:
Allowable parameters for the segment
|
Sorry for the late feedback - been quite busy with work etc. I think it would be good enough (at least in a first version) to have to specify separate segment output(s) on the CLI if need be. Not sure how useful it would be to be able to specify overlapping segments (as long as they go to different outputs) - might be allowed by KA, but again not sure of a good use case. With regards to scoping, I think keeping it simple and predictable (for the user) is important. I played around a bit with segment defs in my little Ruby DSL for generating 6502 binary code - I'll have a look at how I tackled some of these cases there and see if I find something more. |
…es (#60) Machinery to accept only expression values in segment start/end that are possible to compute in the first pass of compilation. This should handle most cases, although I guess conditional compilation could still leak forward label values into segment arguments. Not sure if there's a reasonable way to fix this.
Thanks for the comments!
One use-case would be if someone wants to build multiple .prg files (say a multipart demo) with a single command line invocation. Might be handy if you just want to kickoff a
I think the current implementation is fine now. It follows the same scoping as variables and other symbols. Apart from some minor error checking and multiple prg output, the feature is pretty much done. |
I agree with @neochrome. In details:
Comments:
But overall looks perfect to me I don't need much more than @neochrome (define/split/organize) and segment outputs for Sparkle as I can tell right now :) @neochrome, funny, I did the same but not in Ruby, in python :) |
Btw, building the branch generates some warning:
Is it.. important ? |
Thanks again!
Can you expand on this? I don't understand.
Default behavior would be to treat this as an error if segments going to the same output file overlap. Overlapping segments with a different destination would be fine (otherwise you couldn't really build multiple prg outputs). |
I've been conditioned to ignore these due to GitHub's dependabot spam that I've been getting for the past 1-2 years now. Should clean those up at some point. |
for outputs I meant, the assembling process will:
|
instead of the hard to remember !binary syntax of: !binary "file1.bin" ; all of file1.bin !binary "file2.bin",256 ; first 256 bytes of file !binary "file2.bin",256,8 ; 256 bytes from offset 8 ..add keyword args support so that this is also legal: !binary (file="binary1.bin", offset=0) !binary (file="binary1.bin", offset=2, size=2) !binary (file="binary1.bin", size=4) !binary (file="binary1.bin", offset=2) While at it, handle binary output truncation in case offset+size reaches beyond the end of the file.
Kind of work-in-progress -- this will not catch all segment overlaps. At least overlaps with the current default segment are not checked. Revisit when adding separate prg outputs?
I was trying to organize my code into multiple files, each with their own responsibility and run into some issues with the inclusion order into the main program. If
sub1.asm
defines some subroutines and loads some data, and thensub2.asm
does that too, the final order of things would be something likesub1 code, sub1 data, sub2 code, sub2 data
, which may not always be desired. Instead one might want to be able to consolidate and keep code together and then data together.Would something like this be worthwhile to implement?
Maybe it could work a bit like KickAssembler
.segment/.segmentdef
but simpler?The text was updated successfully, but these errors were encountered: