GithubHelp home page GithubHelp logo

llvm-mos / llvm-mos-sdk Goto Github PK

View Code? Open in Web Editor NEW
264.0 22.0 53.0 14.38 MB

SDK for developing with the llvm-mos compiler

Home Page: https://www.llvm-mos.org

License: Other

CMake 3.31% Assembly 14.51% C 47.39% Awk 0.14% Shell 0.01% C++ 31.33% SourcePawn 0.24% Pascal 0.11% Pawn 0.34% NASL 0.46% Lua 1.24% HTML 0.92%
6502 assembler atari c c64 clang compiler llvm nes cplusplus

llvm-mos-sdk's Introduction

LLVM-MOS SDK

The LLVM-MOS compiler toolchain and platform libraries.

API Reference

Supported platforms

Notable features

  • Broad C99 and C++11 freestanding standards compatibility
  • The high and low-level optimizations expected of a young-ish LLVM backend
    • Fairly good register allocation over A, X, Y, and a field of 16 2-byte zero-page (imaginary) registers
    • The imaginary registers can be placed anywhere and need not be contiguous.
    • The calling convention passes through registers whenever possible.
    • Loop optimizations to select 6502 addressing modes
    • Whole program "static stack" optimization
      • Automatically identifies non-reentrant functions and allocates their frames as static globals
      • Programs without recursion or complex function pointers may not need a soft stack at all.
      • No manual annotations required
    • Whole program zero page allocation
    • Link time inlining and optimization across the whole program
      • Includes SDK libraries. Library calls can be often optimized away completely!
  • Excellent compiler usability
    • Clang's world-class error messages
    • IDE integration through the included custom clangd's Language Server Protocol
    • Straightforward invocations to compile for various targets: mos-c64-clang++ -Os -o game.prg game.cc
  • A small standard library sufficient to provide the above and a few extras
    • Simple printf
    • Simple malloc/free
    • exit, _Exit, and atexit
  • An ELF file format implementation
    • All the usual POSIX tools for working with object files: readelf, nm, etc.
    • A GAS-compatible assembler for the 6502 with a complete macro system
  • A lld linker implementation for the 6502
    • All the usual trimmings of an ELF lld backend
      • Link-time garbage collection
      • Symbol map exports
      • Linker scripts
      • GCC ld compatibility

Notably missing features

  • A hosted C with all the standard library bells and whistles.
  • C++ Exceptions

Getting started

Download

First, download and extract the archive for your platform.

(macOS Only) Remove Quarantine

On macOS, downloading a package automatically applies a quarantine to the file. This will also affect the extracted binaries from the package, which causes GateKeeper to prevent them from running. To avoid this, run the following on the downloaded package before extracting it:

$ xattr -d com.apple.quarantine llvm-mos-macos.tar.xz

(Optional) Add LLVM-MOS to PATH

If you like, you can add LLVM-MOS to your path. This will make accessing LLVM-MOS from the command line easier.

WARNING: Don't install LLVM-MOS into your path if you already have LLVM/Clang installed. LLVM-MOS conflicts with other LLVM/Clang installations.

POSIX

Add the following line to your shell profile (~/.bashrc, ~/.zshrc, etc...):

export PATH=$PATH:<arbitrary-install-directory>/bin

To work with CMake-enabled IDEs, it may also need to be added to your desktop profile (~/.gnomerc, KDE, etc...).

Windows

rundll32.exe sysdm.cpl,EditEnvironmentVariables
# Edit "Path" user variable
# Add entry for "<arbitrary-install-directory>\bin"

Afterwards, new shells will have direct access to LLVM-MOS.

Compile an Example

Once installed, you can compile a sample program with a direct command. You will need to prefix clang (or clang++) with a specific MOS platform provided by the SDK. This will ensure clang loads the correct configuration to generate executables and libraries for that target.

Platform Variant Command
Atari 2600 4K mos-atari2600-4k-clang
Atari 2600 TigerVision 3E mos-atari2600-3e-clang
Atari 5200 Super Cart mos-atari5200-supercart-clang
Atari 8-bit DOS mos-atari8-dos-clang
Atari 8-bit MegaCart cartridge mos-atari8-cart-megacart-clang
Atari 8-bit Standard cartridge mos-atari8-cart-std-clang
Atari 8-bit XEGS cartridge mos-atari8-cart-xegs-clang
Atari Lynx BLL executable mos-lynx-bll-clang
Ben Eater's 6502 Breadboard Kit - mos-eater-clang
Commander X16 - mos-cx16-clang
Commodore 64 mos-c64-clang
Commodore 128 mos-c128-clang
Commodore PET mos-pet-clang
Commodore VIC-20 mos-vic20-clang
CP/M-65 - mos-cpm65-clang
Dodo 6502 Game System - mos-dodo-clang
MEGA65 - mos-mega65-clang
NES Action53 mapper mos-nes-action53-clang
NES CNROM mapper mos-nes-cnrom-clang
NES GTROM mapper mos-nes-gtrom-clang
NES MMC1 mapper mos-nes-mmc1-clang
NES MMC3 mapper mos-nes-mmc3-clang
NES NROM mapper mos-nes-nrom-clang
NES UNROM mapper mos-nes-unrom-clang
NES UNROM-512 mapper mos-nes-unrom-512-clang
Ohio Scientific Challenger 1P - mos-osi-c1p-clang
OLIMEX Neo6502 - mos-neo6502-clang
Picocomputer 6502 - mos-rp6502-clang
PC Engine Standard mos-pce-clang
PC Engine CD mos-pce-cd-clang
RPC/8e (RedPower 2) - mos-rpc8e-clang
Watara Supervision - mos-supervision-clang
6502 simulator - mos-sim-clang
$ cat <install_dir>/examples/hello-putchar.c
#include <stdio.h>

int main(void) {
  const char *cur = "HELLO, PUTCHAR!\n";
  while (*cur)
    putchar(*cur++);
  return 0;
}

$ mos-c64-clang -Os -o hello.prg <install_dir>/examples/hello-putchar.c

$ llvm-objdump -d hello.elf
...

$ mos-c64-clang -Os -o hello.s -Wl,--lto-emit-asm <install_dir>/examples/hello-putchar.c

Developing for 6502 with CMake

A CMake package and toolchain file are provided to make targeting MOS from CMake easy.

Create a new source directory with a CMakeLists.txt like the following where LLVM_MOS_PLATFORM is set to any platform supported by the SDK:

cmake_minimum_required(VERSION 3.18)
set(LLVM_MOS_PLATFORM c64)
find_package(llvm-mos-sdk REQUIRED)
project(llvm-mos-sdk-foo)
add_executable(foo foo.c)

Note: If LLVM-MOS was not added to PATH, set -DCMAKE_PREFIX_PATH=<arbitrary-install-directory> to match the install prefix of LLVM-MOS so find_package will work correctly.

Development

To modify the SDK, you'll need to be able to build it yourself. This requires a working LLVM-MOS compiler, which can be found in the current SDK release. Accordingly, make sure to install the SDK first using the instructions above.

Install ninja

For the steps below to work as-is, you'll need to install Ninja, the fast, parallel build tool favored by LLVM developers. Instructions for your platform will vary; see https://ninja-build.org/.

Alternatively, you can set -G "Makefile" in each CMake command to use standard UNIX Makefiles, or you can substitute any other CMake-supported generator. Your compile times may take a hit, and LLVM is already very slow to build, so Ninja is highly recommended.

Build and Install LLVM-MOS-SDK

Set CMAKE_INSTALL_PREFIX below to the LLVM-MOS installation directory. This will replace the SDK portion of the installation with the newly built artifacts on ninja install.

$ git clone https://github.com/llvm-mos/llvm-mos-sdk.git
$ cd llvm-mos-sdk
$ mkdir build
$ cd build
$ cmake -G "Ninja" -DCMAKE_INSTALL_PREFIX=<sdk-install-directory> ..
$ ninja install

The complete SDK will now be present in the install prefix.

Run Unit Tests

NES (legacy Mesen Mono version tests)

Install Mesen-X and its dependencies.

Set the MESEN_DIR environment variable to the folder containing the Mesen.exe executable before running CMake for the first time. Copy test/mesen_settings.xml to this folder.

Libretro tests (Atari 2600, etc.)

Install emutest (requires Go 1.21):

$ go install github.com/kivutar/emutest@latest

Make sure $GOBIN (usually ~/go/bin) is included in your PATH environment variable so that CMake can find the binary, or set the EMUTEST_DIR environment variable to point to this directory before running cmake -G for the first time.

You can verify emutest with emutest -h on the command-line.

You should see -T Test runner mode (script must call os.exit) in the output.

Build Libretro cores for desired target(s):

Copy the output Libretro core library files (they have extensions .so | .dylib | .dll) to a shared directory, maybe $HOME/libretro. Set the LIBRETRO_CORES_DIR environment variable to this folder before running cmake -G for the first time.

Run a test project

$ ninja test            # run all test projects
$ ninja test-nes-nrom   # run a specific test project, e.g. nes-nrom

llvm-mos-sdk's People

Contributors

andrew900460 avatar asiekierka avatar atn34 avatar bcampbell avatar bcr avatar cnelson20 avatar cogwheel avatar cwedgwood avatar davidgiven avatar gurcei avatar jackoalan avatar jroweboy avatar karunski avatar mlund avatar mrk-its avatar mysterymath avatar oskarlinde avatar pfusik avatar rumbledethumps avatar rweather avatar schlupa avatar sehugg avatar smuehlst avatar toboterxp avatar williamw4096 avatar xarklabs avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

llvm-mos-sdk's Issues

dodo system calls should use __attribute__((leaf)) where appropriate

Dodo system calls that cannot call back to the main program should be marked with __attribute__((leaf)) in their header. Otherwise, the compiler will be forced to pemissive their possible behavior and assume that they can call any global function. This can unnecessarily disable static stack and zero page allocation.

Unable to embed character ROM for NES.

I've written a simple test program for the NES and I can build and link it fine until I try to include a character rom.

I added a .s file with the following:

.section .chr_rom
  .incbin "tileset.chr"

and included it as part of the build script:

./llvm-mos/bin/mos-nes-nrom-128-clang -Os -o climbr.nes main.c chars.s

However the linker gives the following error:

ld.lld: warning: ignoring memory region assignment for non-allocatable section '.chr_rom'
ld.lld: warning: ignoring memory region assignment for non-allocatable section '.vector'

And doesn't include either the character rom or the starting vector.

What am I doing wrong?

Port nesdoug tutorial

I asked around on the NesDev discord, and the scuttlebut seems to be that the nesdoug/neslib library, due to the popularity of the nesdoug C tutorial, form a de-facto standard library for NES development in C.

We should bring the nesdoug/neslib libraries into the SDK if it's feasible and port the tutorial stages so that they work with llvm-mos. This would make it easy to get started with llvm-mos NES development.

Rebuild examples when platform changes

While the recent SDK refactoring helped with the NES ports, it caused the examples to no longer automatically rebuild when the underlying platform changes. This is because the examples refer to the platform only through the config files, which are invisible to CMake.

Given that this is akin to if the underlying C library changed in a regular CMake build, we should probably handle this outside of the example CMake config. We can create a stub file that regenerates each time any library or link.ld changes for a given target (or if there's a bleed-through from a parent target). Then, we can trigger a clean build of the corresponding example target whenever this stub file changes. Probably.

Write NES SDK tests using Mesen testrunner.

Currently, the SDK is tested using the examples. This was good for a smoke test, but the logic in the SDK is growing more complex, and it would be a good idea to have a more formal structure for tests.

We'd want to have tests that certain examples successfully compile, and that other examples do not. We'd also want to make assertions about symbol values, and perhaps certain sections of the resulting binaries.

Place to ask questions about the compiler/assembler?

Right off the bat, I know this is definately not the place to ask such things, and I will delete this as soon as possible.

But I would like to know if there is a place to ask questions about nuances with the compiler/assembler, because I am also fairly new to the llvm-compiler system. (I have not seen any info on the website of good places to go to talk about the compiler)

Briefly, I am trying to write an inline assembly function for reading controller info for the NES. I am getting issues with how it tries to handle asm lables. I could do:

asm("myLabel:")
// some other stuff
asm("bcc myLabel")

This works fine, but then if I try to call the function, it gets a compiler error due to the lable being in 2 places. To be clear, I am actually using Compiler Explorer to test all this, and I am gettig the error on there.

Also, I've been trying to follow the guides on the llvm-mos.org website for doing inline assembly, but I am still having another issue related to this function I'm talking about not actually returning anything. Due to how the "ReadJoypad" function works, it never needs to access any variables, but it does need to store the result in a variable. And I'm not sure If I understood what I'm supposed to tell the compiler to give the correct output.

PET target

I am interested in adding support for the Commodore PET as a target. I have managed to get all of the example programs to compile and run for a 32k PET, mostly by copying over code from the C64 config and adjusting for the PET's memory map and kernel.

Doing this has already taken me beyond the "Porting" and "Extending SDK" parts of the wiki and hence I am not sure how to test that everything is correctly configured. Here is what I have added so far:

  • link.ld defining usable RAM space and stack location. Based on the Commodore link file.
  • kernal.S exporting some of the definitions from cbm_kernal.inc
  • basic-header.S defines the basic SYS command which runs the program; this is identical to the one for the C64
  • pet.inc definitions taken from cc65, akin to c64.inc
  • added relevant cmake stuff as per the "Extending SDK" wiki page

Provide alternate configurations for NES NROM and MMC1 mappers

Even within a single NES mapper, there are a lot of different ways to configure a board. The more sophisticated mappers offer multiple independent axes of configurability, which produces a combinatorially large space. My previous plan was to offer on NES target per configuration, but it's clear that this doesn't scale to the more advanced mappers.

Instead, a new plan is to provide one SDK target per mapper, and to use symbol values to specify the other axes of configuration. These symbol values would determine both the values of the iNES 2.0 header fields and the layout in memory and ROM of various sections.

To prove the approach, an exhaustive configuration system should be created for each possible way to configure NROM and MMC1. If these two mappers cannot be covered exhaustively, then the more complex ones definitely can't, and we'll need to better deliniate what the SDK can support vs what the user would need to write themselves.

MEGA65 target

I have set up a small project to use llvm-mos-sdk with rust with the aim to run on the Mega65 computer. This has a C64 compatibility mode (go 64 a la C128) where the test program runs fine. I wonder what is required to make a true Mega65 target? I'm aware that the mos-llvm project currently doesn't generate CSG4510 instructions (based on 65CE02), but that's perhaps not initially a problem as it's 6502 compatible. I have started a fork with what I think are the structural parts, but so far it's merely a clone of the C64 target. Any input would be highly appreciated.

How to build the SDK with cmake on Windows?

I downloaded the most recent llvm-mos build from https://github.com/llvm-mos/llvm-mos/releases/tag/llvm-mos-windows-main, and I tried to adapt the Linux instructions to build the SDK to Windows. But this fails quickly:

E:\Users\stm\Documents\GitHub\llvm-mos-sdk [winbuild]> & "C:\Program Files\CMake\bin\cmake.exe" -DLLVM_MOS=E:/Users/stm/local/llvm-mos/bin -G Ninja -B build
-- The C compiler identification is unknown
-- The CXX compiler identification is unknown
-- The ASM compiler identification is unknown
-- Didn't find assembler
CMake Error at CMakeLists.txt:3 (project):
  No CMAKE_C_COMPILER could be found.

  Tell CMake where to find the compiler by setting either the environment
  variable "CC" or the CMake cache entry CMAKE_C_COMPILER to the full path to
  the compiler, or to the compiler name if it is in the PATH.


CMake Error at CMakeLists.txt:3 (project):
  No CMAKE_CXX_COMPILER could be found.

  Tell CMake where to find the compiler by setting either the environment
  variable "CXX" or the CMake cache entry CMAKE_CXX_COMPILER to the full path
  to the compiler, or to the compiler name if it is in the PATH.


CMake Error at CMakeLists.txt:3 (project):
  No CMAKE_ASM_COMPILER could be found.

  Tell CMake where to find the compiler by setting either the environment
  variable "ASM" or the CMake cache entry CMAKE_ASM_COMPILER to the full path
  to the compiler, or to the compiler name if it is in the PATH.


-- Warning: Did not find file Compiler/-ASM
-- Configuring incomplete, errors occurred!
See also "E:/Users/stm/Documents/GitHub/llvm-mos-sdk/build/CMakeFiles/CMakeOutput.log".
See also "E:/Users/stm/Documents/GitHub/llvm-mos-sdk/build/CMakeFiles/CMakeError.log".

I'm not very experienced with CMake, but it looks to me like it is not specified that this is a cross-compilation, and therefore CMake is looking for a C compiler for the current platform, e.g. for a Windows C compiler here.

Rewrite portions of the nesdoug/neslib library in C

Select sections of the nesdoug/neslib libraries should be rewritten in C so they can be inlined at point of use. A lot of the functionality boils down to thin accessors and mutators over library state, so specializing such code should increase performance.

This should only be done after there's some kind of testing apparatus around the nesdoug examples, at least semi-automated.

Port cc65 hardware registers for supported platforms

We should at the very least have support for all the hardware and OS registers for each supported target platform; that's pretty intrinsic to being a good freestanding compiler for a given platform.

It's also generally a benefit to be cc65-compatible wherever possible; this lowers transition and porting costs.

Accordingly, we should try to port over the cc65 register definitions for the platforms currently in the SDK.

Add the Apple II family as a target

I recently came across this project, and I was interested in using it to write code for my Apple //e. There is a demo of LLVM-MOS code running on the Apple //e on the website, but there aren't any target triples for it. Do you think we could add that to the list of platforms?

Ideally, I'd be interested in the following variations:

  • DOS 3.3 binary program
  • PRODOS system program
  • A variation for both that makes the HIRES graphics pages available (start program at $6000, use $800-$1FFF as a noinit space and soft stack, add the correct PRODOS stub code to relocate the program)

I'll note that I did attempt to write my own target definition inside my own project (using the instructions from the Embednomicon and basing it off the existing mos-unknown-none target), but my linker script did not appear to have access to any of the includes, including c.ld, imag-regs.ld, and crt0.S/crt0/crt. Here is what I have so far:

mos-apple-iie-none.json:

{
    "arch": "mos",
    "atomic-cas": false,
    "cpu": "mos6502",
    "data-layout": "e-m:e-p:16:8-i16:8-i32:8-i64:8-f32:8-f64:8-a:8-Fi8-n8",
    "disable-redzone": true,
    "linker": "mos-clang",
    "llvm-args": [
      "--force-precise-rotation-cost",
      "--jump-inst-cost=6",
      "--force-loop-cold-block",
      "--phi-node-folding-threshold=0",
      "--two-entry-phi-node-folding-threshold=0",
      "--align-large-globals=false",
      "--disable-spill-hoist"
    ],
    "llvm-target": "mos-unknown-none",
    "max-atomic-width": 8,
    "min-atomic-width": 8,
    "no-default-libraries": false,
    "panic-strategy": "abort",
    "requires-lto": true,
    "singlethread": true,
    "supports-stack-protector": false,
    "target-c-int-width": "16",
    "target-pointer-width": "16",
    "trap-unreachable": false,
    "vendor": "apple"
}

appleiielinker.ld (which I reference using the -Clink-arg=-Tappleiielinker.ld argument in config.toml):

/*
 * Apple //e linker script
 */

/* Available RAM goes from 0x0800 to 0x9600, skipping 0x2000-0x5fff
 * for HIRES graphics. The program will be loaded at 0x6000,
 * and the 6K below HIRES will be reserved for the soft stack
 */
MEMORY {
    ram (rw) : ORIGIN = 0x6000, LENGTH = 0x35ff
}

__rc0 = 0x0002;
/* INCLUDE imag-regs.ld */
__rc1 = __rc0 + 1;
PROVIDE(__rc2 = __rc1 + 1);
__rc3 = __rc2 + 1;
PROVIDE(__rc4 = __rc3 + 1);
__rc5 = __rc4 + 1;
PROVIDE(__rc6 = __rc5 + 1);
__rc7 = __rc6 + 1;
PROVIDE(__rc8 = __rc7 + 1);
__rc9 = __rc8 + 1;
PROVIDE(__rc10 = __rc9 + 1);
__rc11 = __rc10 + 1;
PROVIDE(__rc12 = __rc11 + 1);
__rc13 = __rc12 + 1;
PROVIDE(__rc14 = __rc13 + 1);
__rc15 = __rc14 + 1;
PROVIDE(__rc16 = __rc15 + 1);
__rc17 = __rc16 + 1;
PROVIDE(__rc18 = __rc17 + 1);
__rc19 = __rc18 + 1;
PROVIDE(__rc20 = __rc19 + 1);
__rc21 = __rc20 + 1;
PROVIDE(__rc22 = __rc21 + 1);
__rc23 = __rc22 + 1;
PROVIDE(__rc24 = __rc23 + 1);
__rc25 = __rc24 + 1;
PROVIDE(__rc26 = __rc25 + 1);
__rc27 = __rc26 + 1;
PROVIDE(__rc28 = __rc27 + 1);
__rc29 = __rc28 + 1;
PROVIDE(__rc30 = __rc29 + 1);
__rc31 = __rc30 + 1;

ASSERT(__rc31 == 0x0021, "Inconsistent zero page map.")

MEMORY { zp : ORIGIN = __rc31 + 1, LENGTH = 0x90 - (__rc31 + 1) }

SECTIONS {
    /* INCLUDE c.ld */
    .zp.data : { 
        __zp_data_start = .;
        *(.zp.data .zp.data.* .zp.rodata .zp.rodata.*) 
    } >zp AT>ram
    __zp_data_load_start = LOADADDR(.zp.data);
    __zp_data_size = SIZEOF(.zp.data);
    .zp.bss (NOLOAD) : { 
        __zp_bss_start = .;
        *(.zp.bss .zp.bss.*) 
    } >zp
    __zp_bss_size = SIZEOF(.zp.bss);
    .zp (NOLOAD) : { *(.zp .zp.*) } >zp
    .text : {
        /* A mechanism for dynamically building an _init script. */
        _init = .;
        _start = .;
        *(SORT_BY_INIT_PRIORITY(.init.* .init))
        *(.call_main)
        *(.after_main)

        /* A mechanism for dynamically building a _fini script. */
        _fini = .;
        *(SORT_BY_INIT_PRIORITY(.fini.* .fini))
        *(.fini_rts)

        *(.text .text.*)

        /* A sorted list of initialization function pointers. Used for GCC
        * constructor attribute and C++ global constructors. */
        __init_array_start = .;
        KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.* .init_array)))
        __init_array_end = .;

        /* A sorted list of finalization function pointers. Used for GCC destructor
        * attribute. */
        __fini_array_start = .;
        KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.* .fini_array)))
        __fini_array_end = .;
    }
    .rodata : { *(.rodata .rodata.*) }
    .data : { __data_start = .;
        *(.data .data.*)
        __data_end = .; 
    }
    __data_load_start = LOADADDR(.data);
    __data_size = SIZEOF(.data);
    .bss : { __bss_start = .;
        *(.bss .bss.* COMMON)
        __bss_end = .;
    }
    __bss_size = SIZEOF(.bss);
    .noinit (NOLOAD) : { 
        *(.noinit .noinit.*)
        __heap_start = .;
    }
}

/* 
 * Set the operand stack to the 6K memory region below HIRES
 */
__stack = 0x1FFF;

OUTPUT_FORMAT {
    TRIM(ram)
}

And the errors I get when compiling rust-hello-world-mos with this target triple:

error: linking with `mos-clang` failed: exit status: 1
  |
  = note: LC_ALL="C" PATH="/usr/local/rust-mos/lib/rustlib/x86_64-unknown-linux-gnu/bin:/vscode/vscode-server/bin/linux-x64/e2816fe719a4026ffa1ee0189dc89bdfdbafb164/bin/remote-cli:/home/mos/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" VSLANG="1033" "mos-clang" "/workspaces/rust-mos-hello-world/target/mos-apple-iie-none/debug/deps/rust_mos_hello_world-9618fd27fc545d4f.ufmt_stdio-e29ce7fa101f2a20.ufmt_stdio.76c6debd-cgu.0.rcgu.o.rcgu.o" "-Wl,--as-needed" "-L" "/workspaces/rust-mos-hello-world/target/mos-apple-iie-none/debug/deps" "-L" "/workspaces/rust-mos-hello-world/target/debug/deps" "-L" "/usr/local/rust-mos/lib/rustlib/mos-apple-iie-none/lib" "-Wl,-Bstatic" "/workspaces/rust-mos-hello-world/target/mos-apple-iie-none/debug/deps/libcompiler_builtins-cae85a8e15dfddde.rlib" "-Wl,-Bdynamic" "-Wl,--eh-frame-hdr" "-Wl,-znoexecstack" "-L" "/usr/local/rust-mos/lib/rustlib/mos-apple-iie-none/lib" "-o" "/workspaces/rust-mos-hello-world/target/mos-apple-iie-none/debug/deps/rust_mos_hello_world-9618fd27fc545d4f" "-Wl,--gc-sections" "-no-pie" "-Wl,-O1" "-Tappleiielinker.ld"
  = note: clang-16: warning: argument unused during compilation: '-no-pie' [-Wunused-command-line-argument]
          ld.lld: warning: /workspaces/rust-mos-hello-world/target/mos-apple-iie-none/debug/deps/libcompiler_builtins-cae85a8e15dfddde.rlib: archive member 'lib.rmeta' is neither ET_REL nor LLVM bitcode
          ld.lld: error: unable to find library -l:crt0.o
          ld.lld: error: unable to find library -lcrt0
          ld.lld: error: unable to find library -lcrt
          ld.lld: error: unable to find library -lc
          clang-16: error: ld.lld command failed with exit code 1 (use -v to see invocation)

"Common ELF" target

Basically the common target but with a linker script that outputs a relocatable ELF file. May be useful for custom 8-bit OSes, patching stuff(ROMs, disk images, etc.), or some other stuff.

Unexpected behavior of CBM KERNAL functions

For the snippet below, I get different behavior with cc65 and clang using the VICE emulator. I suspect it might be the calling conventions for the mos-platform/commodore/*.s functions (setnam, setlfs, chkin). Merely calling chkin causes the screen to scroll on clang. The very useful cbm functions were introduced in #86 and #87. Ping @cnelson20.

// cl65 cbm_open.c -o open-cc65.prg --target c64
// mos-c64-clang cbm_open.c -o open-clang.prg
#include <cbm.h>
#include <stdio.h>

const char* filename = "SOMEFILE";

int main() {
    unsigned char s1, s2;
    unsigned char lfn = 8;
    unsigned char device = 8;
    unsigned char secondary_addr = 0;

    cbm_k_setlfs(lfn, device, secondary_addr);
    cbm_k_setnam(filename);

    s1 = cbm_k_open(); // Expected = 0; Clang = 199
    //s2 = cbm_k_chkin(lfn); // Expected = 0; on clang this causes the screen to scroll
    printf("open status = %d\n", s1);
    return 0;
}

MMC1 32K banking

Now that the LMAs and VMAs have been reworked in the NES targets, it should be possible to directly support MMC1's 32KiB banking mode. The approaches used should also be generally applicable to other mappers without a fixed PRG-ROM bank, which improves the generality of the SDK.

Support more of the C++11 library

You may be familiar with the CppCon 2016 talk "Rich Code for Tiny Computers: A Simple Commodore 64 Game in C++17".

The "compiler" implementation was a hack: letting clang translate to IA-32, and then translating a very small subset of IA-32 code to 6502 (while wrongly assuming that IA-32 is an 8-bit processor). Not all registers were supported, nor were function calls, if I remember correctly. The main point was to demonstrate that modern C++ allows zero-overhead abstraction, that is, lots of things can be evaluated at compilation time.

In the video, there was one problem that my very first pull request lefticus/6502-cpp#2 addressed, by implementing constexpr constructors for sprite data.

It would be great if the pong.cpp could be compiled on llvm-mos-sdk with minimal source code modification. Currently, the compilation would fail like this:

pong.cc:2:10: fatal error: 'array' file not found

The std::array is only used for something during compilation time; in the object code, you would only see some immediate loads followed by sta, stx or sty to some VIC-II registers between 0xd020 and 0xd02e.

  vic.border()         = vic.nearest_color<128,128,128>(colors).num; // 50% grey
  vic.background()     = vic.nearest_color<0,0,0>(colors).num;       // black
  vic.sprite_1_color() = vic.nearest_color<255,0,0>(colors).num;     // red
  vic.sprite_2_color() = vic.nearest_color<0,255,0>(colors).num;     // green

Use RICOH cpu for NES

The NES CPU should be specially marked in the SDK to prevent the emission of decimal mode instructions in interrupt prologues.

Allocating variables to specific locations in ram.

In the NES, OAM (sprite) data can be DMAed into the PPU by setting the OAMDMA register to the most significant byte ($XX) of an address and then the CPU will DMA into the PPU data from $XX00-$XXFF.

This means that if you have this array in your code then it must be aligned with $XX00 in ram.

Is it possible to preallocate this memory somehow at a particular location and then reference it in C? I assume it would be done in the linker with a section but I don't know how to do that.

Modified clang.cfg files don't get picked up by the build system

If I modify a clang.cfg file, then try to do a build/install, the modified file isn't installed. This can lead to some very strange results!

$ cat mos-platform/cpm65/clang.cfg 
-D__CPM65__
-Wl,-emit-relocs
-fpost-link-tool=elftocpm65

$ cat /opt/pkg/llvm-mos/bin/mos-cpm65.cfg
...skipped...
-D__CPM65__
-Wl,-emit-relocs
-fpost-link-tool=elftocpm65
...skipped

$ echo "test" >> mos-platform/cpm65/clang.cfg 
$ ninja -C build install
...skipped...

$ cat /opt/pkg/llvm-mos/bin/mos-cpm65.cfg
...skipped...
-D__CPM65__
-Wl,-emit-relocs
-fpost-link-tool=elftocpm65
...skipped...

This is using cmake configured like this:

cd build && cmake -G "Ninja" -DCMAKE_INSTALL_PREFIX=/opt/pkg/llvm-mos ..

I'm using more-or-less head of repo (github says I'm 17 commits behind, but none of those look relevant).

Unable to generate a working .prg (under Windows)

Hi,

I'm trying to use the sdk (I've downloaded the binary for the llvm-mos and I've used ninja to compile the sdk) under Windows, but I have the following error:

C:\AGPX\Documenti\llvm-mos-sdk>..\llvm-mos\bin\clang.exe -v --config build/commodore/64.cfg -Os -o hello.prg examples/hello_putchar.c
clang version 13.0.0 (https://www.github.com/llvm-mos/llvm-mos.git bb89e37b82ba48e169b47e4fcfd46c4740b4dfeb)
Target: mos
Thread model: posix
InstalledDir: C:\AGPX\Documenti\llvm-mos-sdk\..\llvm-mos\bin
Configuration file: C:\AGPX\Documenti\llvm-mos-sdk\build\commodore\64.cfg
 "C:\\AGPX\\Documenti\\llvm-mos\\bin\\clang.exe" -cc1 -triple mos -emit-llvm-bc -flto -flto-unit -disable-free -disable-llvm-verifier -discard-value-names -main-file-name hello_putchar.c -mrelocation-model static -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -nostdsysteminc -mllvm -force-precise-rotation-cost -mllvm -jump-inst-cost=6 -mllvm -phi-node-folding-threshold=0 -mllvm -two-entry-phi-node-folding-threshold=0 -mllvm -align-large-globals=false -mllvm -disable-spill-hoist -debugger-tuning=gdb -v "-fcoverage-compilation-dir=C:\\AGPX\\Documenti\\llvm-mos-sdk" -resource-dir "C:\\AGPX\\Documenti\\llvm-mos\\lib\\clang\\13.0.0" -isystem C:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/include -isystem C:/AGPX/Documenti/llvm-mos-sdk/build/common/include -internal-isystem "C:\\AGPX\\Documenti\\llvm-mos\\lib\\clang\\13.0.0\\include" -Os "-fdebug-compilation-dir=C:\\AGPX\\Documenti\\llvm-mos-sdk" -ferror-limit 19 -fmessage-length=120 -fno-signed-char -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -mllvm -num-imag-ptrs=71 -faddrsig -o "C:\\Users\\AGPX\\AppData\\Local\\Temp\\hello_putchar-04578e.o" -x c examples/hello_putchar.c
clang -cc1 version 13.0.0 based upon LLVM 13.0.0git default target x86_64-pc-windows-msvc
ignoring duplicate directory "C:\AGPX\Documenti\llvm-mos\lib\clang\13.0.0\include"
#include "..." search starts here:
#include <...> search starts here:
 C:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/include
 C:/AGPX/Documenti/llvm-mos-sdk/build/common/include
 C:\AGPX\Documenti\llvm-mos\lib\clang\13.0.0\include
End of search list.
 "C:\\AGPX\\Documenti\\llvm-mos-sdk\\..\\llvm-mos\\bin\\ld.lld" -mllvm -num-imag-ptrs=71 --gc-sections "C:\\Users\\AGPX\\AppData\\Local\\Temp\\hello_putchar-04578e.o" -plugin-opt=O2 -mllvm -force-precise-rotation-cost -mllvm -jump-inst-cost=6 -mllvm -phi-node-folding-threshold=0 -mllvm -two-entry-phi-node-folding-threshold=0 -mllvm -align-large-globals=false -mllvm -disable-spill-hoist -LC:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/ldscripts -LC:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/lib -T C:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/ldscripts/link.ld -LC:/AGPX/Documenti/llvm-mos-sdk/build/common/ldscripts -LC:/AGPX/Documenti/llvm-mos-sdk/build/common/lib -l:crt0.o -lcrt -lc -o hello.prg
ld.lld: error: unable to find library -lcrt
ld.lld: error: unable to find library -lc
clang: error: ld.lld command failed with exit code 1 (use -v to see invocation)

I discovered that to make it able to found the crt and c library, I have to rename the crt.lib and c.lib (in the 'C:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/lib' directory) to 'libcrt.a' and 'libc.a', but then I have the following error:

C:\AGPX\Documenti\llvm-mos-sdk>..\llvm-mos\bin\clang.exe -v --config build/commodore/64.cfg -Os -o hello.prg examples/hello_putchar.c
clang version 13.0.0 (https://www.github.com/llvm-mos/llvm-mos.git bb89e37b82ba48e169b47e4fcfd46c4740b4dfeb)
Target: mos
Thread model: posix
InstalledDir: C:\AGPX\Documenti\llvm-mos-sdk\..\llvm-mos\bin
Configuration file: C:\AGPX\Documenti\llvm-mos-sdk\build\commodore\64.cfg
 "C:\\AGPX\\Documenti\\llvm-mos\\bin\\clang.exe" -cc1 -triple mos -emit-llvm-bc -flto -flto-unit -disable-free -disable-llvm-verifier -discard-value-names -main-file-name hello_putchar.c -mrelocation-model static -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -nostdsysteminc -mllvm -force-precise-rotation-cost -mllvm -jump-inst-cost=6 -mllvm -phi-node-folding-threshold=0 -mllvm -two-entry-phi-node-folding-threshold=0 -mllvm -align-large-globals=false -mllvm -disable-spill-hoist -debugger-tuning=gdb -v "-fcoverage-compilation-dir=C:\\AGPX\\Documenti\\llvm-mos-sdk" -resource-dir "C:\\AGPX\\Documenti\\llvm-mos\\lib\\clang\\13.0.0" -isystem C:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/include -isystem C:/AGPX/Documenti/llvm-mos-sdk/build/common/include -internal-isystem "C:\\AGPX\\Documenti\\llvm-mos\\lib\\clang\\13.0.0\\include" -Os "-fdebug-compilation-dir=C:\\AGPX\\Documenti\\llvm-mos-sdk" -ferror-limit 19 -fmessage-length=120 -fno-signed-char -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -mllvm -num-imag-ptrs=71 -faddrsig -o "C:\\Users\\AGPX\\AppData\\Local\\Temp\\hello_putchar-614d93.o" -x c examples/hello_putchar.c
clang -cc1 version 13.0.0 based upon LLVM 13.0.0git default target x86_64-pc-windows-msvc
ignoring duplicate directory "C:\AGPX\Documenti\llvm-mos\lib\clang\13.0.0\include"
#include "..." search starts here:
#include <...> search starts here:
 C:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/include
 C:/AGPX/Documenti/llvm-mos-sdk/build/common/include
 C:\AGPX\Documenti\llvm-mos\lib\clang\13.0.0\include
End of search list.
 "C:\\AGPX\\Documenti\\llvm-mos-sdk\\..\\llvm-mos\\bin\\ld.lld" -mllvm -num-imag-ptrs=71 --gc-sections "C:\\Users\\AGPX\\AppData\\Local\\Temp\\hello_putchar-614d93.o" -plugin-opt=O2 -mllvm -force-precise-rotation-cost -mllvm -jump-inst-cost=6 -mllvm -phi-node-folding-threshold=0 -mllvm -two-entry-phi-node-folding-threshold=0 -mllvm -align-large-globals=false -mllvm -disable-spill-hoist -LC:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/ldscripts -LC:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/lib -T C:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/ldscripts/link.ld -LC:/AGPX/Documenti/llvm-mos-sdk/build/common/ldscripts -LC:/AGPX/Documenti/llvm-mos-sdk/build/common/lib -l:crt0.o -lcrt -lc -o hello.prg
ld.lld: error: C:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/lib\libcrt.a(zero_bss.c.obj): unable to find library from dependent library specifier: msvcrtd
ld.lld: error: C:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/lib\libc.a(mem.c.obj): unable to find library from dependent library specifier: msvcrtd
ld.lld: error: C:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/lib\libc.a(chrout.c.obj): unable to find library from dependent library specifier: msvcrtd
ld.lld: error: C:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/lib\libc.a(putchar.c.obj): unable to find library from dependent library specifier: msvcrtd
ld.lld: error: C:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/lib\libcrt.a(shift.cc.obj): unable to find library from dependent library specifier: msvcrtd
ld.lld: error: C:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/lib\libcrt.a(mul.cc.obj): unable to find library from dependent library specifier: msvcrtd
ld.lld: error: C:/AGPX/Documenti/llvm-mos-sdk/build/commodore/64/lib\libcrt.a(divmod.cc.obj): unable to find library from dependent library specifier: msvcrtd
clang: error: ld.lld command failed with exit code 1 (use -v to see invocation)

what I have to do? Thanks in advance.

Optimizations

Hello,

I've tried to compile the following simple C code just to do a test:

int main(void) {
  unsigned char *dst = (unsigned char *)0x400;
  const unsigned char *src = (unsigned char *)0x500;

  unsigned int i = 500;
  do {
  	*(dst++) = *(src++);
  } while ((--i) != 0);

  return 0;
}

the compiled code (with mos-c64-clang++ -Wl,--lto-emit-asm -O3 .\mytest.c -o mytest.prg) is as follows:

        .text
        .file   "ld-temp.o"
        .section        .text.main,"ax",@progbits
        .globl  main
        .type   main,@function
main:
        lda     #0
        ldy     #0
        sta     mos8(__rc2)
        sta     mos8(__rc3)
.LBB0_1:
        lda     #0
        clc
        adc     mos8(__rc2)
        tax
        lda     #1
        bcs     .LBB0_3
        lda     #0
.LBB0_3:
        sta     mos8(__rc7)
        lda     #4
        adc     mos8(__rc3)
        stx     mos8(__rc4)
        sta     mos8(__rc5)
        stx     mos8(__rc6)
        lda     #5
        ldx     mos8(__rc7)
        cpx     #1
        adc     mos8(__rc3)
        sta     mos8(__rc7)
        lda     (mos8(__rc6)),y
        sta     (mos8(__rc4)),y
        ldx     mos8(__rc2)
        lda     mos8(__rc3)
        inx
        beq     .LBB0_6
        stx     mos8(__rc2)
        sta     mos8(__rc3)
        cmp     #1
        bne     .LBB0_1
.LBB0_5:
        stx     mos8(__rc2)
        sta     mos8(__rc3)
        cpx     #244
        bne     .LBB0_1
        jmp     .LBB0_7
.LBB0_6:
        clc
        adc     #1
        stx     mos8(__rc2)
        sta     mos8(__rc3)
        cmp     #1
        bne     .LBB0_1
        jmp     .LBB0_5
.LBB0_7:
        ldx     #0
        lda     #0
        rts
.Lfunc_end0:
        .size   main, .Lfunc_end0-main

It looks quite not optimized. As reference, I've compared it with the output of another C compiler for 6502:

main: {
    .label dst = 4
    .label src = 2
    .label i = 6
    lda #<$1f4
    sta.z i
    lda #>$1f4
    sta.z i+1
    lda #<$400
    sta.z dst
    lda #>$400
    sta.z dst+1
    lda #<$500
    sta.z src
    lda #>$500
    sta.z src+1
  __b1:
    // *(dst++) = *(src++)
    ldy #0
    lda (src),y
    sta (dst),y
    // *(dst++) = *(src++);
    inc.z dst
    bne !+
    inc.z dst+1
  !:
    inc.z src
    bne !+
    inc.z src+1
  !:
    // while ((--i) != 0)
    lda.z i
    bne !+
    dec.z i+1
  !:
    dec.z i
    lda.z i
    ora.z i+1
    bne __b1
    // }
    rts
}

It looks really better. Are there some optimization flags that I can add to produce a better code?

Alignment of C64 text section not respected

Because the position of the _start symbol is hard coded in ASCII in the BASIC header, if the start symbol moves due to text section alignment, the BASIC header will jump to the wrong location. The implementation should be made tolerant to any alignment of the text section.

Implement realloc

It would be great to have also realloc implemented, especially for small sizes of heap.
For example, I'm testing allocation using following rust code:

input.split("\n").map(|i| i.parse::<i16>().unwrap()).collect::<Vec<_>>();

and it fails trying to allocate memory for 2000 integers (4000 bytes total) having default heap size 4096 bytes.

It produces following chain of calls of rust allocator:

alloc(2) -> 0x520e
alloc(8) -> 0x5216
realloc(0x520e, 8) -> 0x5216
alloc(16) -> 0x5224
realloc(0x5216, 16) -> 0x5224
alloc(32) -> 0x523a
realloc(0x5224, 32) -> 0x523a
alloc(64) -> 0x5260
realloc(0x523a, 64) -> 0x5260
alloc(128) -> 0x52a6
realloc(0x5260, 128) -> 0x52a6
alloc(256) -> 0x532c
realloc(0x52a6, 256) -> 0x532c
alloc(512) -> 0x5432
realloc(0x532c, 512) -> 0x5432
alloc(1024) -> 0x5638
realloc(0x5432, 1024) -> 0x5638
alloc(2048) -> 0x0
realloc(0x5638, 2048) -> 0x0
PANIC!!!

So it starts with small memory allocated for vector and increases capacity as new data is added trying to realloc existing buffer. Default realloc implementation simply allocates new buffer and copies data - that's why there is not enough memory.

relloc would reduce heap fragmentation in such case and simply fit data in memory.

cc: @karunski

vtable_errors test fails at -O0: undefined symbol

The vtable_errors test in the llvm end-to-end test suite fails at -O0. It's likely that an optimization can usually optimize away some part of the vtable ABI that we haven't implemented yet, but on -O0, that might not work.

FAILED: SingleSource/UnitTests/vtable_errors 
: && /home/runner/work/llvm-test-suite/llvm-test-suite/llvm-test-suite/build/tools/timeit --summary SingleSource/UnitTests/vtable_errors.link.time /home/runner/work/llvm-test-suite/llvm-test-suite/llvm-mos/bin/mos-sim-clang++ -O0  SingleSource/UnitTests/CMakeFiles/vtable_errors.dir/vtable_errors.cpp.o -o SingleSource/UnitTests/vtable_errors   && cd /home/runner/work/llvm-test-suite/llvm-test-suite/llvm-test-suite/build/SingleSource/UnitTests && /usr/local/bin/cmake -E create_symlink /home/runner/work/llvm-test-suite/llvm-test-suite/llvm-test-suite/SingleSource/UnitTests/vtable_errors.reference_output /home/runner/work/llvm-test-suite/llvm-test-suite/llvm-test-suite/build/SingleSource/UnitTests/vtable_errors.reference_output
ld.lld: error: undefined symbol: SingleInheritance::methodA()
>>> referenced by ld-temp.o
>>>               lto.tmp:(vtable for SingleInheritance)
clang-14: error: ld.lld command failed with exit code 1 (use -v to see invocation)

Port Mesen testrunner to use libretro and EmuTest

It was a lot of work getting the Mesen testrunner to operate headlessly in CI. This won't scale to other emulators; Mesen was sort-of designed to be used as a test runner, but the others largely aren't, and they lack good scripting interfaces.

At least that used to be true, but the libretro project provides a cross-emulator control API, not for the purposes of test running, but so the same frontend can control vastly different emulators. It looks like the emutest project is a libretro project that allows libretro emulator plugins to be driven headlessly in response to Lua scripts. The stated purpose is to test libretro plugins, but we can use it just as well to test our SDK. Assuming it works as well as it claims.

`llvm-mos-windows.7z` file is corrupt.

When trying to unzip the file, either with the official 7zip client, or with other tools that use their libraries, I get about halfway through extraction before it complains that the file is corrupt.

The official client shows this as a list of data errors:
image

Total Commander does something similar, where it unzips half the files, but then just fails with a more generic error:
image

Reduce the size of the __cxa_guard variable.

As per the Itanium C++ ABI, the guard variables used by __cxa_guard and friends are 8 bytes, however, this is larger than necessary for the 6502. We should see if there's a simple way to allow targets to customize the size of this variable in Clang.

Bootstrap MOS compiler doesn't work on non x86_64

On aarch64 (also presume others) the x86_64 dynamically linked bootstrap is downloaded. This cannot execute via a qemu-binfmt misc binary execution on Linux because it requires an additional flag setting for qemu-x86_64-static (-L ) to allow the executable to find the libraries that the executable is linked against. This prevents building.

Common platform with CMake errors unless `CMAKE_TRY_COMPILE_TARGET_TYPE` is set to static library

This issue seems to be triggered under specific circumstances:

  1. LLVM_MOS_PLATFORM is set to common
  2. CMAKE_TRY_COMPILE_TARGET_TYPE is not set to STATIC_LIBRARY

I am unable to upload the repro project onto GitHub, so here's the Google Drive link instead.

Log
[main] Configuring folder: mos-test 
[driver] Removing /home/atirut/Projects/mos-test/build/CMakeCache.txt
[driver] Removing /home/atirut/Projects/mos-test/build/CMakeFiles
[proc] Executing command: /usr/bin/cmake --no-warn-unused-cli -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_BUILD_TYPE:STRING=Debug -S/home/atirut/Projects/mos-test -B/home/atirut/Projects/mos-test/build -G Ninja
[cmake] Not searching for unused variables given on the command line.
[cmake] /home/atirut/Programs/llvm-mos/bin/mos-common-clang: /lib64/libtinfo.so.6: no version information available (required by /home/atirut/Programs/llvm-mos/bin/mos-common-clang)
[cmake] /home/atirut/Programs/llvm-mos/bin/mos-common-clang++: /lib64/libtinfo.so.6: no version information available (required by /home/atirut/Programs/llvm-mos/bin/mos-common-clang++)
[cmake] /home/atirut/Programs/llvm-mos/bin/mos-common-clang: /lib64/libtinfo.so.6: no version information available (required by /home/atirut/Programs/llvm-mos/bin/mos-common-clang)
[cmake] /home/atirut/Programs/llvm-mos/bin/mos-common-clang: /lib64/libtinfo.so.6: no version information available (required by /home/atirut/Programs/llvm-mos/bin/mos-common-clang)
[cmake] /home/atirut/Programs/llvm-mos/bin/mos-common-clang++: /lib64/libtinfo.so.6: no version information available (required by /home/atirut/Programs/llvm-mos/bin/mos-common-clang++)
[cmake] /home/atirut/Programs/llvm-mos/bin/mos-common-clang: /lib64/libtinfo.so.6: no version information available (required by /home/atirut/Programs/llvm-mos/bin/mos-common-clang)
[cmake] -- The C compiler identification is unknown
[cmake] -- The CXX compiler identification is unknown
[cmake] -- Detecting C compiler ABI info
[cmake] /home/atirut/Programs/llvm-mos/bin/mos-clang: /lib64/libtinfo.so.6: no version information available (required by /home/atirut/Programs/llvm-mos/bin/mos-clang)
[cmake] /home/atirut/Programs/llvm-mos/bin/mos-clang++: /lib64/libtinfo.so.6: no version information available (required by /home/atirut/Programs/llvm-mos/bin/mos-clang++)
[cmake] /home/atirut/Programs/llvm-mos/bin/mos-clang: /lib64/libtinfo.so.6: no version information available (required by /home/atirut/Programs/llvm-mos/bin/mos-clang)
[cmake] -- Detecting C compiler ABI info - failed
[cmake] -- Check for working C compiler: /home/atirut/Programs/llvm-mos/bin/mos-common-clang
[cmake] /home/atirut/Programs/llvm-mos/bin/mos-clang: /lib64/libtinfo.so.6: no version information available (required by /home/atirut/Programs/llvm-mos/bin/mos-clang)
[cmake] /home/atirut/Programs/llvm-mos/bin/mos-clang++: /lib64/libtinfo.so.6: no version information available (required by /home/atirut/Programs/llvm-mos/bin/mos-clang++)
[cmake] /home/atirut/Programs/llvm-mos/bin/mos-clang: /lib64/libtinfo.so.6: no version information available (required by /home/atirut/Programs/llvm-mos/bin/mos-clang)
[cmake] -- Check for working C compiler: /home/atirut/Programs/llvm-mos/bin/mos-common-clang - broken
[cmake] CMake Error at /usr/share/cmake/Modules/CMakeTestCCompiler.cmake:69 (message):
[cmake]   The C compiler
[cmake] 
[cmake]     "/home/atirut/Programs/llvm-mos/bin/mos-common-clang"
[cmake] 
[cmake]   is not able to compile a simple test program.
[cmake] 
[cmake]   It fails with the following output:
[cmake] 
[cmake]     Change Dir: /home/atirut/Projects/mos-test/build/CMakeFiles/CMakeTmp
[cmake]     
[cmake]     Run Build Command(s):/usr/bin/ninja-build cmTC_b1fc4 && [1/2] Building C object CMakeFiles/cmTC_b1fc4.dir/testCCompiler.c.obj
[cmake]     /home/atirut/Programs/llvm-mos/bin/mos-common-clang: /lib64/libtinfo.so.6: no version information available (required by /home/atirut/Programs/llvm-mos/bin/mos-common-clang)
[cmake]     [2/2] Linking C executable cmTC_b1fc4
[cmake]     FAILED: cmTC_b1fc4 
[cmake]     : && /home/atirut/Programs/llvm-mos/bin/mos-common-clang   CMakeFiles/cmTC_b1fc4.dir/testCCompiler.c.obj -o cmTC_b1fc4   && :
[cmake]     /home/atirut/Programs/llvm-mos/bin/mos-common-clang: /lib64/libtinfo.so.6: no version information available (required by /home/atirut/Programs/llvm-mos/bin/mos-common-clang)
[cmake]     /home/atirut/Programs/llvm-mos/bin/ld.lld: /lib64/libtinfo.so.6: no version information available (required by /home/atirut/Programs/llvm-mos/bin/ld.lld)
[cmake]     ld.lld: error: cannot find linker script link.ld
[cmake]     clang-16: error: ld.lld command failed with exit code 1 (use -v to see invocation)
[cmake]     ninja: build stopped: subcommand failed.
[cmake]     
[cmake]     
[cmake] 
[cmake]   
[cmake] 
[cmake]   CMake will not be able to correctly generate this project.
[cmake] Call Stack (most recent call first):
[cmake]   CMakeLists.txt:6 (project)
[cmake] 
[cmake] 
[cmake] -- Configuring incomplete, errors occurred!
[cmake] See also "/home/atirut/Projects/mos-test/build/CMakeFiles/CMakeOutput.log".
[cmake] See also "/home/atirut/Projects/mos-test/build/CMakeFiles/CMakeError.log".

Implement <atomic>

Since we define there to be exactly one main thread, we can have a fairly trivial implementation. Special care should be given to whether char is defined to be lock-free; lock free atomics gain additional semantics WRT signal handlers. The others should not be lock-free, since they're not actually atomic.

Set up Doxygen document generation

We should really have a documentation generator in place before we really start filling out the SDK.

I did a quick survey, and it looks like there's two big games in town: Doxygen and Sphinx. Sphinx has the benefit of free hosting on ReadTheDocs. We should try to set this up for our SDK.

Source code in assembly output

Hi,

first of all, many many compliments! You've done a great job!
I have a question: I've tried the "-Wl,--lto-emit-asm" option, but I wish to understand if there's an option to interleave the assembly code with the source (as comment). This would be really useful to understand how a certain piece of code is translated. Is there a similar option?

Thanks in advance and keep the absolutely outstanding work!

Linker script for a simple ROM?

I am making a custom BIOS and I cannot seem to figure out how to make the linker put codes and initialized data(strings, etc.) in the area starting from $F000

Relocatable binary format?

When compiling codes, the resulting ELF binary does not seem to have any relocation data. This means if any 6502 OS wants to do multitasking, LLVM-MOS ELF is not an option. While there are other compilers like CC65 supports outputting to O65 relocatable format, the performance of the compiled codes just sucks in general.

Being able to have both LLVM's awesome optimization and being able to relocate codes would be very nice.

Make `atari8-stdcart` match new NES LMA convention

The LMA/VMA relationship for the NES targets was simplified recently, but the improvements didn't yet make it over to the atari8-stdcart target, which was loosely based on them. This target should also be updated with the new conventions.

ninja clean doesn't clean mos-build external project

I've noticed that ninja clean will only clean the build artifacts from the outer project, not any of the target-specific files. This can make it difficult to test changes to the compiler, since it won't rebuilt the target files unless I completely remove them by hand.

Cross-platform SDK smoke test

LLVM's end-to-end test suite only works on Mac and Windows, and it exercises the SDK differently than an end user would.

llvm-mos should have an automated smoke test for Mac, Windows, and Linux that compiles a simulator "Hello, World" using the SDK, as an end user would on first checkout. This will help ensure that the first steps when using the SDK remain smooth.

Name of class osi_screen isn't reserved

The osi_screen template's link-time instantiations may (technically) conflict with user class of the same name, which is a ding against C++ standards compliance. The usual way to deal with this is to prefix the name with double underscores (i.e., __osi_screen), since it's undefined behavior for a user to create an identifier with that naming convention. There shouldn't be any additional trouble, since osi_screen is totally internal to the implementation.

If we want to expose this to the user, the usual way to do this is to have both an internal version, __osi_screen and an external version, osi_screen, which is an alias. Then, the alias line can be put into a header which can be optionally included; this allows users to buy into the namespace "pollution."

@smuehlst

Investigate AVR Libc

While maintaining our own libc is all well and good, given the limited resources available to the project, it's probably not the best use of our time.

The trouble is, the off-the-shelf libc's that we might grab (e.g., the WIP LLVM libc, newlib, picolibc, etc.) tend to be written with the assumption that integer div/mul/mod are cheap, and that a barrel shifter is available. Neither of these is true on the 6502, and all of these end up going from constant time operations to loops. This really breaks the performance of a wide swath of libc algorithms, like we saw with mpaland/printf.

AVR libc is a possible exception. While AVR does supply a hardware multiplier, it doesn't include a barrel shifter or hardware divider. It's also an 8-bitter, like the 6502. This may mean that AVR libc has been optimized for a chip much closer to the 6502, and to get the algorithms polished for the 6502, we'd only need to scrub out assumptions that integer multiplication is cheap, which should be a much smaller task.

AVR libc should be investigated as a possible long-term basis for a more full implementation of a libc for our SDK.

va_args issue

Hi,

I'm looking at using llvm-mos for an upcoming project, and I have it all up and running, but I do have a bit of a custom setup with a custom linker script so my question here may be due to that.

I'm trying to get my own printf up and running and I have a question about this generated code. I have something like this

void my_printf(const char* fmt, ...); 

void somecode() {
    my_printf("some string %d %d %d", 0x12, 0x13, 0x14);
}

and the generated code for this call ends up being

    a131: 18           	clc
    a132: a5 00        	lda	$0
    a134: 69 fa        	adc	#$fa
    a136: 85 00        	sta	$0
    a138: a5 01        	lda	$1
    a13a: 69 ff        	adc	#$ff
    a13c: 85 01        	sta	$1
    a13e: a0 00        	ldy	#$0
    a140: a9 12        	lda	#$12
    a142: 91 00        	sta	($0),y
    a144: a0 02        	ldy	#$2
    a146: a9 13        	lda	#$13
    a148: 91 00        	sta	($0),y
    a14a: a0 04        	ldy	#$4
    a14c: a9 14        	lda	#$14
    a14e: 91 00        	sta	($0),y
    a150: a0 01        	ldy	#$1
    a152: a9 00        	lda	#$0
    a154: 91 00        	sta	($0),y
    a156: a0 03        	ldy	#$3
    a158: 91 00        	sta	($0),y
    a15a: a0 05        	ldy	#$5
    a15c: 91 00        	sta	($0),y
    a15e: a2 96        	ldx	#$96
    a160: 86 02        	stx	$2
    a162: a2 a2        	ldx	#$a2
    a164: 86 03        	stx	$3
    a166: 20 0c a1     	jsr	$a10c

What I don't fully understand is the part at the start where RS0 looks to be used "like a stack pointer", but in my case zp 0 and 1 has the value 0 I wonder if I have screwed up something with my setup (likely) and this should point to some specific memory location?

Thanks!

Support shifted PETSCII character set

The C64 putchar should detect whether the VIC-II is configured to use the shifted character set; in that case, it should transpose the uppercase and lowercase characters.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.