Some early preliminary notes from the alpha vectrex-focused release of vbcc... I'll be updating my copy of this as I use it. At the moment I'm only looking at it from the point of view of being a replacement for the existing compiler. I'll leave the discussion of how we might implement and what should go in to a completely new library for another time. -------------------------------- Installation notes bin files are 64 bit. Fortunately I have qemu installed on my i686 system. Might be worth supplying both 32 bit native binaries, and cross-platform portable 64-bit fat binaries using APE (cosmocc). Aside: the build process that enquires of the user about word signedness and size asks a lot of questions that can be answered automatically, assuming that the questions are about the host computer and not the target computer: see https://homepages.cwi.nl/~steven/enquire.html -------------------------------- Libraries 17.29 6809/Vectrex This is a port of vclib to the Vectrex. The config +vectrex will create a cartridge ROM image including a cartridge header. Vectrex users programming in the Vide IDE include a "cartridge.c" file in their compilation which is always linked first so that it is placed as the first part of the ROM code. It is available to the user so that they can adjust the ROM name and the screen ccordinates of the header. The significant content of the file contains this: #include struct cartridge_t { char copyright[11]; // copyright string, must start with "g GCE" and must end with "\x80" const void* music; // 16 bit memory adress of title music data signed int title_height; // signed 8 bit value, height of game title letters unsigned int title_width; // unsigned 8 bit value, width of game title letters int title_y; // signed 8 bit value, y coordinate of game title int title_x; // signed 8 bit value, x coordinate of game title char title[]; // game title string, must end with "\x80\x00" }; const struct cartridge_t game_header __attribute__((section(".cartridge"), used)) = { .copyright = "g GCE 2017\x80", // change year if neccessary, do not change "g GCE" .music = &Vec_Music_1, // taken from included headers .title_height = -8, .title_width = 80, .title_y = -16, .title_x = -72, .title = "GAME TITLE\x80" // note that \x00 is automatically appended! }; The format is slightly more complex than that but if the other features are wanted the user has to replace the declarations above with the alternative format. The difference is that the title can be over multiple lines with separate x,y for each line. Only the string on the final line is terminated by \0x80, the earlier ones are terminated by \0". I think. It's been some time since I needed to use that format, I may have the details slightly wrong. Anyway my point is that vbcc should not create a ROM header, the user does that in cartridge.h [Again: I emphasize that this is only if we are trying to be compatible with the existing code base. For a new environment, creating the rom header differently would be fine.] The linker file vlink.cmd is used. The linker parameters mentioned in the following chapters can either be changed by modifying the linker file, or by adding the option --D= on the command line invocation of vc. 17.29.1 Memory The usable RAM region defaults to 0xC880..0xCBEA, the ROM region defaults to 0x0000.0x8000. Those values can be changed by the linker parameters RAMSTART, RAMEND, ROMSTART, ROMEND. Data sections will be initialized by copying the init data from ROM to RAM. Note that the ROM area on the Vectrex is actually 48K not 32K, though larger roms were not used until relatively recently. (There's also another small area that can be used as ROM but I don't know of anyone using it yet due to the overhead of decoding it in a cartridge) Nowadays some ROMs use multiple banks which Vide and GCC do support, although not very well. There are a couple of different methods used to do bank switching, and especially if using the 4-bank cartridges. I'll seek out the details at some point. There are a very small number of cartridges that support extra RAM. The Vecfever is one of them but you may be aware how few people have access to one. In normal use it shouldn't matter much to a 6809 compiler if an area that is normally in ROM is actually writable. Almost certainly an author would be handling that area of memory themself, explicitly in the code. 17.29.2 Stack The stack pointer will be initialized to 0xCBEA. This value can be changed using the linker parameter __STACK. The stack size can be set using STACKLEN. I believe when a Vectrex game rom is started, S is already initialised by the BIOS, and probably should never be touched (other than through legitimate pushing and pulling...). DP will also have been initialised. This should all be in existing Vectrex documentation, such as it is. 17.29.3 Heap The free area up to __STACK-STACKLEN is used as heap. No vectrex code in the current system under GCC and Vide uses the heap. There are often only about 800 bytes left free for programs, so RAM is *extremely* tight: we don't want unused heap code or variables taking up any space at all, if a heap library exists, not even the minimal 2 bytes that would be needed for an empty freespace list. Vectrex coders do their own space management, aggressively. Usually by moving as much as humanly possible into ROM, with anything that can't go in ROM being calculated on the fly rather than stored in RAM. I can't emphasize enough how little RAM the Vectrex leaves for the programmer afer the BIOS has taken what it needs. Coders will even steal the odd byte of BIOS RAM if they know that the BIOS is never going to use it during the run of their ROM. 17.29.4 HW Registers TODO 17.29.5 stdio If stdio functions are called, a 20x12 character buffer is used to handle text output. The screen will be refreshed when output functions are called and when the program terminates. Therefore the text will not be visible during calculations of a normal console C program. The function __conrefresh() can be called to trigger a screen refresh. No-one uses stdio procedures. There's no serial output on the Vectrex and text display is so slow that drawing text (even with the built-in raster primitives) would severely affect program speed. Potentially stdio might be useful with some flash cards such as the VecFever, with a serial device that outputs to USB, but there's no standardised interface. Easiest to just omit. Some other standard headers that don't actually require code could usefully be available, if only to make sources slightly more portable, eg stdint.h or limits.h Headers with inline procedures or macro definitions such as isdigit() etc would also be useful. Library procedures that make sense on the Vectrex would be acceptable, as long as nothing is pulled in by the linker when they're not used. GCC under Vide does not offer most of these headers, only . It should! 17.29.6 BIOS Interface TODO: not yet sure The header vectrex.h contains inline-assembly declarations or macros for Vectrex BIOS functions. #define __D(x,y) ((((unsigned char)y)<<8)|((unsigned char)x)) #define __A __varsmodified("") __A void Wait_Recal()="\tjsr\t0xf192"; __A void Intensity_a(char x)="\texg\ta,b\n\tjsr\t0xf2ab"; __A void Moveto_ab_7f(char x, char y)="\tlda\t0,s\n\tjsr\t0xf2fc"; __A void Moveto_d_7f(int)="\tjsr\t0xf2fc"; __A void Moveto_ab(char x, char y)="\tlda\t0,s\n\tjsr\t0xf312"; __A void Moveto_d(int)="\tjsr\t0xf312"; __A void Draw_Line_ab(char x, char y)="\tlda\t0,s\n\tjsr\t0xf3df"; __A void Draw_Line_d(int)="\tjsr\t0xf3df"; __A void Print_Str_d(int,__reg("u") void *)="\tjsr\t0xf37a"; __A void Print_Str_ab(char x,char y,__reg("u") void *)="\tlda\t0,s\n\tjsr\t0xf37a"; __A void Print_Str(__reg("u") void *)="\tjsr\t0xf495"; We do have a list of registers used and modfied by all the BIOS routines that can be used to add attributes to the BIOS procedures, to help with optimising. I don't know at this point whether the assignment of parameters to GCC procedures uses the same mapping to registers and stack parameters as vbcc, I need to read your docs on calling conventions, or talk to you about them if not documented yet. For reasons that you'll have to ask Chris and Peer about, the convention with the existing Vectrex library is that coordinates are y,x rather than x,y. Chris at least is quite dogmatic about this being the preferred One True Way. It's embedded in so much code and documentation nowadays that it's unlikely we can persuade anyone to switch to using x,y. Some functions take two coordinates in accumulators a and b. vbcc does not support accessing the accumulators separately. Therefore those functions are usually available in two versions. One version takes a 16bit argument containing the coordinates as lo-byte and hi-byte in the 16bit accumulator d. The macro _D(x,y) can be used to calculate the combined 16bit value from two coordinates. Using this API version is most efficient if the 16bit value can be calculated once and reused later, or if the coordinates are constants. Another API accepts two coordinates as separate parameters. This approach will usually be faster for dynamically calculated coordinates. Draw_Line_d(_D(0,0)); Draw_Line_ab(x, y); The GCC Vectrex library does support these names but the normal procedure used is Draw_Line(int y, int x) which in vbcc would be better specified as Draw_Line(int8_t y, int8_t x) An example of a definition of an existing procedure as it might be implemented in the vbcc Vectrex library could be something like this: #define asm(s) __asm(s) // Be more compatible with gcc syntax void Print_Str_yx(int8_t y, int8_t x, char *s) { // assume vbcc calling conventions are that parameters are passed to this in A, B, Y respectively // and the BIOS procedure uses a,b as is, but passes the string in via U, then the code would look // like this: asm(" TFR Y,U"); // Move string 's' into the U register that Print_Str_d expects. asm(" JMP $F37A"); // Print_Str_d: // Uses DP (must be 0xD0), U, A, B // Outputs U (points to the byte after the terminating 0x80) // Corrupts A, B, X. // Other registers untouched. // (Would be a JSR followed by an RTS so might as well save an instruction and JMP instead.) } Chapter 17: C Library 185 17.29.7 Floating Point Not yet implemented. No-one ever uses floating point on the Vectrex, it's way too expensive at runtime. There is some use of fixed point but everyone has to write their own version. Most code just uses integers, usually 8 bit but also 16 bit where needed. There is almost no use of 32-bit integers as arithmetic on those is particularly expensive. There is no floating point rom on the Vectrex so specific floating point procedures will have to be written based on the Motorola ROM code, pulling in any subprocedures that are called. The FP09 source code is available at https://gtoal.com/src/asm-expand/ including a macro expander for the Motorola assember format that's hard to find an assembler for, plus the bug-fixed https://gtoal.com/src/asm-expand/fp09/util.sa (The .asm files in https://gtoal.com/src/asm-expand/fp09/ are the macro-expanded versions of the original .sa files)