Oscar64: Difference between revisions
(Created page with "==== Documentation ==== The main documentation website is located here: https://github.com/drmortalwombat/oscar64/blob/main/oscar64.md === Installation procedure === (this is from Mu0n, under Windows 11 but using a WSL command window) <blockquote>Assumptions: * Windows' WSL is installed (ie with Ubuntu) * Python is installed inside windows * make is installed inside WSL * gcc is installed inside WSL ('''sudo apt install build-essential''') </blockquote> Step 1) in W...") |
(→Embedding asset files: parameters added to the #embed directive) |
||
| (2 intermediate revisions by the same user not shown) | |||
| Line 78: | Line 78: | ||
=== How to manage multiple source code files in a project === | === How to manage multiple source code files in a project === | ||
* Create .h + .c pairs of source code files by themes.<br> | |||
* Use '''whatever.h''' so that '''BASEPATH/f256lib-oscar64/doodles/myproject/src/whatever.c''' and its corresponding whatever.h are referred to<br> | |||
* Put the entirety of whatever.h's content between | |||
<pre>#ifndef WHATEVER_H | |||
#define WHATEVER_H | |||
</pre> | |||
and | |||
<pre> | |||
#endif | |||
</pre> | |||
to avoid complaints of multiple definitions if multiple files need this reference. | |||
=== Compiling a program, scripts from Mu0n === | === Compiling a program, scripts from Mu0n === | ||
| Line 199: | Line 219: | ||
//return to normalcy | //return to normalcy | ||
#pragma data(data)</pre> | #pragma data(data)</pre> | ||
If you want to embed files that are larger than 64kb OR if you want to manually force a specific size of data that will get loaded as an embedded asset, use a byte number right after #embed, like so: | |||
<pre> | |||
__export const char bmScreen[] = { | |||
#embed 76800 "../assets/bitmap.bin" | |||
}; | |||
</pre> | |||
''(this would load a full screen bitmap of 76,800 bytes at a 320x240 resolution.)'' | |||
If you want to use an offset from which to start using your data, use a second number like so: | |||
<pre> | |||
__export const char binaryChunk[] = { | |||
#embed 8192 1024 "../assets/chunk.bin" | |||
}; | |||
</pre> | |||
''(this would load 8kb but starting at byte 1024 from the start instead of 0)'' | |||
=== How to use higher memory and the MMU to store code === | === How to use higher memory and the MMU to store code === | ||
| Line 257: | Line 294: | ||
=== Accessing the extra 2x core banks of 512kb memory === | === Accessing the extra 2x core banks of 512kb memory === | ||
Since the launch of the 2x core, the full 2MB of SRAM is accessible if you set a bit right in register 0x0000. For more details on this feature of the 2x core, [[ | Since the launch of the 2x core, the full 2MB of SRAM is accessible if you set a bit right in register 0x0000. For more details on this feature of the 2x core, [[Use the Core2x|see this page]]. | ||
To peek a byte at these regions of memory, use this asm block as an oscar64 function: | To peek a byte at these regions of memory, use this asm block as an oscar64 function: | ||
| Line 267: | Line 304: | ||
{ | { | ||
return __asm { | return __asm { | ||
lda addr | |||
sta 0x05 | |||
lda addr+1 | |||
sta 0x06 | |||
lda addr+2 | |||
sta 0x07 | |||
ldx 0x00 | ldx 0x00 | ||
ldy 0x01 | ldy 0x01 | ||
txa | |||
ora #0x08 | ora #0x08 | ||
| Line 287: | Line 324: | ||
byt 0xa7 | byt 0xa7 | ||
byt 0x05 | |||
stx 0x00 | stx 0x00 | ||
sty 0x01 | sty 0x01 | ||
plp | |||
sta accu | sta accu | ||
lda #0 | lda #0 | ||
sta accu+1 | sta accu+1 | ||
}; | |||
}</pre> | }</pre> | ||
| Line 306: | Line 343: | ||
{ | { | ||
__asm { | __asm { | ||
lda addr | |||
sta 0x05 | |||
lda addr+1 | |||
sta 0x06 | |||
lda addr+2 | |||
sta 0x07 | |||
ldx 0x00 | ldx 0x00 | ||
ldy 0x01 | ldy 0x01 | ||
txa | |||
ora #0x08 | ora #0x08 | ||
| Line 327: | Line 364: | ||
lda value | lda value | ||
byt 0x87 | |||
byt 0x05 | |||
stx 0x00 | |||
sty 0x01 | |||
plp | |||
ldx #0x00 | |||
}; | }; | ||
} | } | ||
Latest revision as of 15:34, 1 May 2026
Documentation
The main documentation website is located here: https://github.com/drmortalwombat/oscar64/blob/main/oscar64.md
Installation procedure
(this is from Mu0n, under Windows 11 but using a WSL command window)
Assumptions:
- Windows' WSL is installed (ie with Ubuntu)
- Python is installed inside windows
- make is installed inside WSL
- gcc is installed inside WSL (sudo apt install build-essential)
Step 1) in Windows, make a base directory (let's call it BASEPATH) that will hold both: * the oscar64 project, but with the 'f256k-support' branch rather than 'main' branch https://github.com/sdwfrost/oscar64 * the f256lib-oscar64 project, 'main branch' https://github.com/sdwfrost/f256lib-oscar64 (both from sdwfrost's GitHub account) Step 2) from windows, open a cmd window, go to your intended base folder Step 3) type WSL Step 4) clone oscar64 with git clone -b f256k-support https://github.com/sdwfrost/oscar64.git Step 5) clone f256lib-oscar64 side by side in the same base folder. git clone -b main https://github.com/sdwfrost/f256lib-oscar64 Both 'oscar64' and 'f256lib-oscar64' folders will be in the same location when this is done. Step 6) go into oscar64/ Step 7) type: make -f make/makefile (this assumes gcc being present in WSL, it will take a while!) Step 8) switch over to f256lib-oscar64/ and type: OSCAR64=../../oscar64/bin/oscar64 make all (warning 1: at the time of writing this guide, the 2nd project, BachHero, triggers an error that halts the whole list. Simply remove that entry from /f256lib-oscar64/doodles/MakeFile to get the rest going) (warning 2: most projects will compile, but not run properly when run in the Wildbits environment since they expect extra library files that have not been ported over) Step 9) to compile a single project in general, make sure you use a path that points to the compiled oscar64 of step 7 like so: (assuming your project myproject is in BASEPATH/f256lib-oscar64/doodles/) BASEPATH/oscar64/bin/oscar64 -tm=f256k -n -i=BASEPATH/f256lib-oscar64/f256lib BASEPATH/f256lib-oscar64/doodles/myproject/src/myproject.c -o=BASEPATH/f256lib-oscar64/doodles/myproject/myproject.pgz
Noteworthy files and folders
(some of these are merely suggestions in how to organize your local installation of oscar64)
assuming your BASEPATH = the folder where you do your installation,
BASEPATH/oscar64/ is where the compiler should be installed
BASEPATH/f256lib-oscar64/ is where the F256/wildbits libraries for oscar64 should be installed
BASEPATH/f256lib-oscar64/f256lib/ is the folder containing all the library files
BASEPATH/f256lib-oscar64/f256lib/f256lib.c is the master library file, also has a corresponding f256lib.h header file and loads all the rest.
BASEPATH/f256lib-oscar64/doodles/ is a good place to store your projects
BASEPATH/f256lib-oscar64/doodles/myproject/ is the root folder of your project called 'myproject' and where the program and linker produced files end up in
BASEPATH/f256lib-oscar64/doodles/myproject/src/ is the folder containing all of your source code
How to manage multiple source code files in a project
- Create .h + .c pairs of source code files by themes.
- Use whatever.h so that BASEPATH/f256lib-oscar64/doodles/myproject/src/whatever.c and its corresponding whatever.h are referred to
- Put the entirety of whatever.h's content between
#ifndef WHATEVER_H #define WHATEVER_H
and
#endif
to avoid complaints of multiple definitions if multiple files need this reference.
Compiling a program, scripts from Mu0n
I use a pair of scripts that are located in BASEPATH/f256lib-oscar64/doodles/
Here's the shell script ("c.sh") I use to simply compile a program, this works regardless if your project uses one .c file or multiples. Adjust your absolute paths to what you have on your modern computer. "projectname" is the folder of your project inside the "doodles" folder.
run it using the command ./c.sh myprojectname
#!/bin/bash
# --- 1. CONFIGURATION ---
OSCAR_BIN="/mnt/d/F256/oscar64/bin/oscar64"
# Use the Windows python launcher (it handles COM8 perfectly)
PYTHON_EXE="python.exe"
# Use the Windows path for the script (escaped backslashes)
FOENIX_MGR="D:\\F256\\llvm-mos\\f256dev\\FoenixMgr\\FoenixMgr\\fnxmgr.py"
# --- 2. ARGUMENTS ---
PROJ_NAME="$1"
SRC_DIR="${PROJ_NAME}/src/"
SRC_FILE="${PROJ_NAME}/src/${PROJ_NAME}.c"
OUT_DIR="${PROJ_NAME}/"
BIN_FILE="${PROJ_NAME}.pgz"
FLAGS="-tm=f256k -n -v -i=../f256lib"
# --- 3. Gather all files in src/
mapfile -t CFILES < <(find "$SRC_DIR" -maxdepth 1 -type f -name "*.c")
# --- 4. COMPILE ---
echo "Compiling:"
printf '%s\n' "${CFILES[@]}"
echo
echo "Linking into ${OUT_DIR}/${PROJ_NAME}.pgz"
$OSCAR_BIN $FLAGS "${CFILES[@]}" -o="./$OUT_DIR/$PROJ_NAME.pgz"
Here's the shell script ("car.sh" = Compile And Run) I use to compile a program and send it over to my Wildbits through the foenixmgr script. This assumes that your host is win11 and python is run from that, from inside WSL ubuntu. Tweak to your setup's situation, of course. run it using the command ./car.sh myprojectname
#!/bin/bash
# --- 1. CONFIGURATION ---
OSCAR_BIN="/mnt/d/F256/oscar64/bin/oscar64"
# Use the Windows python launcher (it handles COM8 perfectly)
PYTHON_EXE="python.exe"
# Use the Windows path for the script (escaped backslashes)
FOENIX_MGR="D:\\F256\\llvm-mos\\f256dev\\FoenixMgr\\FoenixMgr\\fnxmgr.py"
# --- 2. ARGUMENTS ---
PROJ_NAME="$1"
SRC_DIR="${PROJ_NAME}/src/"
SRC_FILE="${PROJ_NAME}/src/${PROJ_NAME}.c"
OUT_DIR="${PROJ_NAME}/"
BIN_FILE="${PROJ_NAME}.pgz"
FLAGS="-tm=f256k -n -i=../f256lib"
# --- 3. Gather all files in src/
mapfile -t CFILES < <(find "$SRC_DIR" -maxdepth 1 -type f -name "*.c")
# --- 4. COMPILE ---
echo "Compiling:"
printf '%s\n' "${CFILES[@]}"
echo
echo "Linking into ${OUT_DIR}/${PROJ_NAME}.pgz"
$OSCAR_BIN $FLAGS "${CFILES[@]}" -o="./$OUT_DIR/$PROJ_NAME.pgz"
# --- 5. TRANSFER ---
if [ $? -eq 0 ]; then
echo "Transferring to F256K2 via Windows Python..."
# We use the Windows path for the file we just built
WIN_BIN_PATH="D:\\F256\\f256lib-oscar64\\doodles\\${PROJ_NAME}\\${BIN_FILE}"
$PYTHON_EXE "$FOENIX_MGR" --port COM8 --run-pgz "$WIN_BIN_PATH"
else
echo "Compilation failed."
exit 1
fi
Embedding asset files
Here's an example of a few assets loaded in a specific spot in memory, starting from 0x10000. It needs to be part of a section, then a region and then some array identifiers that point to the data itself. When the project compiles, you can check out the layout of the memory being used inside your .map file.
/*
* The following assets will be located within these bounds
*
10000 - 10400 : grupal, DATA:assets
10400 - 10800 : sBoy1, DATA:assets
10800 - 10c00 : sThing, DATA:assets
10c00 - 11000 : sGirl1, DATA:assets
11000 - 11400 : sCath, DATA:assets
11400 - 11800 : sCat, DATA:assets
11800 - 12000 : sDash, DATA:assets
*/
#pragma section( assets, 0 )
#pragma region( assets, 0x10000, 0x20000, , , {assets} )
#pragma data(assets)
__export const char grupal[] = { //1kb palette from 0x10000 to 0x103FF
#embed "../assets/grudge.pal"
};
__export const char sBoy1[] = { //16x16 sprite of 1kb from 0x10400 to 0x107FF
#embed "../assets/boy1.bin"
};
__export const char sThing[] = {
#embed "../assets/thing.bin"
};
__export const char sGirl1[] = {
#embed "../assets/girl1.bin"
};
__export const char sCath[] = {
#embed "../assets/cath.bin"
};
__export const char sCat[] = {
#embed "../assets/cat.bin"
};
__export const char sDash[] = {
#embed "../assets/dash.bin"
};
//return to normalcy
#pragma data(data)
If you want to embed files that are larger than 64kb OR if you want to manually force a specific size of data that will get loaded as an embedded asset, use a byte number right after #embed, like so:
__export const char bmScreen[] = {
#embed 76800 "../assets/bitmap.bin"
};
(this would load a full screen bitmap of 76,800 bytes at a 320x240 resolution.)
If you want to use an offset from which to start using your data, use a second number like so:
__export const char binaryChunk[] = {
#embed 8192 1024 "../assets/chunk.bin"
};
(this would load 8kb but starting at byte 1024 from the start instead of 0)
How to use higher memory and the MMU to store code
Much like assets, you will have to use the #pragma directive to set up a section and region for each chunk of RAM. Since a trampoline scheme gets used here in conjunction with the machine's MMU, these regions should be 0x2000 big, or 8kb.
Keep in mind that these chunks of RAM will be swapped in and out of the 0xA000 to 0xBFFF 8kb chunk visible by the CPU.
Here is the list of stuff you must define for it to work:
- A specific number for your code's block = physical address / 0x2000 you have in mind to stash your code. For example, to use the 8kb of code space between 0x10000 and 0x11FFF, this will be "overlay block 8". For the space between 0x12000 and 0x13FFF, this is "overlay block 9"
#define OVL1_BLOCK 8 // Physical 0x10000
- #pragma directive such as:
// Overlay 1: stored at physical 0x10000, compiled to run at 0xA000
#pragma section( ovl1_code, 0 )
#pragma region( ovl1, 0x10000, 0x12000, , , { ovl1_code }, 0xA000 )
- Forward declaration of a trampoline function used to access the higher memory function, such as:
// ---------------------------------------------------------------------------
// Forward declarations of trampolines (in main code, always visible)
// ---------------------------------------------------------------------------
void firstSegment(int arg1, int arg2);
// Trampolines save the current bank 5 mapping, switch to the target
// overlay's physical block, call the FAR function, then restore the
// original mapping. This supports nested cross-overlay calls.
void firstSegment(int arg1, int arg2) {
volatile byte saved = PEEK(OVERLAY_MMU_REG);
POKE(OVERLAY_MMU_REG, OVL1_BLOCK);
FAR_firstSegment(arg1, arg2);
POKE(OVERLAY_MMU_REG, saved);
}
- Your far memory function in between #pragma code directives:
#pragma code( ovl1_code )
void FAR_firstSegment(int arg1, int arg2) {
textPrint("firstSegment = ");
textPrintInt((int32_t)(arg1 + arg2));
textPrint("\n");
}
//return to normalcy
#pragma code( code )
Note: it's perfectly ok to define multiples of these high memory regions. One far memory function can call another far memory function from another region without issue, but it has to call it through its lower memory trampoline.
Accessing the extra 2x core banks of 512kb memory
Since the launch of the 2x core, the full 2MB of SRAM is accessible if you set a bit right in register 0x0000. For more details on this feature of the 2x core, see this page.
To peek a byte at these regions of memory, use this asm block as an oscar64 function:
peek24 accepts a 32bit long address, stores it temporarily into a few bytes near the beginning of zero page. It then activates bit 3 of register 0x0000 to access the new 2x core higher memory banks. Finally, it fetches the content of that byte as a returned char.
char peek24(unsigned long addr)
{
return __asm {
lda addr
sta 0x05
lda addr+1
sta 0x06
lda addr+2
sta 0x07
ldx 0x00
ldy 0x01
txa
ora #0x08
php
sei
sta 0x00
tya
ora #0x30
sta 0x01
byt 0xa7
byt 0x05
stx 0x00
sty 0x01
plp
sta accu
lda #0
sta accu+1
};
}
To write something to these higher memory banks, you can use poke24, which goes the other way:
void poke24(unsigned long addr, unsigned char value)
{
__asm {
lda addr
sta 0x05
lda addr+1
sta 0x06
lda addr+2
sta 0x07
ldx 0x00
ldy 0x01
txa
ora #0x08
php
sei
sta 0x00
tya
ora #0x30
sta 0x01
lda value
byt 0x87
byt 0x05
stx 0x00
sty 0x01
plp
ldx #0x00
};
}
"Troubleshoot Gotchas" during compilation
None to report so far.