Added A2-3D2 example.

This commit is contained in:
Scott Duensing 2024-04-07 16:54:52 -05:00
parent 72a6812c1a
commit cd27a5061a
23 changed files with 924 additions and 88 deletions

View file

@ -28,6 +28,7 @@ TARGET=f256lib.h
cat f256lib/stddclmr.h > ${TARGET}
echo "#ifndef F256LIB_AMALGAMATED_BUILD" >> ${TARGET}
echo "#define F256LIB_AMALGAMATED_BUILD" >> ${TARGET}
cat f256lib/f_api.h >> ${TARGET}
@ -73,4 +74,5 @@ cat f256lib/f_sprite.c >> ${TARGET}
cat f256lib/f_file.c >> ${TARGET}
cat f256lib/f_platform.c >> ${TARGET}
echo "#endif" >> ${TARGET}
echo "#endif // F256LIB_IMPLEMENTATION" >> ${TARGET}
echo "#endif // F256LIB_AMALGAMATED_BUILD" >> ${TARGET}

BIN
examples/a23d2/a2-3d/A2-3D2#066000 (Stored with Git LFS) Normal file

Binary file not shown.

75
examples/a23d2/build.sh Executable file
View file

@ -0,0 +1,75 @@
#!/bin/bash -ex
#
# Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
PROJECT=3ddemo
F256=$(readlink -f $(pwd)/../..)
LLVM=${F256}/llvm-mos
PATH=${LLVM}/bin:${PATH}
CLANG="mos-f256k-clang -I${F256} -I$(pwd)/src -Os"
# Out-of-tree build to keep things tidy.
[[ -d .builddir ]] && rm -rf .builddir
mkdir -p .builddir
# Generate overlay data. Do not use relative paths.
${F256}/overlay 5 $(pwd)/.builddir $(pwd)/src
pushd .builddir
# Copy Apple ][ binary library A2-3D2 and truncate it to 8k.
# The truncated bits are Apple ][ rendering code, so we don't need it.
cp ../a2-3d/A2-3D2#066000 a2-3d2.bin
truncate -s 8k a2-3d2.bin
# Compile the 3D scene database generator and run it.
cc -I../src -I${F256} ../tools/scene.c -o scene
./scene
# Concatinate our embedded binary data into a single file.
cat a2-3d2.bin scene.3d > embedded.bin
# Compile our code and the A2-3D2 support library.
${CLANG} -c main.c
${CLANG} -c a23d2.c
# Link!
${CLANG} -T ../f256.ld \
-Wl,-Map=${PROJECT}.map \
-o ${PROJECT} \
main.o a23d2.o
# Rename results to PGZ.
mv ${PROJECT} ${PROJECT}.pgz
# Generate debugging goodness.
llvm-nm ${PROJECT}.elf > ${PROJECT}.sym
llvm-objdump --syms -d --print-imm-hex ${PROJECT}.elf > ${PROJECT}.lst
hexdump -C ${PROJECT}.pgz > ${PROJECT}.hex
python ${F256}/pgz-thunk.py ${PROJECT}.pgz
# Put the PGZ in the main directory.
mv ${PROJECT}.pgz ../.
popd

116
examples/a23d2/f256.ld Normal file
View file

@ -0,0 +1,116 @@
/* fake C Stack */
PROVIDE(__stack = 0xA000);
/* entry point to my program */
PROVIDE(__f256_start = 0x300);
/* page size of a block of memory */
PROVIDE(__BLOCK_SIZE = 0x2000);
/* swappable block address */
PROVIDE(__SLOT_ADDR = 0xA000);
/* f256k uses first 16 bytes of ZP for mmu control? */
__rc0 = 0x10;
/* __rc0 = 0xc3; */
INCLUDE imag-regs.ld
/*
ASSERT(__rc0 == 0x10, "Inconsistent zero page map.")
ASSERT(__rc31 == 0x2f, "Inconsistent zero page map.")
*/
MEMORY {
/* kernel uses 0xf0-0xff for parameter passing */
/* A2-3D2 uses 0x60-0xc2 */
zp : ORIGIN = __rc31 + 1, LENGTH = 0xF0 - (__rc31 + 1)
/* zp : ORIGIN = 0x10, LENGTH = 80 */
ram (rw) : ORIGIN = __f256_start, LENGTH = __stack-__f256_start
}
/* LMAs */
__block8_lma = ( 8<<24)|__SLOT_ADDR;
__block9_lma = ( 9<<24)|__SLOT_ADDR;
__block10_lma = (10<<24)|__SLOT_ADDR;
__block11_lma = (11<<24)|__SLOT_ADDR;
__block12_lma = (12<<24)|__SLOT_ADDR;
__block13_lma = (13<<24)|__SLOT_ADDR;
__block14_lma = (14<<24)|__SLOT_ADDR;
__block15_lma = (15<<24)|__SLOT_ADDR;
__block16_lma = (16<<24)|__SLOT_ADDR;
__block17_lma = (17<<24)|__SLOT_ADDR;
__block18_lma = (18<<24)|__SLOT_ADDR;
__block19_lma = (19<<24)|__SLOT_ADDR;
__block20_lma = (20<<24)|__SLOT_ADDR;
__block21_lma = (21<<24)|__SLOT_ADDR;
__block22_lma = (22<<24)|__SLOT_ADDR;
__block23_lma = (23<<24)|__SLOT_ADDR;
/* Stash preloaded binary data */
__binarydata_lma = 0x54000; /* Block 42 */
__BINARYDATA_SIZE = 0x2C000; /* Size of A2-3D2, 3D/2D data area, and 2 bitmaps. */
MEMORY {
block8 : ORIGIN = __block8_lma, LENGTH = __BLOCK_SIZE
block9 : ORIGIN = __block9_lma, LENGTH = __BLOCK_SIZE
block10 : ORIGIN = __block10_lma, LENGTH = __BLOCK_SIZE
block11 : ORIGIN = __block11_lma, LENGTH = __BLOCK_SIZE
block12 : ORIGIN = __block12_lma, LENGTH = __BLOCK_SIZE
block13 : ORIGIN = __block13_lma, LENGTH = __BLOCK_SIZE
block14 : ORIGIN = __block14_lma, LENGTH = __BLOCK_SIZE
block15 : ORIGIN = __block15_lma, LENGTH = __BLOCK_SIZE
block16 : ORIGIN = __block16_lma, LENGTH = __BLOCK_SIZE
block17 : ORIGIN = __block17_lma, LENGTH = __BLOCK_SIZE
block18 : ORIGIN = __block18_lma, LENGTH = __BLOCK_SIZE
block19 : ORIGIN = __block19_lma, LENGTH = __BLOCK_SIZE
block20 : ORIGIN = __block20_lma, LENGTH = __BLOCK_SIZE
block21 : ORIGIN = __block21_lma, LENGTH = __BLOCK_SIZE
block22 : ORIGIN = __block22_lma, LENGTH = __BLOCK_SIZE
block23 : ORIGIN = __block23_lma, LENGTH = __BLOCK_SIZE
binarydata : ORIGIN = __binarydata_lma, LENGTH = __BINARYDATA_SIZE
}
REGION_ALIAS("c_writeable", ram)
REGION_ALIAS("c_readonly", ram)
SECTIONS {
INCLUDE c.ld
.block8 : { *(.block8 .block8.*) } >block8 end_block8 = .;
.block9 : { *(.block9 .block9.*) } >block9 end_block9 = .;
.block10 : { *(.block10 .block10.*) } >block10 end_block10 = .;
.block11 : { *(.block11 .block11.*) } >block11 end_block11 = .;
.block12 : { *(.block12 .block12.*) } >block12 end_block12 = .;
.block13 : { *(.block13 .block13.*) } >block13 end_block13 = .;
.block14 : { *(.block14 .block14.*) } >block14 end_block14 = .;
.block15 : { *(.block15 .block15.*) } >block15 end_block15 = .;
.block16 : { *(.block16 .block16.*) } >block16 end_block16 = .;
.block17 : { *(.block17 .block17.*) } >block17 end_block17 = .;
.block18 : { *(.block18 .block18.*) } >block18 end_block18 = .;
.block19 : { *(.block19 .block19.*) } >block19 end_block19 = .;
.block20 : { *(.block20 .block20.*) } >block20 end_block20 = .;
.block21 : { *(.block21 .block21.*) } >block21 end_block21 = .;
.block22 : { *(.block22 .block22.*) } >block22 end_block22 = .;
.block23 : { *(.block23 .block23.*) } >block23 end_block23 = .;
.binarydata : { *(.binarydata .binarydata.*) } >binarydata end_binarydata = .;
}
OUTPUT_FORMAT {
BYTE(0x5A) /* pgZ */
/* RAM Segment */
SHORT(ORIGIN(ram)) /* where to load it, 24 bits */
BYTE(0x00)
SHORT(__bss_start-ORIGIN(ram)) /* size to load */
BYTE(0x00)
TRIM(ram)
/* Overlay Segments */
INCLUDE output.ld
/* Binary Data */
SHORT(ORIGIN(binarydata))
BYTE(ORIGIN(binarydata)>>16)
SHORT(end_binarydata - __binarydata_lma)
BYTE((end_binarydata - __binarydata_lma)>>16)
TRIM(binarydata)
/* Launch the program, at _start */
SHORT(_start)
LONG(0)
}

26
examples/a23d2/run.sh Executable file
View file

@ -0,0 +1,26 @@
#!/bin/bash
#
# Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
python ../../FoenixMgr/FoenixMgr/fnxmgr.py --run-pgz 3ddemo.pgz

178
examples/a23d2/src/a23d2.c Normal file
View file

@ -0,0 +1,178 @@
/*
* Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "a23d2.h"
#include <string.h> // For memcopy
cameraT *_camera = (cameraT *)0x200; // Simulation copy of camera.
cameraT *_cameraInDatabase;
uint16_t _drawlist;
uint16_t _drawlistInDatabase;
byte *_pointer;
uint16_t _bytes;
uint8_t _x1;
uint8_t _y1;
uint8_t _x2;
uint8_t _y2;
bool _useColor;
byte _mmu;
byte _ram;
#define SEGMENT_A23D2
// There's a lot of global use in here. We can't use the virtual stack.
void a23d2Draw(void) {
_pointer = (byte *)_drawlist;
// Move our 3D/2D data buffer at 0x56000 into slot 4.
POKE(MMU_MEM_BANK_4, DATABASE_FAR_BLOCK);
while (true) {
switch (*_pointer++) {
// Line.
case (byte)LIN2D:
_x1 = (uint8_t)((int8_t)(*_pointer++) + 128);
_y1 = 255 - (uint8_t)((int8_t)(*_pointer++) + 128);
_x2 = (uint8_t)((int8_t)(*_pointer++) + 128);
_y2 = 255 - (uint8_t)((int8_t)(*_pointer++) + 128);
bitmapLine(_x1, _y1, _x2, _y2);
continue;
// Point.
case (byte)PNT2D:
_x1 = (uint8_t)((int8_t)(*_pointer++) + 128);
_y1 = 255 - (uint8_t)((int8_t)(*_pointer++) + 128);
bitmapPutPixel(_x1, _y1);
continue;
// Set Color.
case (byte)STCOL:
_x1 = (int8_t)(*_pointer++);
if (_useColor) bitmapSetColor(_x1);
continue;
// Set Resolution.
case (byte)SRES:
// Eat this byte. We don't need it.
_pointer++;
continue;
// End.
case (byte)END:
break;
}
break;
}
// Restore memory map.
POKE(MMU_MEM_BANK_4, 4);
}
void a23d2Init(void) {
// We need to manually page 0x54000 into 0x6000.
// This isn't actually large enough for A2-3D2 but what we should only
// lose Apple ][ stuff we're not using anyway.
POKE(MMU_MEM_BANK_3, A23D2_FAR_BLOCK);
// We're going to clobber from 0x80fb to 0x8101. Back it up.
memcpy((byte *)0x2f7, (byte *)0x80fb, 0x06);
// Initialize A2-3D2 so we can use the "fast entry point" (NXTPT) when rendering.
_bytes = 0;
_pointer = (byte *)0x80fb; // Standard location for test database in A2-3D2.
_pointer[_bytes++] = SCRSZ; // Screen size. 256x240. Center is 0,0.
_pointer[_bytes++] = 255;
_pointer[_bytes++] = 239;
_pointer[_bytes++] = 0;
_pointer[_bytes++] = 0;
_pointer[_bytes++] = END; // Setup complete!
asm("jsr 0x606c"); // Call ENTRYS. This preserves the ZP for us.
// Put back the RAM we clobbered.
memcpy((byte *)0x80fb, (byte *)0x2f7, 0x06);
// Move our 3D/2D data buffer at 0x56000 into slot 4.
POKE(MMU_MEM_BANK_4, DATABASE_FAR_BLOCK);
// Set up drawlists.
_drawlistInDatabase = DATABASE + 1; // First value after ARRAY in near memory.
POKE(DRAWLIST_P0, END);
POKE(DRAWLIST_P1, END);
// Set up camera.
_cameraInDatabase = (cameraT *)(DATABASE + 4); // First value after EYE in near memory.
_camera->x = _cameraInDatabase->x;
_camera->y = _cameraInDatabase->y;
_camera->z = _cameraInDatabase->z;
_camera->p = _cameraInDatabase->p;
_camera->b = _cameraInDatabase->b;
_camera->h = _cameraInDatabase->h;
// Restore memory map.
POKE(MMU_MEM_BANK_4, 4);
POKE(MMU_MEM_BANK_3, 3);
}
void a23d2Render(void) {
// We need to manually page 0x54000 into 0x6000.
// This isn't actually large enough for A2-3D2 but what we should only
// lose Apple ][ stuff we're not using anyway.
POKE(MMU_MEM_BANK_3, A23D2_FAR_BLOCK);
// Move our 3D/2D data buffer at 0x56000 into slot 4.
POKE(MMU_MEM_BANK_4, DATABASE_FAR_BLOCK);
// Update drawlist.
POKEW(_drawlistInDatabase, _drawlist);
// Update camera position.
_cameraInDatabase->x = _camera->x;
_cameraInDatabase->y = _camera->y;
_cameraInDatabase->z = _camera->z;
_cameraInDatabase->p = _camera->p;
_cameraInDatabase->b = _camera->b;
_cameraInDatabase->h = _camera->h;
memcpy((byte *)0x29d, (byte *)0x60, 0x62); // Save the ZP we're going to clobber.
POKEW(0x9b, DATABASE); // Set IBP.
asm("jsr 0x6118":::"a","x","y","c","v"); // Call NXTPT.
memcpy((byte *)0x60, (byte *)0x29d, 0x62); // Put the ZP back.
// Restore memory map.
POKE(MMU_MEM_BANK_4, 4);
POKE(MMU_MEM_BANK_3, 3);
}

111
examples/a23d2/src/a23d2.h Normal file
View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifdef __F256K__
#include "f256lib.h"
#else
#include <stdint.h>
#include <stdbool.h>
typedef uint8_t byte;
#endif
#define A23D2_FAR_BLOCK 42
#define DATABASE_FAR_BLOCK 43
#define DATABASE_FAR 0x56000
#define DRAWLIST_P0_FAR 0x57000
#define DRAWLIST_P1_FAR 0x57800
#define DATABASE 0x8000
#define DRAWLIST_P0 0x9000
#define DRAWLIST_P1 0x9800
// A2-3D1 Commands. Commented out items are Apple ][ only.
#define PNT 0x00 // xLSB, xMSB, yLSB, yMSB, zLSB, zMSB - Define 3D Point
#define SPNT 0x01 // xLSB, xMSB, yLSB, yMSB, zLSB, zMSB - Define 3D Start Point
#define CPNT 0x02 // xLSB, xMSB, yLSB, yMSB, zLSB, zMSB - Define 3D Continue Point
#define RAY 0x03 // xLSB, xMSB, yLSB, yMSB, zLSB, zMSB - Define 3D Ray
#define CLPSW 0x04 // N - Define Clipper (0=off, 1=on)
#define EYE 0x05 // xLSB, xMSB, yLSB, yMSB, zLSB, zMSB, P, B, H - Define 3D Eye/Camera
#define LIN2D 0x06 // X1, Y1, X2, Y2 - Draw 2D Line
//#define DISP 0x07 // N - Display Select (50=set graphics, 51=set text, 52=clear mixed, 53=set mixed, 54=set page 1, 55=set page 2, 56=clear hi-res, 57=set hi-res)
//#define ERAS 0x08 // N - Erase Screen (0=erase page 1, 1=erase page 2, 2=fill page 1, 3=fill page 2)
//#define DRAW 0x09 // N - Select Draw Page (0=page 1, 1=page 2)
#define PNT2D 0x0a // X1, Y1 - Draw 2D Point
#define JMP 0x0b // LSB, MSB - Interpretive Jump
//#define LMODE 0x0c // N - Line Drawing Mode (0=solid, 1=xor)
#define ARRAY 0x0d // LSB, MSB - Enable Output Array
#define SCRSZ 0x0e // WIDTH, HEIGHT, xCENTER, yCENTER - Define Screen Size
#define FIELD 0x0f // xLSB, xMSB, yLSB, yMSB, zLSB, zMSB - Field of View Selection
#define INIT 0x10 // Easy Init
#define NOP 0x11 // No Operation
// A2-3D2 Commands. Commented out items are Apple ][ only.
#define STCOL 0x12 // COL - Set Color
#define ICALL 0x13 // STAT, LOC, ADDR - Independent Object Call
#define SRES 0x14 // RES - Set Resolution (0=140x192, 1=280x192)
//#define HLIN 0x15 // x1L, x1H, y1, x2L, x2H, y2 - Hi-Res (280x192) Line 2D
//#define SHRB 0x16 // xL, xH, y - Set Hi-Res Bias
//#define HLIN2 0x17 // x1, y1, x2, y2 - Hi-Res (x limited) Line 2D
//#define HPNT 0x18 // xL, xH, y - Hi-Res (280x192) Point 2D
//#define HPNT2 0x19 // x, y - Hi-Res (x limited) Point 2D
#define SKIP 0x1a // SIZE, STATUS - Skip Segment
//#define PAUS 0x1b // TIME - Pause for TIME/5ths of a Second
#define SET323 0x1c // LSB, MSB - Set 3D to 3D Array Address
#define GN323 0x1d // STATUS - Set 3D to 3D Status
#define END 0x79 // End of Database
typedef struct cameraS {
int16_t x;
int16_t y;
int16_t z;
byte p;
byte b;
byte h;
} cameraT;
extern cameraT *_camera;
extern cameraT *_cameraInDatabase;
extern uint16_t _drawlist;
extern uint16_t _drawlistInDatabase;
extern byte *_pointer;
extern uint16_t _bytes;
extern uint8_t _x1;
extern uint8_t _y1;
extern uint8_t _x2;
extern uint8_t _y2;
extern bool _useColor;
extern byte _mmu;
extern byte _ram;
// NOTE:
// There are no function prototypes in this header.
// This library lives in it's own overlay segment and the overlay tool
// will generate prototypes as well as trampoline macros for us.

230
examples/a23d2/src/main.c Normal file
View file

@ -0,0 +1,230 @@
/*
* Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Memory Map:
*
* Far Heap (upper 448k):
*
* 0x7ffff - Top of far heap / End of bitmap page 1
* - Bitmap page is 0x14000 (81920 bytes)
* 0x6c000 - Start of bitmap page 1
* 0x6bfff - End of bitmap page 2
* - Bitmap page is 0x14000 (81920 bytes)
* 0x58000 - Start of bitmap page 2
* 0x57fff - End of A2-3D2 and data to be used in slots 3 and 2/4 below
* - ...
* 0x54000 - Start of A2-3D2 and data to be used in slots 3 and 2/4 below
* - 57344 bytes free
* 0x45fff - End of overlay code
* - ...
* 0x10000 - Bottom of far heap / Start of overlay code
*
*
* Near Heap (lower 64k):
*
* 0xffff - Top of near heap
* - ...
* 0xe000 - Microkernel
* - ...
* 0xc000 - I/O and microkernel
* - ...
* 0xa000 - Overlay code
* 0x9fff - Top of virtual stack
* - ...
* 0x8000 - Program code / 3D/2D data
* - ...
* 0x6000 - Program code / 3D library
* - ...
* 0x0300 - Start of program code
* 0x02ff - End of program arguments / data storage
* - ... (We're going to overwrite this!)
* 0x0200 - Start of program arguments / data storage
* 0x01ff - Top of CPU stack space
* - ...
* 0x0100 - Bottom of CPU stack space
* 0x00ff - End of microkernel use
* - ...
* 0x00f0 - Start of microkernel use
* - 46 bytes free
* 0x00c2 - End of A2-3D2 use
* - ...
* 0x0060 - Start of A2-3D2 use
* - 49 bytes free
* 0x002f - llvm virtual register 31
* - ...
* 0x0010 - llvm virtual register 0
* 0x000f - MMU_MEM_BANK_7
* - ...
* 0x0008 - MMU_MEM_BANK_0
* - 7 bytes free
* 0x0001 - MMU_IO_CTRL
* 0x0000 - MMU_MEM_CTRL
*
*
* Calling the 3D Renderer:
*
* The MMU splits the near heap into 8k "slots" that 8k "blocks" of far heap
* can be mapped into. f256lib, by default, sets the near heap up as
* follows:
*
* 0xe000 - Slot 7 - Microkernel
* 0xc000 - Slot 6 - I/O and Microkernel
* 0xa000 - Slot 5 - Code Overlay Region
* 0x8000 - Slot 4 - Program Code
* 0x6000 - Slot 3 - Program Code
* 0x4000 - Slot 2 - Program Code
* 0x2000 - Slot 1 - Program Code
* 0x0000 - Slot 0 - Zero Page & Program Code
*
* Our 3D library, subLOGIC's A2-3D2, was designed to be run on an Apple ][.
* The Apple ][ has two high-resolution video pages in the middle of the
* memory map and A2-3D2 loads at 0x6000 immediately after the second video
* page. This makes sense on the Apple. On the Foenix, it's in the way at
* slot 3. The library also needs a 3D scene database and outputs an array
* of 2D drawing instructions. Given the size of A2-3D2 this pushes our
* memory usage up into slot 4. This leaves slots 0 to 2 for the simulator.
* That's less than 24k. Not good.
*
* We're going to place the 3D library and related data in the far heap and
* manually swap them in using the MMU when we need to render the scene. To
* do this, we need to ensure we're not currently executing code from
* somewhere in the slot 2 to 4 range. To accomplish this, all the functions
* that deal with A2-3D2 are placed in an overlay. This ensures whatever
* code calls into slots 2 to 4 has a program counter between 0xa000 and
* 0xbfff - well out of the way of the 3D stuff.
*
* The last thing to worry about is data needed by both the simulator and
* A2-3D2. This is basically only the camera position and rotation. These
* 10 bytes will be stored directly into RAM from 0x200 to 0x20a overwriting
* any command line arguments that may have been in memory.
*
*/
#define WITHOUT_FILE
#define WITHOUT_SPRITE
#define WITHOUT_TILE
#define F256LIB_IMPLEMENTATION
#include "f256lib.h"
#include "a23d2.h"
/*
* embedded.bin is loaded at 0x54000:
*
* 8k a2-3d2.bin @ 0x54000
* 8k scene.3d @ 0x56000
*
*/
EMBED(".binarydata.embedded", embedded, "embedded.bin");
void runSimulation(void) {
bool pageZero;
// Which page is visible?
pageZero = true;
// Draw it!
while (true) {
// Flip pages.
if (pageZero) {
// Looking at bitmap 0.
pageZero = false;
bitmapSetActive(1);
bitmapSetVisible(0, true);
bitmapSetVisible(1, false);
_drawlist = DRAWLIST_P1;
} else {
// Looking at bitmap 1.
pageZero = true;
bitmapSetActive(0);
bitmapSetVisible(1, true);
bitmapSetVisible(0, false);
_drawlist = DRAWLIST_P0;
}
// Erase old scene.
bitmapSetColor(0);
_useColor = false;
a23d2Draw();
// Draw new scene.
a23d2Render();
_useColor = true;
a23d2Draw();
// Move camera.
_camera->p += 1; // Change pitch angle.
_camera->b += 2; // Change bank angle.
_camera->h += 3; // Change heading angle.
}
}
int main(int argc, char *argv[]) {
byte c;
byte ega[16][3] = {
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0xaa },
{ 0x00, 0xaa, 0x00 },
{ 0x00, 0xaa, 0xaa },
{ 0xaa, 0x00, 0x00 },
{ 0xaa, 0x00, 0xaa },
{ 0xaa, 0x55, 0x00 },
{ 0xaa, 0xaa, 0xaa },
{ 0x55, 0x55, 0x55 },
{ 0x55, 0x55, 0xff },
{ 0x55, 0xff, 0x55 },
{ 0x55, 0xff, 0xff },
{ 0xff, 0x55, 0x55 },
{ 0xff, 0x55, 0xff },
{ 0xff, 0xff, 0x55 },
{ 0xff, 0xff, 0xff }
};
// Load EGA palette into CLUT0.
for (c=0; c<16; c++) graphicsDefineColor(0, c, ega[c][0], ega[c][1], ega[c][2]);
a23d2Init();
// Set up bitmap planes.
for (c=0; c<2; c++) {
// Clear screen.
bitmapSetActive(c);
bitmapSetColor(0);
bitmapClear();
// 3D Viewport edge.
bitmapSetColor(14);
bitmapLine(256, 0, 256, 239);
}
bitmapSetVisible(0, true);
bitmapSetVisible(1, false);
runSimulation();
return 0;
}

View file

@ -0,0 +1,96 @@
/*
* Copyright (c) 2024 Scott Duensing, scott@kangaroopunch.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include "a23d2.h"
uint8_t db[8192] = { 0 };
uint16_t bytes = 0;
void cube(void) {
int16_t i = 0;
uint8_t scene[] = {
STCOL, 0x04, // Red
SPNT, 0x00, 0xff, 0x00, 0xff, 0x00, 0x03, // Cube
CPNT, 0x00, 0x01, 0x00, 0xff, 0x00, 0x03,
CPNT, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03,
CPNT, 0x00, 0xff, 0x00, 0x01, 0x00, 0x03,
CPNT, 0x00, 0xff, 0x00, 0xff, 0x00, 0x03,
CPNT, 0x00, 0xff, 0x00, 0xff, 0x00, 0x05,
CPNT, 0x00, 0x01, 0x00, 0xff, 0x00, 0x05,
RAY, 0x00, 0x01, 0x00, 0xff, 0x00, 0x03,
CPNT, 0x00, 0x01, 0x00, 0x01, 0x00, 0x05,
RAY, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03,
CPNT, 0x00, 0xff, 0x00, 0x01, 0x00, 0x05,
RAY, 0x00, 0xff, 0x00, 0x01, 0x00, 0x03,
CPNT, 0x00, 0xff, 0x00, 0xff, 0x00, 0x05,
SPNT, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, // Edge Line
CPNT, 0x00, 0x00, 0x80, 0x00, 0x00, 0x03,
END
};
while (scene[i] != END) {
db[bytes++] = scene[i++];
}
}
int main(int argc, char *argv[]) {
FILE *out;
// All scene databases need to begin with the ARRAY and EYE records.
// The CLPSW clipping setting is up to you. :-)
db[bytes++] = ARRAY; // Will be filled in by the program.
db[bytes++] = 0;
db[bytes++] = 0;
db[bytes++] = EYE; // Will be filled in by the program.
db[bytes++] = 0x00; // X
db[bytes++] = 0x00;
db[bytes++] = 0x00; // Y
db[bytes++] = 0x00;
db[bytes++] = 0x00; // Z
db[bytes++] = 0x00;
db[bytes++] = 0x00; // P
db[bytes++] = 0x00; // B
db[bytes++] = 0x00; // H
db[bytes++] = CLPSW;
db[bytes++] = 0x00;
cube();
db[bytes++] = END;
out = fopen("scene.3d", "wb");
if (out) {
fwrite(db, 1, 8192, out);
fclose(out);
}
return 0;
}

View file

@ -1,7 +0,0 @@
[DEFAULT]
port=/dev/ttyUSB1
labels=sample.lbl
flash_address=380000
chunk_size=1024
cpu=65c02
data_rate=6000000

View file

@ -1,7 +0,0 @@
[DEFAULT]
port=/dev/ttyUSB1
labels=sample.lbl
flash_address=380000
chunk_size=1024
cpu=65c02
data_rate=6000000

View file

@ -1,7 +0,0 @@
[DEFAULT]
port=/dev/ttyUSB1
labels=sample.lbl
flash_address=380000
chunk_size=1024
cpu=65c02
data_rate=6000000

View file

@ -1,7 +0,0 @@
[DEFAULT]
port=/dev/ttyUSB1
labels=sample.lbl
flash_address=380000
chunk_size=1024
cpu=65c02
data_rate=6000000

View file

@ -1,7 +0,0 @@
[DEFAULT]
port=/dev/ttyUSB1
labels=sample.lbl
flash_address=380000
chunk_size=1024
cpu=65c02
data_rate=6000000

View file

@ -25,6 +25,19 @@
#include "../../f256lib.h"
/*
* Add return values to overlay tool.
* Overlay tool may need to generate prototypes for multiple file programs.
* Move bitmap memory to top of far ram.
* Add cc65 support.
* Move docs to top of amalgamated build.
* Check out https://github.com/econtrerasd/VickyGraph/tree/main/Calypsi-65816-grfdemo/src
* Find way to create Windows version binaries.
* Docs!
*
*/
void dirtest(void) {
DIR *dir;

View file

@ -1,7 +0,0 @@
[DEFAULT]
port=/dev/ttyUSB1
labels=sample.lbl
flash_address=380000
chunk_size=1024
cpu=65c02
data_rate=6000000

View file

@ -1,7 +0,0 @@
[DEFAULT]
port=/dev/ttyUSB1
labels=sample.lbl
flash_address=380000
chunk_size=1024
cpu=65c02
data_rate=6000000

View file

@ -58,7 +58,7 @@ void f256Init(void) {
#ifndef WITHOUT_KERNEL
kernelReset();
#endif
#if !(defined WITHOUT_BITMAP || defined WITHOUT_TILE || defined WITHOUT_SPRITE)
#ifndef WITHOUT_GRAPHICS
graphicsReset();
#endif
#ifndef WITHOUT_TEXT

View file

@ -125,31 +125,18 @@ typedef unsigned char bool;
// Near memory slot to use for far memory swapping.
#ifndef SWAP_SLOT
#define SWAP_SLOT MMU_MEM_BANK_5
#define SWAP_SLOT MMU_MEM_BANK_7
#endif
// This is an attempt to allow us to free up slot 5 and use other slots
// for swapping RAM in and out. ***TODO*** Currently, it does not work.
#if SWAP_SLOT == MMU_MEM_BANK_6
#if SWAP_SLOT == MMU_MEM_BANK_7
#define SWAP_IO_SETUP() \
byte sios_mmu = PEEK(MMU_IO_CTRL); \
byte sios_ram = PEEK(MMU_MEM_BANK_6); \
({ \
asm("sei"); \
POKE(MMU_IO_CTRL, 4); \
})
#define SWAP_IO_SETUP() \
byte sios_ram = PEEK(MMU_MEM_BANK_7); \
asm("sei");
#define SWAP_IO_SHUTDOWN() ({ \
POKE(MMU_MEM_BANK_6, sios_ram); \
POKE(MMU_IO_CTRL, sios_mmu); \
asm("cli"); \
})
#elif SWAP_SLOT == MMU_MEM_BANK_7
#define SWAP_IO_SETUP() asm("sei");
#define SWAP_IO_SHUTDOWN() asm("cli");
#define SWAP_IO_SHUTDOWN() \
POKE(MMU_MEM_BANK_7, sios_ram); \
asm("cli");
#else
@ -168,7 +155,7 @@ typedef unsigned char bool;
// Things not in the Merlin defs.
#define EIGHTK 0x2000
#define EIGHTK 0x2000
#define TEXT_MATRIX 0xc000 // I/O Page 2
@ -202,6 +189,25 @@ typedef struct colorS {
} colorT;
// Allow embedding binary data into program
#define IBSTR2(x) #x
#define IBSTR(x) IBSTR2(x)
#define EMBED(INCBIN_SECTION, name, file) \
__asm__(".section " INCBIN_SECTION ",\"aR\" \n" \
".global incbin_" IBSTR(name) "_start\n" \
".balign 16\n" \
"incbin_" IBSTR(name) "_start:\n" \
".incbin \"" file "\"\n" \
\
".global incbin_" IBSTR(name) "_end\n" \
".balign 1\n" \
"incbin_" IBSTR(name) "_end:\n" \
".byte 0\n" \
); \
extern __attribute__((aligned(16))) const char incbin_ ## name ## _start[]; \
extern const char incbin_ ## name ## _end[]
// Single-byte
#define PEEK(addy) ((byte)*(volatile byte *)(addy))
#define POKE(addy, value) (*(volatile byte *)(addy) = (value))
@ -219,8 +225,8 @@ typedef struct colorS {
#define POKED(addy,value) (*(volatile uint32_t *)(addy) = (value))
// Bit fun.
#define LOW_BYTE(v) ((byte)(x))
#define HIGH_BYTE(v) ((byte)(((uint16_t)(x)) >> 8))
#define LOW_BYTE(x) ((byte)(x))
#define HIGH_BYTE(x) ((byte)(((uint16_t)(x)) >> 8))
#define SWAP_NIBBLES(x) ((x & 0x0F) << 4 | (x & 0xF0) >> 4)
#define SWAP_UINT16(x) (((x) >> 8) | ((x) << 8))
#define CHECK_BIT(x, pos) (x & (1UL << pos))

View file

@ -36,10 +36,17 @@ static uint32_t _PAGE_SIZE;
static uint32_t _BITMAP_BASE[3]; // Maximum of 3 pages possible.
static byte _BITMAP_CLUT[3];
static byte _color;
static byte _active; // Current drawing page.
static byte _active; // Current drawing page.
// uint32_t address = _BITMAP_BASE[_active] + (y * _MAX_X + (int32_t)x); \
#define bitmapPutPixelIOSet(x, y) FAR_POKE((_BITMAP_BASE[_active] + mathUnsignedAddition(mathUnsignedMultiply(y, _MAX_X), (int32_t)x)), _color)
#define bitmapPutPixelIOSet(x, y) ({ \
uint32_t address = _BITMAP_BASE[_active] + mathUnsignedAddition(mathUnsignedMultiply(y, _MAX_X), (int32_t)x); \
byte block = address / EIGHTK; \
address &= 0x1FFF; \
POKE(SWAP_SLOT, block); \
POKE(SWAP_ADDR + address, _color); \
})
void bitmapClear(void) {
@ -64,7 +71,6 @@ void bitmapClear(void) {
for (c=0; c<5120; c++) mem[c] = _color;
SWAP_RESTORE_SLOT();
SWAP_IO_SHUTDOWN();
#endif
}
@ -137,7 +143,6 @@ void bitmapLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
}
SWAP_RESTORE_SLOT();
SWAP_IO_SHUTDOWN();
}
@ -166,11 +171,12 @@ void bitmapReset(void) {
// Fractional pageBlock. Round up.
pageBlocks++;
}
realSize = mathUnsignedMultiply(pageBlocks, EIGHTK);
realSize = mathUnsignedMultiply(pageBlocks, EIGHTK); // Works out to 80k or 0x14000.
_BITMAP_BASE[0] = 0x10000;
_BITMAP_BASE[1] = mathUnsignedAddition(_BITMAP_BASE[0], realSize); // Page 2 = 0x24000
_BITMAP_BASE[2] = mathUnsignedAddition(_BITMAP_BASE[1], realSize); // Page 3 = 0x38000
// Bitmaps start at the top of far memory and work downwards for each additional page.
_BITMAP_BASE[0] = 0x080000 - realSize; // Page 1 = 0x6c000
_BITMAP_BASE[1] = _BITMAP_BASE[0] - realSize; // Page 2 = 0x58000
_BITMAP_BASE[2] = _BITMAP_BASE[1] - realSize; // Page 3 = 0x44000
/*
textPrint("\nbase0 = "); textPrintInt(_BITMAP_BASE[0]);

View file

@ -33,27 +33,39 @@ static void dmaWait(void);
void dmaFill(uint32_t start, uint32_t length, byte value) {
while (PEEKW(RAST_ROW_L) != 482); // Wait for VBL.
POKE(DMA_CTRL, DMA_CTRL_FILL | DMA_CTRL_ENABLE);
POKE(DMA_FILL_VAL, value);
POKEA(DMA_DST_ADDR, start);
POKEA(DMA_COUNT, length);
POKE(DMA_CTRL, PEEK(DMA_CTRL) | DMA_CTRL_START);
dmaWait();
// dmaWait();
}
void dma2dFill(uint32_t start, uint16_t width, uint16_t height, uint16_t stride, byte value) {
POKE(DMA_CTRL, DMA_CTRL_2D | DMA_CTRL_ENABLE);
while (PEEKW(RAST_ROW_L) != 482); // Wait for VBL.
asm("sei");
POKE(DMA_CTRL, DMA_CTRL_2D | DMA_CTRL_FILL | DMA_CTRL_ENABLE);
POKE(DMA_FILL_VAL, value);
POKEA(DMA_DST_ADDR, start);
POKEW(DMA_WIDTH, width);
POKEW(DMA_HEIGHT, height);
POKEW(DMA_STRIDE_DST, stride);
POKE(DMA_CTRL, PEEK(DMA_CTRL) | DMA_CTRL_START);
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("nop");
asm("cli");
dmaWait();
// dmaWait();
}

View file

@ -30,6 +30,7 @@
#endif
//***FIX*** IIgs colors aren't as useful as EGA colors.
colorT textColors[16] = {
{ 0x00, 0x00, 0x00 }, // 0 Black
{ 0xdd, 0x00, 0x33 }, // 1 Deep Red

View file

@ -47,6 +47,8 @@ void trimEnd(char *string);
void findBank(char *name) {
int x;
printf("Found Segment: %s\n", name);
// Is this the MAIN segment?
if (strcmp(name, "MAIN") == 0) {
_currentBank = 0;
@ -83,6 +85,7 @@ void parseCFile(char *filename, char *targetFile, FILE *trampoline, char *trampo
char *b;
bool found;
int x;
int line = 1;
int comments = 0;
bool inComment = false;
int brackets = 0;
@ -102,6 +105,9 @@ void parseCFile(char *filename, char *targetFile, FILE *trampoline, char *trampo
* Someone should fix it. :-)
*/
// Always start in the lower 64k.
_currentBank = 0;
in = fopen(filename, "rt");
if (in == NULL) {
fclose(trampoline);
@ -132,10 +138,10 @@ void parseCFile(char *filename, char *targetFile, FILE *trampoline, char *trampo
if ((c == '/') && (pos > 0) && (buffer[pos-1] == '/')) inComment = true;
// Look for '/*' comment start.
if ((c == '*') && (pos > 0) && (buffer[pos-1] == '/')) comments++;
if ((c == '*') && (pos > 0) && (buffer[pos-1] == '/') && !inComment) comments++;
// Look for '*/' comment end.
if ((c == '/') && (pos > 0) && (buffer[pos-1] == '*')) comments--;
if ((c == '/') && (pos > 0) && (buffer[pos-1] == '*') && !inComment) comments--;
}
// Count brackets so we know if we're inside a function or not.
@ -150,6 +156,8 @@ void parseCFile(char *filename, char *targetFile, FILE *trampoline, char *trampo
// End of line?
if ((c == 13) || (c == 10)) {
line++;
inComment = false;
crSinceStart++;
@ -191,6 +199,8 @@ void parseCFile(char *filename, char *targetFile, FILE *trampoline, char *trampo
*b = '(';
// Write out new function definition.
fprintf(out, "%s%cFAR%d_%s {\n", buffer, found ? '*' : ' ', _currentBank, start);
// Create trampoline prototype.
fprintf(trampoline, "%s%cFAR%d_%s;\n", buffer, found ? '*' : ' ', _currentBank, start);
// Create trampoline macro.
fprintf(trampoline, "#define %s(...) ({ \\\n"
"\t\tunsigned char ___mmu = (unsigned char)*(volatile unsigned char *)%#06x; \\\n"