Skip to content
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

Initialize the Pong sprite data at compilation time, and adjust the translation. #2

Merged
merged 5 commits into from
Oct 26, 2016

Conversation

dr-m
Copy link

@dr-m dr-m commented Oct 1, 2016

Instead of generating code for initializing the sprite data, initialize the sprite data as compile-time constants. Adjust the translation for the x86 code generated by clang version 4.0.0-svn279916-1 (Debian GNU/Linux unstable).

TODO: Generate a Commodore program file, and test this. Add precise instructions or a script for building the examples.

@dr-m
Copy link
Author

dr-m commented Oct 2, 2016

There was an extra level of indirection in my implementation of movl with a 16-bit operand in my 2nd commit, which I removed in the 3rd commit. Instead of referring to label and label+1, we must use #<label and #>label.
I successfully tested the translation by manually adapting the output for the DASM assembler, deleting some directives and converting the .asciz to hexadecimal. I used the starting address 0x900 (SYS2304), which caused the sprites to be located at 0xb00 and 0xb40.

Marko Mäkelä added 2 commits October 6, 2016 17:41
Implement 16-bit shrl (new instruction).

Implement movl with a 16-bit literal value. Add the 6502 ROR instruction.
VIC_II::SPRITE_ALIGNMENT: The MOS 6566/6567/6569 VIC-II expects
sprite data to be aligned at 64 bytes.

VIC_II::SPRITE_STARTING_BANK: Remove.

VIC_II::write_multi_color_pixel(), VIC_II::write_pixel(): Make static.
Write to the specified memory address.

VIC_II::Sprite::Sprite(): Refactored from VIC_II::make_sprite().

VIC_II::enable_sprite(): Take a Sprite reference.

sBall, sBat: Sprite images, declared at global scope.

FIXME: How to ensure that the VIC_II::Sprite addresses do not end up in
the range 0x1000..0x1fff or 0x9000..0x9fff (where the character generator
ROM is overriding RAM)? Any portable alternative to using GCC-style
__attribute__((section("sprites"))) and a linker script?

Note: Declaring the sprite images as static const objects in main()
would cause clang++4.0-svn279916-1 to generate code for initializing them.
So, we will declare the objects in the global scope.

This has been tested on a Commodore 64 with the following steps:

clang++-4.0 -m32 -O3 -std=c++1z -S pong.cpp
x86-to-6502 < pong.s > pong.asm
edit pong.asm to define code start at 0x900 and to adapt the output
invoke some 6502 assembler
SYS2304 to run the output on a Commodore 64
@dr-m
Copy link
Author

dr-m commented Oct 6, 2016

I rebased the fork. The first commit fixes the x86-to-6502 compiler, and the second one updates the example, using the C++11 alignas() attribute in the VIC_II::Sprite declaration.

@dr-m
Copy link
Author

dr-m commented Oct 9, 2016

For what it is worth, I tried writing a constexpr VIC_II::Sprite::Sprite() constructor. I would change the type of VIC_II::Sprite::memory to std::array<uint8_t,63> and then use a variadic template to initialize a std::tuple of 63 uint8_t, and finally convert it to the std::array using some code from here: http://stackoverflow.com/questions/10604794/convert-stdtuple-to-stdarray-c11
The result was not only an insanely long compilation time, but also worse code. A subroutine _GLOBAL__sub_I_… would be generated for initializing the compile-time constant data.

Marko Mäkelä added 3 commits October 9, 2016 18:35
write_multi_color_line(): Replaces write_multi_color_pixel().

write_line(): Replaces write_pixel().

The generated code is not affected by this change.
write_multi_color_line(), write_line(): Remove.

VIC_II::SpriteLine<bool multicolor>: A line of sprite bitmap data.
The constructor converts one line of data at a time.

VIC_II::Sprite<bool multicolor>: An array of SpriteLine.

This change does not affect the generated binary code.
In the assembler code generated by clang++-4.0, the binary data
will be formatted in groups of 3 bytes instead of 3*21 bytes.
This change does not affect the generated code, other than the
assembler labels for the data. The data will still be initialized
at compilation time.
@dr-m
Copy link
Author

dr-m commented Oct 9, 2016

Finally, I figured out that by creating a template<bool multicolor> struct VIC_II::SpriteLine { uint8_t line[3]; } I can convert sprite data one line at a time, either using a 24-digit binary constant for multicolor=false, or using a 12-digit hexadecimal constant for multicolor=true (wasting 2 of each 4 bits). The constexpr SpriteLine constructor would convert the integer constant to 3 bytes. The Sprite<multicolor> would encapsulate an array of 21 SpriteLine<multicolor>.
With this arrangement, the sprite data will be compile-time constant even when using GCC and even when it is declared inside a function. (GCC 6.2.0 failed to compile the whole program; I tested by disabling some parts and specifying -std=c++14.)

@lefticus lefticus merged commit 717b79f into lefticus:master Oct 26, 2016
@lefticus
Copy link
Owner

I've merged the branch, but the #< assembler syntax needs better support if it requires post processing of the assembly output

@dr-m dr-m mentioned this pull request Oct 27, 2016
@dr-m
Copy link
Author

dr-m commented Oct 27, 2016

Thanks for merging this!
The unary < and > operators for extracting the least significant and the most significant byte of a 16-bit word are implemented in all 6502 assemblers that I know of. I guess that this convention was borrowed from the Motorola 6800. The documentation of the TMPx assembler which you apparently used at http://turbo.style64.org/docs/turbo-macro-pro-tmpx-syntax contains an example of passing a 16-bit address to a puts-like system call ($ab1e in the Commodore 64 BASIC interpreter).
I had to postprocess the output, because the assembler that I used (dasm or xa65) did not support .asciz or some directives in the file preamble. (For what it is worth, the Debian archive includes xa65 but neither dasm or TMPx.)
It seems to me that x86-to-6502 should drop the leading $ from labels, because that prefix is equivalent to the C 0x prefix in all 6502 assemblers that I know of. While some 6502 assembler might be tweaked to accept lda #<$_ZL4sBat, other labels, such as ab1e, could be mistaken for a hexadecimal constant.
Perhaps an issue should be opened to introduce a command line switch to x86-to-6502 for choosing the 6502 assembler dialect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants