| |
Sasq
Registered: Apr 2004 Posts: 155 |
Badass - New 6502 Assembler
The last couple of months I've created a new 6502 Assembler called bass (or Badass).
The basic idea is for it to be as advanced as Kickassembler, but with a less complex, more unified syntax.
And it also has unit tests in an internal emulator.
You can find it at https://github.com/sasq64/bass
I've started a tutorial here: http://apone.org/bass/part1.html
Here is an example C64 source http://apone.org/bass/example.asm.html |
|
| |
Frantic
Registered: Mar 2003 Posts: 1627 |
Looks quite nice at first glance! |
| |
chatGPZ
Registered: Dec 2001 Posts: 11108 |
This is really interesting! |
| |
Bacchus
Registered: Jan 2002 Posts: 154 |
Interesting. Will have a look.
/Bacchus |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
Some other things:
* It should be pretty easy to build, you just need a modern C++ compiler and CMake. Windows users can open the directory in VS Code for instance.
* If you're looking to customize the assembler it should also be straight-forward. Look in `meta.cpp` for the definitions of all meta commands and `functions.cpp` for functions. You should be able to add your own by copying the existing ones.
The thing I'm experimenting most with now is how to interact with the emulator. You can for instance call into LUA from 6502 using "brk", and this could be used for proto-typing -- ie to start with LUA code and then re-implement it in 6502 with tests to back it up.
I also modified the X16 Commander emulator to also bind LUA to 6502 in the same way so I can run X16 programs that are partly in LUA.
Unit tests are also good for optimizing, since you get the cycle count as an output, so you can assert that your code does not become slower. |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
I must say I'm impressed by your C++ coding style. Really a pleasure to the eye. And also a nice project with a lot of new ideas.
To me personally I always use Eye of the Beholder as a test case in my head; could I port EotB to this assembler? And by the looks of it, no, due to the lack of high level memory management with segments and separate linking and so on. Maybe features to add for someone? |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
I am looking for beta testers, so there is a good chance I will implement any required features for someone actively using it :)
And I am aware that there is functionality missing in memory layout, sections and linking. I am not sure exactly how to make that powerful and simple.
Right now you can for instance do things like this:
!section "extra", sections.main.end
; stuff
!section "main", $801
; more stuff
This will place section "extra" after "main".
... but I realize you need something more advanced. Suggestions are welcome. |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Some great ideas and modern approaches to old problems.
One thing i've occasionally missed with 6502 assemblers is the possibility to have a hashbang in the first line of an assembly source file.
I like to have small projects (size-restricted demos mostly, or random experiments) in single monolithic files, and avoiding to create a build script or Makefile when getting started on something new would be nice. :) |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Quote: Some great ideas and modern approaches to old problems.
One thing i've occasionally missed with 6502 assemblers is the possibility to have a hashbang in the first line of an assembly source file.
I like to have small projects (size-restricted demos mostly, or random experiments) in single monolithic files, and avoiding to create a build script or Makefile when getting started on something new would be nice. :)
hashbangs are implemented by the exec() routine in the OS.. |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
As for sections and the like, have you checked out 64tass?
This is my current go-to assembler for smaller projects, and seems quite similar in its approaches.
Full-blown separate link stage is ca65's domain, of course, but i usually avoid linker files until they really make things tidier and more managable, which happens rather late for most projects. |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Quoting JackAsserhashbangs are implemented by the exec() routine in the OS.. Until the interpreter in question chokes on a syntax error. :) |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
@Krill: Done :)
(Just extended the grammar to allow '#' comments if they are whole line comments). |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Awesome! \=D/ |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
My "vague" plan about sections and linking is not to have linking, but rather something more "javascript" like where you can have sources that "export" symbols and then you can import those sources.
And instead of a link script you can choose to have a top level source file that lays out everything. |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Quote: @Krill: Done :)
(Just extended the grammar to allow '#' comments if they are whole line comments).
Ahh, that little detail! |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Quote: My "vague" plan about sections and linking is not to have linking, but rather something more "javascript" like where you can have sources that "export" symbols and then you can import those sources.
And instead of a link script you can choose to have a top level source file that lays out everything.
I can do a small write up what I personally would need in terms of segments to support building a complex cart like EotB. I had similar chats with Mads when he implemented segments in Kickasm. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
Quote: I can do a small write up what I personally would need in terms of segments to support building a complex cart like EotB. I had similar chats with Mads when he implemented segments in Kickasm.
That would be great! |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Quoting SasqMy "vague" plan about sections and linking is not to have linking, but rather something more "javascript" like where you can have sources that "export" symbols and then you can import those sources.
And instead of a link script you can choose to have a top level source file that lays out everything. Sounds like this could be achieved with separate section-declare/collect and section directives, as 64tass does.
These allow the position in the source code to be independent of the position in the output binary.
Rest (splitting up source files) can be done via regular include semantics. |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Quote: Quoting SasqMy "vague" plan about sections and linking is not to have linking, but rather something more "javascript" like where you can have sources that "export" symbols and then you can import those sources.
And instead of a link script you can choose to have a top level source file that lays out everything. Sounds like this could be achieved with separate section-declare/collect and section directives, as 64tass does.
These allow the position in the source code to be independent of the position in the output binary.
Rest (splitting up source files) can be done via regular include semantics.
It's not only that. It's more about the assembler needs to know the bank ID for all labels it has so that bank switch macros knows what bank to switch in when JSRing (via ram trampolines) across different banks.
ca65 solves this by allowing an arbitrary bank-id to be assigned to a memory-directive. Segments emitting code into that memory will have all their labels assigned with that bank ID and other code can resolve it with the .bank(label) operator. |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Would a .sectionof(label) directive allow for that? Sections are named, of course. |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Quote: Would a .sectionof(label) directive allow for that? Sections are named, of course.
Yes, maybe. Bottom line I have a jsrf (jsr far) macro that works and looks exactly like jsr but the assembler emits all the code needed to perform a proper bankswitch and back again upon rts. This gives me the freedom to shuffle around the segments completely across various banks without having to think about it. That makes it very easy for me to fill the banks and pack the code tightly and never worry about breaking code when shuffling around the segments onto other banks. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
Could this be supported by simply allowing > 16bit addresses in symbols ? Meaning normally the top 8bits of a 24bit address would be the bank.
So then something like
!macro jsrf(a)
lda #a>>16 ; load bank
; Do magic
jsr a ; (top bits ignored as normal)
}
!section "bank5", $05a000
my_code:
nop
rts
!section "bank6", $06a000
nop
jsrf my_code
|
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Quote: Could this be supported by simply allowing > 16bit addresses in symbols ? Meaning normally the top 8bits of a 24bit address would be the bank.
So then something like
!macro jsrf(a)
lda #a>>16 ; load bank
; Do magic
jsr a ; (top bits ignored as normal)
}
!section "bank5", $05a000
my_code:
nop
rts
!section "bank6", $06a000
nop
jsrf my_code
That a step closer indeed. Also, sections needs to be filled and padded out so that the final binary have all the segments after each other. So you typically need a size and a fillval parameter for each section also. You also need to specify run-adress, in this case $8000 for both segments.
Also declaring a section with the same name further down but without adress should ideally continue to fill the section with "stuff". I use this f.e. to put bits and pieces of the clear frame buffer unrolled code where there is room. All of a sudden a bank is filled and a small portion of this clear code has to be moved to another section, so I just change the bank-id (or in your case section name) to something else and see if it fits there.
But all of this are just curiosities. I will NOT port EotB to this assembler, but just wanted to share the more advanced use cases with banking and segments. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
Quoting JackAsserT
But all of this are just curiosities. I will NOT port EotB to this assembler, but just wanted to share the more advanced use cases with banking and segments.
EoTB must be one of the largest C64 projects ever, so yeah that would be pretty stupid ;) |
| |
Frantic
Registered: Mar 2003 Posts: 1627 |
Well, good support for cartridge banking is a nice thing to have, regardless of whether the project is super big or not. DreamAss has some features along those lines as well, and I used that at some point for a little cartridge project I was fiddling with. At the moment I am working on a new music editor, and it may eventually turn out that I need to do it as a cartridge image instead, to be able to fit all the stuff that I want to have in it. If that would happen, a great assembler with intuitive support for cartridge banking would surely be my first choice. |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Quoting FranticAt the moment I am working on a new music editor, and it may eventually turn out that I need to do it as a cartridge image instead, to be able to fit all the stuff that I want to have in it. Would REU be an option? And if not, Retro Replay's banked 32KB of RAM? :) |
| |
Frantic
Registered: Mar 2003 Posts: 1627 |
The way I see it a cartridge image would be a more straightforward solution to the problem at hand, and loading time would be close to zero, even though both of the options you mention would of course provide some more space in different ways. Anyway, a discussion of that would probably be off topic in this thread, and the preferred option is still to squeeze it all into normal C64 RAM if possible. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
@JackAsser: What about this:
stuct Section
string name
uint32 start
uint32 size
uint32 current_pc
uint32 offset
uint8 data[]
uint32 flags
uint8 fillchar
ASSEMBLING
* When a section is created, start & current_pc are the same.
* current_pc can be explicitly set, but normally increases as data[] grows.
* Size can be set if known, otherwise it will be the size of the data array.
* Sections can be switched at any time. Generated code and data is appended to the data array of the current section.
* Addresses can be > 16bit. Recommended to use >,< unary operators to get low and high byte.
* Assembler will generate an error if you try to access memory not within the 16bit range (ie where bits 16 and above differ).
OUTPUT
* If offset is not set, offset = start
* If size is not set, size = data.size
* Otherwise grow data to size and insert fillchar
* Write all sections in order to output file at offset
FLAGS
* NoOutput - Section only used for labels and offsets, will not be written to the output file.
* SeparateFile - write section to its own file, based on 'name'.
* ReadOnly - Intended to go into ROM. Assembler could warn if self modifying code is used.
AUTOMATIC BANK HANDLING
* A single section for multiple banks
* Keep track of where bank ends and wrap to next
* Needs grouping of statements so assembler know where it can "bank break" |
| |
Frantic
Registered: Mar 2003 Posts: 1627 |
Sounds good I think. Regarding "* ReadOnly - Intended to go into ROM. Assembler could warn if self modifying code is used" it would of course also be important to allow self-modifying code to be assembled to ROM segments, since one would typically copy at least some code from ROM to RAM at runtime, and that code may involve self-modification etc. |
| |
Golara Account closed
Registered: Jan 2018 Posts: 212 |
big + for c++ I'll definitely check it out |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Yes frasse, that is a common use case. I have pure rom segments, i have ram segments (stored on rom) and i have bss-segments (pure ram, nothing stored) |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Quoting FranticSounds good I think. Regarding "* ReadOnly - Intended to go into ROM. Assembler could warn if self modifying code is used" it would of course also be important to allow self-modifying code to be assembled to ROM segments, since one would typically copy at least some code from ROM to RAM at runtime, and that code may involve self-modification etc. Wouldn't that be a RAM segment that is loaded/assembled to ROM? I.e., a segment with different load and run addresses. |
| |
Frantic
Registered: Mar 2003 Posts: 1627 |
Yes, that's what I tried to say. What Jackasser said, basically. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
Well if it's intended for RAM, don't tag it as "Read Only" :)
The terms here can be a bit confusing though.
So if I understand correctly:
load_address is where the section is expected to end up in memory. It is used for checking overlap, and is normally specified directly by the developer. It defines the initial PC (run_address)
run_address is normally the same as load_address, but if the developer changes the PC inside a section, they will not align any more. run_address is something the developer needs to keep track of "manually".
file_offset normally needs to be specified for cart images, where the output is not a simple linear mapping to RAM. |
| |
Frantic
Registered: Mar 2003 Posts: 1627 |
Yes, the terms are a bit slippery. So, no matter if I use the terms correctly or not, what I meant was this:
If we distinguish between a segment (a larger unit) and a section (several sections of code can be contained in a segment), a segment which is generally intended for ROM and should be read only, may still contain one section of code which contains something that should be executed in C64 RAM or drive RAM and may contain self-modifying code.
!segment ROM_BANK1, $8000-$A000, READ_ONLY { ;a "segment"
[some read only stuff that can't use self-modifying code etc]
!section NAME_OF_SECTION, relativepc=$0800 { ;a "section" inside the segment
[some stuff that is intended to be copied "manually" from the ROM to $0800 in RAM. This should be able to override the READ ONLY restriction that otherwise applies to the segment that contains this section.]
}
[some more read only stuff that can't use self-modifying code etc]
}
Maybe there is some entirely different and better way to solve this. I just wanted to explain in more detail what I meant. |
| |
Golara Account closed
Registered: Jan 2018 Posts: 212 |
I know this is tool from coder for a coder, but still you could have released built binaries for people that can't into modern software compilationing
I made it :P Statically linked, so it should work on everything
windows 64bit (compiled with mingw on linux): https://mega.nz/file/2gYXFaBA#MftkFZhFnAdm4fKJ7WCZ4sq3ULVemKlXr..
linux 64bit https://mega.nz/file/2gYXFaBA#MftkFZhFnAdm4fKJ7WCZ4sq3ULVemKlXr.. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
@Golara: There are Windows releases on the git-page, built using MSVC.
Binaries for Linux is usually not a good idea.
And for most people it is just "clone" and "make" and you are done. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
@Frantic: I am hoping to avoid multiple levels with both segments and section because it complicates things...
For that particular case you can either mark the section as not ReadOnly and live without the extra checking. But better probably to add support for changing also the ReadOnly state on the fly, like the PC.
I'm wondering if there are other cases that are harder to handle with only one level of sections. Can you think of a situation where you really need the parent/child relationship ? |
| |
Golara Account closed
Registered: Jan 2018 Posts: 212 |
Quote: @Golara: There are Windows releases on the git-page, built using MSVC.
Binaries for Linux is usually not a good idea.
And for most people it is just "clone" and "make" and you are done.
I must have missed it then. Normaly there's a "releases" tab at the top, next to issues, pull requests etc. But it's not there now...
As for linux binaries. I know what you mean, but these problems arise when you use dynamic linking and your program wants glib 2.14.2 but you have 2.14.1 so it's not compatible :P This is a static build (that's why it's 22mb) and it should work on anything.
The only thing I can see potentially breaking is trying to run this binary on an older kernel than mine... I don't know if that's a problem but if doesn't work my vote is on that. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
@Golara: I think both those links are for the windows build... |
| |
Frantic
Registered: Mar 2003 Posts: 1627 |
@sasq: changing the ReadOnly state on the fly sounds like a convenient solution, that doesn't overcomplicate things.
As for other uses of a parent-child type of structure, it is probably not necessary. Benefits of having it, that I can think of, may include:
* Local labels within a "section". If I remember correctly, DASM is pretty strong in this domain. (But you already had something like that in the assembler I think? Some sort of "blocks"? I confess I haven't looked into the details of your assembler yet — so all of what I say is just a bunch of general thoughts based on the discussion in this thread.)
* The grouping of statements that you mentioned, so the assembler knows where to "bank break" (e.g. not in the middle of a section), if you were thinking of some sort of automatic handling of rom banks. In this regard, a "section" could perhaps be defined as "floating", to allow the assembler to place it in any (according to some definition) available space in the ROM banks, rather than necessarily put it where it occurs in the source.
Anyway.. The support for banks/cartridges shouldn't be taken too far. If it comes at the cost of making all kinds of things more complicated in the assembler, it is probably not worth it. Personally I am happy as long as an assembler at least has some basic support for banking/cartridges that makes projects like that a bit easier. |
| |
Golara Account closed
Registered: Jan 2018 Posts: 212 |
Quote: @Golara: I think both those links are for the windows build...
yes, my bad. Here it is https://mega.nz/file/exYzBCLZ#1KnI4ZkpL-Wk-qtwLkVv1oJtmsw4a_5o0.. |
| |
Oswald
Registered: Apr 2002 Posts: 5017 |
Quote: Quoting SasqMy "vague" plan about sections and linking is not to have linking, but rather something more "javascript" like where you can have sources that "export" symbols and then you can import those sources.
And instead of a link script you can choose to have a top level source file that lays out everything. Sounds like this could be achieved with separate section-declare/collect and section directives, as 64tass does.
These allow the position in the source code to be independent of the position in the output binary.
Rest (splitting up source files) can be done via regular include semantics.
*= allows that aswell, I dont really see advantage of sectons for this :P |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Quote: *= allows that aswell, I dont really see advantage of sectons for this :P
Nah. You have position in rom, positioning in ram and positioning in the actual binary (i.e. Bank) |
| |
Oswald
Registered: Apr 2002 Posts: 5017 |
Quote: Nah. You have position in rom, positioning in ram and positioning in the actual binary (i.e. Bank)
I mean this part "section-declare/collect and section directives, as 64tass does. These allow the position in the source code to be independent of the position in the output binary." |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Just like chisel and hammer also work to write your next novel, yes. |
| |
Oswald
Registered: Apr 2002 Posts: 5017 |
Quote: Just like chisel and hammer also work to write your next novel, yes.
same effor frankly to change section or *= addresses. |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
The point is that the current program counter is just one of many attributes of a program section/segment. Once you commit to using them, you have better and more elegant control. Then you also prefer to manipulate section attributes rather than rely on the old blunt tool that is "* =".
And besides, can you easily continue right where some other part of code ended, just by using "* ="? That is, without having gaps in your code or awkwardly saving current output PC in some variable to reuse it for some other "* =" further down or similar. |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Quote: The point is that the current program counter is just one of many attributes of a program section/segment. Once you commit to using them, you have better and more elegant control. Then you also prefer to manipulate section attributes rather than rely on the old blunt tool that is "* =".
And besides, can you easily continue right where some other part of code ended, just by using "* ="? That is, without having gaps in your code or awkwardly saving current output PC in some variable to reuse it for some other "* =" further down or similar.
@Oswald: Trust me and Krill on this. Only having *= for Eye of the Beholder would have been a disaster. PC and relative PC are just some of many attributes for a segment.
@Sasq: I suggest you take a look at LD65 and how they separate memory and segments as two different entities. It's quite elegant and you should be able to copy those concepts and instead of a separate link file you can have it directly in the source. https://www.cc65.org/doc/ld65-5.html |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
The question is still do we need "nested" sections.
So how would this work with a separate segment for ram_fn ?
!section "bank5", $058000
jsr copy_fn
jsr $c000
rts
copy_fn:
stx ram_fn_end-ram
$ lda ram_fn,x
sta $c000,x
dey
bne -
rts
!pc $c000
ram_fn:
nop
rts
I guess you need something like
!section "ram_fn", start=sections.bank5.end, pc=$c000
ram_fn:
nop
rts
Except hardcoding start is inflexible, ideally you want to
tell the assembler to place section anywhere withing a certain area... hence the division between memory and section in LD65...
Ok so I'll introduce memory areas, and then you can specify section start to either a specific address, or a memory area.
So we should not need something weird like wrapping the ram_fn in a nested section hopefully. |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
I recently needed* nested sections.
This was for a portion of code that is copied from somewhere to RAM under $d000 after run, modified in that IORAM section, then later on transferred to the drive and executed there somewhere below $0800.
The nesting came in handy for sharing that IORAM section between drive code and other stuff not executed on the drive.
* Could have done without, mind, but a lot less elegantly and with some more potential sources of bugs. |
| |
oziphantom
Registered: Oct 2014 Posts: 478 |
a case from 64Tass which has an internal linker, which lets you do crazy stuff.
So you have an IRQ handler, but you have 2, 1 PAL and 1 NTSC and you want to copy it to RAM but you want a hole big enough for it to be copied.
Then you want the some parts of the IRQ handler to be in the same address so other code can reference them.
so you have
* = Location in ROM File
IRQ_NTSC_START
.dsection sIRQ_NTSC
IRQ_PAL_START
.dsection sIRQ_PAL
.logical IRQ_DEST ; make the code assemble as if its in RAM
.section IRQ_NTSC
.section IRQ_NTSC_ENTER
.block IRQ_NTSC
IRQ_ENTER
...code..
.ends
.align size(IRQ_NTSC_ENTER) >? size(IRQ_PAL_ENTER) ; make sure first is in the same sport
IRQ_FIRST
...code...
IRQ_SECOND
...code...
IRQ_THRID
...code...
.bend ; NTSC IRQ
.ends; NTSC IRQ Handler
.here
.logical IRQ_DEST
.section sIRQ_PAL
.section IRQ_PAL_ENTER
.block IRQ_PAL
IRQ_ENTER
...code..
.ends
.align size(IRQ_NTSC_ENTER) >? size(IRQ_PAL_ENTER) ; make sure first is in the same sport
IRQ_FIRST
...code...
IRQ_SECOND
...code...
IRQ_THRID
...code...
.bend
.ends; PAL IRQ Handler
.here
then in the main code you have
IRQ_DEST
.fill size(sIRQ_NTSC) ?> size(sIRQ_PAL)
IRQ_FIRST = IRQ_PAL.IRQ_FIRST
cerror IRQ_NTSC.IRQ_FIRST != IRQ_PAL.IRQ_FIRST, "align filed"
(all of the top of my head so the .section, .block and .logical order might be wrong |
| |
Count Zero
Registered: Jan 2003 Posts: 1821 |
Just like Jackasser and Frantic already mentioned some cartridge related stuff, this is how I tried to do it in Dreamass - unfortunately after the macro call the PC is off by one ("segmentof" still needs to be fixed on Dreamass) :(
However most inportant for us when asking DocBacardi for features was allowing setting up cart banking like:
#segdef "bank0",$8000-$A000, fillup, force, $bb, abs
#segdef "bank1",$8000-$A000, fillup, force, $bb, abs
#outfile @, "bank0", "bank1"
#include "macros.src"
#include "bank0.src"
#include "bank1.src"
That way problems on missing labels when referencing them in another bank are circumvented as Dreamass has access to all labels and something like ".Bankjsr (somerout)" can be handled by a macro with
#if segmentof {subroutine} != BANKNAME
with BANKNAME being (re)-defined in bank0, bank1, etc. to allow comparison in the macro.
Of course the project wont exceed 64kb here so we didnt see a reason for 24bit addresses.
There is little more to it. Looking at the bass tutorials and stuff something similar should be possible for smaller cart projects, hm?
Some current bass features look nice while of course quite a few things are not my cup of tea :) |
| |
Oswald
Registered: Apr 2002 Posts: 5017 |
Quote: @Oswald: Trust me and Krill on this. Only having *= for Eye of the Beholder would have been a disaster. PC and relative PC are just some of many attributes for a segment.
@Sasq: I suggest you take a look at LD65 and how they separate memory and segments as two different entities. It's quite elegant and you should be able to copy those concepts and instead of a separate link file you can have it directly in the source. https://www.cc65.org/doc/ld65-5.html
I trust both of you, I just think assembler functionality like this is often used unecessarily. Segments are not needed to change location of stuff in memory as it was explained here.
Oziphantom's example could be a simple .if PAL then PALIRQ .else NTSCIRQ fex. and the routine needed to be referenced by other code could just use a label.
I would like an assembler that makes code easyer to read and write.
fex in the BadAss example:
!rept 256 { !byte (sin(i*Math.Pi*2/256)+1) * 100 + 24 }
we use sines so often, why cant it be just like FullSine(Length,Max,Min)
(ok can be done through imported functions, that looks really nice in BadAss, but after 30 years of using ".", I cant stomach "!" :) |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Quote: I trust both of you, I just think assembler functionality like this is often used unecessarily. Segments are not needed to change location of stuff in memory as it was explained here.
Oziphantom's example could be a simple .if PAL then PALIRQ .else NTSCIRQ fex. and the routine needed to be referenced by other code could just use a label.
I would like an assembler that makes code easyer to read and write.
fex in the BadAss example:
!rept 256 { !byte (sin(i*Math.Pi*2/256)+1) * 100 + 24 }
we use sines so often, why cant it be just like FullSine(Length,Max,Min)
(ok can be done through imported functions, that looks really nice in BadAss, but after 30 years of using ".", I cant stomach "!" :)
I kinda agree with you. :) Maybe both could be supported. *= for the quick hacks and segments for full blown cart dev. Also agree on . vs ! :D |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Agree with . rather than !, rest not sure. :) |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
I really wanted dots for local labels, as it naturally appends to the last non local label;
copy:
nop
.loop
dex
beq .loop
Here “.loop” just becomes “copy.loop” |
| |
Frantic
Registered: Mar 2003 Posts: 1627 |
@sasq: I'm with you there. Also, I've been using ACME for a whole bunch of years, so the ! notation comes quite naturally by now. :)
Speaking of dots at the start of local labels: It is nice if the assembler can spit out all the labels to a file which is compatible with the VICE command line parameter "-moncommands", e.g. something that looks like:
al C:1004 .PL_SP1_chn01
al C:1022 .PL_SP2_chn01
al C:103f .PL_SETPARAMFLAG_chn01
al C:1043 .PL_PARAM_chn01
al C:1048 .PL_SETNOTEFLAG_chn01
al C:104c .PL_NOTE_chn01
al C:1057 .PL_SP1_chn02
al C:1075 .PL_SP2_chn02
al C:1092 .PL_SETPARAMFLAG_chn02
al C:1096 .PL_PARAM_chn02
al C:109b .PL_SETNOTEFLAG_chn02
al C:109f .PL_NOTE_chn02
al C:10aa .PL_SP1_chn03
al C:10c8 .PL_SP2_chn03
al C:10e5 .PL_SETPARAMFLAG_chn03
al C:10e9 .PL_PARAM_chn03
al C:10ee .PL_SETNOTEFLAG_chn03
Note that all labels have a dot at their beginning here, even if those are not local labels in the original ACME source code. |
| |
oziphantom
Registered: Oct 2014 Posts: 478 |
Quoting OswaldOziphantom's example could be a simple .if PAL then PALIRQ .else NTSCIRQ fex. and the routine needed to be referenced by other code could just use a label.
Please tell me how you can use an if/else to handle the case of having PAL And NTSC stored in ROM in a cart that copies the right version into RAM as the game boots depending upon which hardware it is plugged in to. And how you would have just a label to handle reference by other code. |
| |
Oswald
Registered: Apr 2002 Posts: 5017 |
Ozi, my bad I made wrong assumptions what you are doing there. anyway 6 "." directives seems a lot for some irq assembly...
Sasq, why "." cant e used for directives and label hierarhy too? an algorithm can differentiate if its a . infront of a keyword or after a label? |
| |
chatGPZ
Registered: Dec 2001 Posts: 11108 |
one reason: to do that, you must know all and every keyword that you will ever use in advance, our your sources will randomly break in the future. it also makes the parser much easier and less messy to do. and its more consistent too. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
I can add a '--dot-meta' option that would
* Change prefix of meta to dot
* Require that you not put any meta commands or opcodes in the first column
* Require that you _do_ put assignments in the first column
.local_symbol = 3
.print .local_symbol
lda #.local_symbol
beq .skip
.skip
rts
... but I don't really like it :) |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
This is how it's starting to work now. Needs tweaking for sure but will give a lot of possibilities.
!section "ZP", start=$00, size=$100, flags=NoStore
!section "RAM", start=$801, size=$9f00-$0801, flags=NoStore
;!section "HIRAM", start=$a000, size=$2000, NoStore
!memory "HIRAM",$a000,$2000
!section "DATA", in="RAM", flags=NoStore
!section "main", in="RAM", flags=First {
!section "ZP" {
var0: !ds 1
}
start:
sei
!section "sine" in="DATA" {
sine: !rept 256 { !byte sin(i) }
}
lda sine,x
sta var0
}
; Put pointer to given string or array in XY
!macro xyptr(a) {
!section "DATA" {
.local
!fill a
}
ldx #>.local
ldy #<.local
}
!section "extra", in="HIRAM" {
}
!section "other", in="HIRAM" {
}
Sections
!section <args...> [ { <statements> } ]
Arguments can be positional or named. The arguments are in order:
name - Name of the section to open up or create
start - Start address of the section (load address)
pc - Initial Program counter for this section (runtime address)
flags - Flags for the section
in - Parent section for this section
size - Fixed size of this section
fill - Fill char for this section if not filled up to _size_
If _name_ is not provided, an anonymous section is created.
If _start_ is provided, this creates a new section. It is an error
if a section with this name already exists.
If _start_ is not provided, _name_ must exist or this must be a child
section.
if _pc_ is not provided, it defaults to _start_.
Flags
NoStore: means this section will not be saved.
ReadOnly: means it will be located in ROM
First: means this section should come first in its parent
if _in_ is specified, this section is a child section.
A child section can not be reopened, and does not need to be named.
A child section will start at it's parents start, and will increase
it's parent pc to it's size.
A parent section should not have a different load and runtime address
The parent of a child section _must_ be a NoStore section.
Opening up an existing section and creating a child section is similar,
except in the latter case a new section is created.
`!memory <name> <start> <size>`
Short hand to create a NoStore section that can be the parent of other sections |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Yeah, that feels like a nice approach. With that you could also include the section definitions externally and thus have a structure similar to ca65's link-files. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
Ok now this:
Sections form a tree. Only leaf sections may contain data.
You can not "open up" sections, only add a section to a
parent section.
Root sections usually have fixed size and fixed start.
After an assembly pass, go through the tree and place all sections sequentially in their parent.
Now all sections will have a fixed start address.
If any section was moved, we need to do another pass.
; Root sections
!section "RAM" start=$0000 size=64*1024 NoStore
!section "ZP" start=$00 size=256 NoStore
; Non-leaf section
!section "text" in="RAM" NoStore Last
; Leaf section
!section "code" in="RAM", start=$801 {
; Basic start and such
; Another leaf section, defined recursively
!section in="text" {
name: !text "name"
}
lda name,x
}
|
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
What does NoStore mean in a parent section actually? |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
Well NoStore should be implied in any non-leaf section now.
It means it will not be any data in the section. |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Quote: Well NoStore should be implied in any non-leaf section now.
It means it will not be any data in the section.
Yup, I guessed as much. You really need output directives to root sections also, i.e. to what file they should be emitted. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
Sure, that already works. Although I need to allow file ouput section to overlap I guess. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
Here is the new Section documentation (and other meta commands):
https://github.com/sasq64/bass/blob/new-sections/docs/META.md |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
Beta4 update. Changes include:
* Indexed labels, for accessing labels inside macros and rept statements
* New section system, child sections etc
* Unicode strings
* !check for runtime asserts in 6502 code
* Better error reporting
https://github.com/sasq64/bass/releases |
| |
Frantic
Registered: Mar 2003 Posts: 1627 |
Good work there, sir! I didn't manage to build bass on my MacOS 10.13 system though, due to various errors when compiling. Too bad. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
Yes Apples clang still lacks many C++17 features. I'll see what I can do... |
| |
Boogaloo
Registered: Aug 2019 Posts: 21 |
I'm following this with great interest. I'll try it out soonish. Great work so far!
(And I agree with JackAsser about the clean C++ code.) |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
OK, removed shared_ptr<T[]> which is not supported by OSX yet it seems, should build now. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
@Boogaloo Thanks! |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
Here is an example of indexed labels and unit testing, based
on a snippet from Trash that wanted this feature;
; constant D011VALUE == value in d011
D011VALUE = 0
!macro DrawRasterColors(row) {
!if (row & 7) == (D011VALUE & 7) {
; 23 cycle macro
col[row]:
lda #0 ; 2
sta $d020 ; 6
sta $d021 ; 10
!rept 5 { nop }
bit $ea ; 23
} else {
;63 cycle macro
col[row]:
lda #0 ; 2
sta $d020 ; 6
sta $d021 ; 10
!rept 25 { nop }
bit $ea ; 63
}
}
!section "main", $c000
!rept 6*8 {
DrawRasterColors(i + $40)
}
!test "bad" {
DrawRasterColors(0)
}
!assert tests.bad.cycles == 23
!test "good" {
DrawRasterColors(1)
}
!assert tests.good.cycles == 63
!test "modify" {
lda #9
sta col[$40]+1
lda #8
sta col[$41]+1
}
!assert tests.modify.ram[$c001] == 9
!assert tests.modify.ram[$c010] == 8
|
| |
Oswald
Registered: Apr 2002 Posts: 5017 |
indexed labels is nice, lot of guys need that when creating selfmodded speedcode with macros :) |
| |
Raistlin
Registered: Mar 2007 Posts: 552 |
I was interested in trying out this assembler .. but .. trying to compile the source, I'm getting some problems..
On Windows, CMake is refusing to generate the compile_commands.json file ....
Anyone know what might be needed to get this compiling on Windows? |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
`compile_commands.json` are not needed for building, only for Intellisense features in editors such as Visual Studio Code. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
The `dev` branch is where it's happening BTW.
The following is an example on how you can let the assembler "pre-render" sid register data for faster playback (like the Dane part in Edge of Disgrace):
!script "../lua/sid.lua"
data = load("../data/test.sid")
sid = sid_parse(data)
!section "music", sid.load
music:
!fill sid.data
%{
sid_data = nil
function generate_data()
map_bank_write(0xd4, 1, function(adr, val)
if sid_data then
table.insert(sid_data, adr - 0xd400)
table.insert(sid_data, val)
end
end)
start_run()
init = sym("sid.init")
play = sym("sid.play")
set_a(0)
call(init)
sid_data[#sid_data - 1] = sid_data[#sid_data - 1] | 0x80
for i=1,15*50 do
l = #sid_data
call(play)
if l ~= #sid_data then
sid_data[#sid_data - 1] = sid_data[#sid_data - 1] | 0x80
else
print("Silent frame")
end
end
end
function get_sid_data()
sid_data = {}
generate_data()
result = sid_data
sid_data = nil
return result
end
}%
!text "SID"
sid_data:
!fill get_sid_data()
|
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Quote: The `dev` branch is where it's happening BTW.
The following is an example on how you can let the assembler "pre-render" sid register data for faster playback (like the Dane part in Edge of Disgrace):
!script "../lua/sid.lua"
data = load("../data/test.sid")
sid = sid_parse(data)
!section "music", sid.load
music:
!fill sid.data
%{
sid_data = nil
function generate_data()
map_bank_write(0xd4, 1, function(adr, val)
if sid_data then
table.insert(sid_data, adr - 0xd400)
table.insert(sid_data, val)
end
end)
start_run()
init = sym("sid.init")
play = sym("sid.play")
set_a(0)
call(init)
sid_data[#sid_data - 1] = sid_data[#sid_data - 1] | 0x80
for i=1,15*50 do
l = #sid_data
call(play)
if l ~= #sid_data then
sid_data[#sid_data - 1] = sid_data[#sid_data - 1] | 0x80
else
print("Silent frame")
end
end
end
function get_sid_data()
sid_data = {}
generate_data()
result = sid_data
sid_data = nil
return result
end
}%
!text "SID"
sid_data:
!fill get_sid_data()
Hehe, awesome! |
| |
Mr. SID
Registered: Jan 2003 Posts: 421 |
Yeah, you can do stuff like that with k2asm and Python too. Some of it is useful and other things are masturbatory coding... :) |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
Does k2asm also contain an emulator?
Otherwise I can't see how it can do this. |
| |
Mr. SID
Registered: Jan 2003 Posts: 421 |
No, but you can do pretty much anything in Python these days: https://github.com/docmarionum1/py65emu |
| |
Compyx
Registered: Jan 2005 Posts: 631 |
Hot damn, there's PLA in play*. An actual mnemonic in a shitload of 'code'. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
I have done several improvements now, including a built in "fantasy" text mode 6502 system.
This allows you to prototype program to run directly in the terminal.
Made a short & ugly screencast about it:
https://youtu.be/g1uuhz7Qupw
Manual is also coming along, and the "hardware" of the text mode system is documented at the end:
http://apone.org/bass/ |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Just came across something which might or might not be a sensible and valuable feature for a 6502 assembler:
Interleaving code.
Sometimes, you really want to mix two "unrelated" sources at build time, with various constraints.
E.g., intermingling multispeed/sample-replay with VIC raster stuff and other (branch-less unrolled) code as to minimise context-switching overhead.
Or, putting little NMI handlers into pages which also happen to hold some other (fully branching) code.
The question would be, should an assembler handle that (instead of some higher-level compiler-like thing), and how to formalise/formulate the constraints. |
| |
chatGPZ
Registered: Dec 2001 Posts: 11108 |
support for interleave code with fpp data? yes please :) |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Quoting Groepazsupport for interleave code with fpp data? yes please :) Indeed, mixing executable code with other data is also something you need here and there. :) |
| |
map
Registered: Feb 2002 Posts: 27 |
'Some higher-level compiler-like thing' for this problem seems to be invented it seems.
At least according to Raistlins comment here:
https://csdb.dk/release/?id=195841&show=notes#notes
Quoting name **Raistlin’s Code Generator**
Note that most of Raistlin’s parts used his C++ tool for generating highly optimised/unrolled ASM. It’s able to neatly interleave any “grunt” code (such as bitmap/char/sprite plotting) into accurately timed IRQ code (eg. For border opening). With this, opening borders and such is very simple - allowing the coder to concentrate on optimising the plotting algorithms. Without the tool, we shudder to think how someone might go about achieving some of the things we made for this demo ;-)
Actually I'm wondering if Raistlin would like to share that tool, or at least some more details. :-) |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
See S:T Lars Meeting III - Invite source |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Quoting map'Some higher-level compiler-like thing' for this problem seems to be invented it seems. Why yes, that kind of stuff is something like a d64 image tool, in that every coder sooner or later rolls their own custom implementation (and repeats all the mistakes done by others before). :)
But an open and generic tool for that would be nice, and possibly included with an actual assembler. |
| |
chatGPZ
Registered: Dec 2001 Posts: 11108 |
yes - and to be useful for the generic case it really needs support by the assembler. and its a quite tricky problem to solve too, similar to jackassers recent pack-code-into-banks challenge :) |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Quote: See S:T Lars Meeting III - Invite source
This one tracks register usage and cycles in the speed code in one code base and nops in another timed codebase and merges them while maintaining critical timing. |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Quote: yes - and to be useful for the generic case it really needs support by the assembler. and its a quite tricky problem to solve too, similar to jackassers recent pack-code-into-banks challenge :)
Which worked extremely well. I now have a prelinker scripts that digests all .o and .lib files and actually generates the link file for ld65. A prelinker. Freed up alot of space. |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Quoting JackAsserThis one tracks register usage and cycles in the speed code in one code base and nops in another timed codebase and merges them while maintaining critical timing. Yes, and that kind of stuff would have to be formalised for a generic tool. =) |
| |
Rex
Registered: Sep 2011 Posts: 14 |
For borderline pacman I coded a cycle-based code merger in C for merging cycle-exact raster code (opening the side-borders, displaying 9 sprites per rasterline etc.) with BOB-rendering code (rendering pacman and ghosts plus updating changed tiles).
In my case the raster-code has defined "cycle holes" with number of cycles that has to be spent and the BOB-code is split into tiny "atomic" blocks marked with the number of cycles the block uses. The code merger is short and runs on the c64 itself - it fills up the "cycle holes" with BOB-codes and NOP/BIT$EA to ensure the exact number of cycles is produced.
https://gitlab.com/camelot/kickc/-/blob/master/src/test/kc/comp..
This was the specific type of merging I needed for that effect. Other effects will need other types of code merging. Merging code and data will require another completely different merging strategy.
I am not sure that a general solution for the "merging problem" does exist. It would be interesting to see some ideas on what a general solution could look like. |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Quoting RexIt would be interesting to see some ideas on what a general solution could look like. I propose... a combined superset of various use-cases and their individual strategies. =)
But i guess the "FPP data"/"NMI handlers" problem would be the easiest to solve first. As in, have some fixed gaps in the code to assemble around. |
| |
Raistlin
Registered: Mar 2007 Posts: 552 |
Nice work, Rex - I use something similar in my all-border DYPPs and other such effects ... though I generate everything on PC by having CPP spit out ASM files.
There are some interesting optimizations to be had with this sort of stuff .. for example, where you have a 13 cycle gap and the code you want to insert is just STAs (4 cycles each). Use 12 cycles and you're left with a 1-cycle "problem... so you use 8 cycles instead, "wasting" 4-5. In my code, where possible, I made it such that I could easily waste an additional cycle - so using STA ----, Y for example, ensuring that the indexed write will always cross a page boundary (and therefore eat an extra cycle). Not always possible of course... but well worth it when it is. |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Quoting RaistlinSTA ----, Y for example, ensuring that the indexed write will always cross a page boundary (and therefore eat an extra cycle). So... formalise as "sta label,_y"? (without index or with y.) :)
(And i believe STA mem16,Y has a cycle count independent of page crossings: always 5.) |
| |
Raistlin
Registered: Mar 2007 Posts: 552 |
Sorry, I’m mixing my STA and LDA timings :-) |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Ok, well, thinking a bit further about it, this is one of the few things where a Turing-complete scripting language native to the assembler would come in handy. (Not much of a fan of that otherwise, one hammer vs. world made of nails and so.)
Something where stateful user code can do accounting and control emission of opcodes, etc. |
| |
Rex
Registered: Sep 2011 Posts: 14 |
That is a neat optimization Raistlin!
Another option would be marking some of the logic code blocks as independent to allow the merger to re-organize them to fill the available cycles with as much active code as possible.
One general need is probably the cycle-exact code merging. A solution for that should be able to fill cycle gaps in cycle-exact raster code. This requires the ability to keep track of cycle counts. A general solution should probably also support keeping track of (and handling) register usage. Smart optimizations like what you are proposing would also be nice.
Merging code and data in memory under constraints is probably a different use-case with different requirements. |
| |
chatGPZ
Registered: Dec 2001 Posts: 11108 |
rearranging code in cycle exact code doesnt only require tracking cycle count... you also have to track where in the line you are and consider the dma setup cycles. sounds like fun =) |
| |
Raistlin
Registered: Mar 2007 Posts: 552 |
Just to throw another spanner into this already quite complex system...
Something else that I do on C++ side is that I have some "loose" setup things that need to be done .. so, for example, it's common to want to move the Sprite Y values down every 21 lines. Except of course it doesn't need to be on exact lines - it can be almost anywhere within the existing line of sprites - so you have ~20 raster lines where it could happen for every 21.
I effectively make that a low-importance task - but higher importance than the "slow" task (which is usually something like the blitting of the DYPP or circle scroll).
And... it's good to know what raster-line you're on at each point - when scrolling D800 data, or when updating bitmap data etc, it's good to know whether you're behind or ahead of the raster.
Coding all of this, and keeping within memory budgets, is quite a task ;-) |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Quoting RaistlinCoding all of this, and keeping within memory budgets, is quite a task ;-) Top Coders
1 Raistlin (9.8)
2 Graham (9.8)
3 Crossbow (9.8) That top spot don't come from nothin'. =) |
| |
map
Registered: Feb 2002 Posts: 27 |
Quoting Krill
But an open and generic tool for that would be nice, and possibly included with an actual assembler.
I totally agree that it would be nice to have such a tool. Maybe even nicer to have the possibility to combine it with the assembler of your choice instead of having it build into a certain assembler only. |
| |
Jammer
Registered: Nov 2002 Posts: 1289 |
Looks great from the first look! <3 |
| |
Krill
Registered: Apr 2002 Posts: 2839 |
Quoting mapI totally agree that it would be nice to have such a tool. Maybe even nicer to have the possibility to combine it with the assembler of your choice instead of having it build into a certain assembler only. That's a good point.
Another would be that it can take quite long to generate good solutions to the problem (which is quite often NP-complete or worse), and you'd want to keep intermediate artefacts for speedier rebuilds and retain some manual control over the process. Pretty similar to synthesised netlists in FPGA/PLD stuff. |
| |
Sasq
Registered: Apr 2004 Posts: 155 |
So if you had something like this, how far would that get you? :
!delay <cycles>, <regs_to_preserve>
!merge <section1>, <secition2>, <max_cycles>
Where merge was allowed to insert any code in the delay "slots"
as long as registers where preserved ? |
| |
Zaz
Registered: Mar 2004 Posts: 33 |
Quoting KrillQuoting RaistlinCoding all of this, and keeping within memory budgets, is quite a task ;-) Top Coders
1 Raistlin (9.8)
2 Graham (9.8)
3 Crossbow (9.8) That top spot don't come from nothin'. =)
Well, I did most of the things mentioned and some others 8 years ago, such as https://csdb.dk/release/?id=121570, so the coder rating can't be just from mastering cycle exact code generation ;-)
To be more on topic, I don't think this kind of feature is something for the assembler, the problem is of a different kind. The code generation for this needs to know where all the multiplexed sprites are, as well as the bad lines... |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Quote: Quoting KrillQuoting RaistlinCoding all of this, and keeping within memory budgets, is quite a task ;-) Top Coders
1 Raistlin (9.8)
2 Graham (9.8)
3 Crossbow (9.8) That top spot don't come from nothin'. =)
Well, I did most of the things mentioned and some others 8 years ago, such as https://csdb.dk/release/?id=121570, so the coder rating can't be just from mastering cycle exact code generation ;-)
To be more on topic, I don't think this kind of feature is something for the assembler, the problem is of a different kind. The code generation for this needs to know where all the multiplexed sprites are, as well as the bad lines...
"Well, I did most of the things mentioned and some others 8 years ago, such as https://csdb.dk/release/?id=121570, so the coder rating can't be just from mastering cycle exact code generation ;-)"
It's defined by "food, right now". ;)
@Raistilin: Love u, so no offence! <3 |
| |
JackAsser
Registered: Jun 2002 Posts: 1989 |
Quote: So if you had something like this, how far would that get you? :
!delay <cycles>, <regs_to_preserve>
!merge <section1>, <secition2>, <max_cycles>
Where merge was allowed to insert any code in the delay "slots"
as long as registers where preserved ?
Regs to preserve might be a nice annotation. In my merger I tracked LDA-ish instructions to know if a reg became dirty.
Also elaborate on merge!
Typically you have one code chunk with speed code and another one with raster code with timing critical parts. The speed code should be interleaved with the raster code and maintain 1) raster code timing and 2) register usage on speed code. To ease up constraints one might ignore a) branch penalties 2) char fetch DMA and 3) sprite DMA |
| |
Raistlin
Registered: Mar 2007 Posts: 552 |
This does seem like something that’s not really for the compiler ... a separate tool that spits out ASM files might work. I have that now in a sense - but it’s not a generic solution, I have some C++ helper libraries and then I’ll typically have one C++ file per demo effect that I create using this - that C++ creating all my needed data files, pre-visualisations of the effect, etc etc. Those C++ files can run pretty huge ... my C++ skills aren’t the best - but, well, they’re just for me - and it’s the resultant ASM that matters ;-)
As said, though, I don’t think it’s particularly the merging of code that people might need help with ... it’s also what that 2 branches of code is in the first place - and how to try to reduce register usage in a way that 2 different sets of code can run without lots of register saving and reloading. How will a generalised merge tool work well with that I wonder? |
| |
Raistlin
Registered: Mar 2007 Posts: 552 |
“ the coder rating can't be just from mastering cycle exact code generation ;-)”
The charts on CSDb don’t make a whole lot of sense - and particularly break down when there are lower vote counts. Feel free to downvote me and mould the chart how you think it should be. I don’t take much notice nor care to it tbh. No Crest demos in the top 10, for instance, is a crime against humanity... me being placed higher than HCL and Axis is also utter madness - but unsustainable (wait till there are 20 votes cast). |
| |
Jammer
Registered: Nov 2002 Posts: 1289 |
LOL, I'm in coders' TOP5?! WTF?! I can't even cycle :D |