Spec, I implemented tutorial 9 for Bebbo GCC 6.4.0 a time ago. The code should work fine with Bartman GCC too.
Code:
// Scoopex Tutorial 9 for Bebbo GCC 6.4.0
#include <clib/exec_protos.h>
#include <graphics/gfxbase.h>
#include <cstdio>
#include <cstdint>
#include <cstring>
volatile uint16_t* const DMACONR = (uint16_t* const) 0xDFF002;
volatile uint32_t* const VPOS32 = (uint32_t* const) 0xDFF004;
volatile uint16_t* const VPOSR = (uint16_t* const) 0xDFF004;
volatile uint8_t* const VPOSR_LOW = (uint8_t* const) 0xDFF005;
volatile uint16_t* const VPOSHR = (uint16_t* const) 0xDFF006;
volatile uint8_t* const VPOSHR_HIGH = (uint8_t* const) 0xDFF006;
volatile uint8_t* const VPOSHR_LOW = (uint8_t* const) 0xDFF007;
volatile uint16_t* const INTENAR = (uint16_t* const) 0xDFF01C;
volatile uint32_t* const COP1LC32 = (uint32_t* const) 0xDFF080;
volatile uint16_t* const COP1LCH = (uint16_t* const) 0xDFF080;
volatile uint16_t* const COP1LCL = (uint16_t* const) 0xDFF082;
volatile uint16_t* const COP2LCH = (uint16_t* const) 0xDFF084;
volatile uint16_t* const COP2LCL = (uint16_t* const) 0xDFF086;
volatile uint16_t* const DMACONW = (uint16_t* const) 0xDFF096;
volatile uint16_t* const INTENAW = (uint16_t* const) 0xDFF09A;
volatile uint16_t* const INTREQW = (uint16_t* const) 0xDFF09C;
volatile uint8_t* const CIAA_PRA = (uint8_t* const ) 0xBFE001;
static const uint16_t WIDTH = 320;
static const uint16_t HEIGHT = 256;
uint8_t* screen_ptr = 0;
uint8_t* smile_sprite_ptr = 0;
uint16_t* copper_list = 0;
uint16_t* copper_list_end = 0;
const uint16_t SMILE_SPRITE[] = {
0x2C40,0x3C00, // Vstart.b,Hstart/2.b,Vstop.b,%A0000SEH
0x07C0,0x0000, // dc.w % ***** ,%
0x1FF0,0x0000, // dc.w % ********* ,%
0x3FF8,0x0000, // dc.w % *********** ,%
0x7FFC,0x0000, // dc.w % ************* ,%
0x67CC,0x1830, // dc.w % ** ***** ** ,% ** **
0xE7CE,0x1830, // dc.w %*** ***** *** ,% ** **
0xFFFE,0x0000, // dc.w %*************** ,%
0xFFFE,0x0000, // dc.w %*************** ,%
0xFFFE,0x2008, // dc.w %*************** ,% * *
0xFFFE,0x1830, // dc.w %*************** ,% ** **
0x7FFC,0x07C0, // dc.w % ************* ,% *****
0x7FFC,0x0000, // dc.w % ************* ,%
0x3FF8,0x0000, // dc.w % *********** ,%
0x1FF0,0x0000, // dc.w % ********* ,%
0x07C0,0x0000, // dc.w % ***** ,%
0x0000,0x0000, // dc.w % ,%
0,0
};
const uint16_t NULL_SPRITE[] = {
0x2a20,0x2b00,
0,0,
0,0
};
const uint16_t COPPER_LIST_BEGIN[] = {
//Copper:
0x1fc,0, // slow fetch mode, AGA compatibility
0x100,0x0200,
0x8e,0x2c81,
0x90,0x2cc1,
0x92,0x38,
0x94,0xd0,
0x108,0,
0x10a,0,
0x102,0,
0x1a2,0xe22,
0x1a4,0xff0,
0x1a6,0xfff
};
const uint16_t SPR_P[] = {
//SprP:
0x120, 0x0000, // Sprite 0 SMILE_SPRITE_HIGH (value is defined later)
0x122, 0x0000, // Sprite 0 SMILE_SPRITE_LOW
0x124, 0x0000, // Sprite 1 NULL_SPRITE_HIGH
0x126, 0x0000, // Sprite 1 NULL_SPRITE_LOW
0x128, 0x0000, // Sprite 2 NULL_SPRITE_HIGH
0x12a, 0x0000, // Sprite 2 NULL_SPRITE_LOW
0x12c, 0x0000, // Sprite 3 NULL_SPRITE_HIGH
0x12e, 0x0000, // Sprite 3 NULL_SPRITE_LOW
0x130, 0x0000, // Sprite 4 NULL_SPRITE_HIGH
0x132, 0x0000, // Sprite 4 NULL_SPRITE_LOW
0x134, 0x0000, // Sprite 5 NULL_SPRITE_HIGH
0x136, 0x0000, // Sprite 5 NULL_SPRITE_LOW
0x138, 0x0000, // Sprite 6 NULL_SPRITE_HIGH
0x13a, 0x0000, // Sprite 6 NULL_SPRITE_LOW
0x13c, 0x0000, // Sprite 7 NULL_SPRITE_HIGH
0x13e, 0x0000 // Sprite 7 NULL_SPRITE_LOW
};
const uint16_t COPPER_LIST_END[] = {
//CopBplP:
0xe0, 0x0006, // Screen HIGH WORD 0x0006 default
0xe2, 0x0000, // Screen LOW WORD 0x0000 default
0x180,0x349,
0x2b07,0xfffe,
0x180,0x56c,
0x2c07,0xfffe,
0x180,0x113,
0x100,0x1200,
0x182,0x379,
//waitras1: // COPPER_LIST_END[18]
0x8007,0xfffe,
0x180,0x055, // Adjusting color entry 0 of palette for horizontal bouncing bar
//waitras2: // COPPER_LIST_END[22]
0x8107,0xfffe,
0x180,0x0aa, // Adjusting color entry 0 again for next color of gradient
//waitras3: // COPPER_LIST_END[26]
0x8207,0xfffe,
0x180,0x0ff, // Next color
//waitras4: // COPPER_LIST_END[30]
0x8307,0xfffe,
0x180,0x0aa, // Next color
//waitras5: // COPPER_LIST_END[34]
0x8407,0xfffe,
0x180,0x055, // Next color
//waitras6: // COPPER_LIST_END[38]
0x8507,0xfffe,
0x180,0x113, // Next color
0xffdf,0xfffe,
0x2c07,0xfffe,
0x180,0x56c, // Next color
0x2d07,0xfffe,
0x180,0x349, // Last color of horizontal bar
0xffff,0xfffe
};
void waitRaster(uint32_t value) {
uint32_t mask = 0x1FF00;
uint32_t maskedValue = (value << 8) & mask;
while ((*VPOS32 & mask) != maskedValue);
}
void createScreenBuffer() {
size_t bitplane_size = WIDTH * HEIGHT / 8;
screen_ptr = (uint8_t*) AllocMem(bitplane_size, MEMF_CHIP);
uint8_t* helper = screen_ptr;
// Inicialización del hardware
for (uint32_t i = 0; i < bitplane_size; i++) {
// Filling frame buffer with horizontal position of beam. Assembler version of Scoopex
// is developed in assembler so it's faster. The look is different by this reason.
*helper++ = *VPOSHR_LOW;
}
}
void destroyScreenBuffer() {
size_t bitplane_size = WIDTH * HEIGHT / 8;
FreeMem(screen_ptr, bitplane_size);
}
void createCopperList() {
size_t size = sizeof(COPPER_LIST_BEGIN) +
sizeof(SPR_P) +
sizeof(COPPER_LIST_END) +
sizeof(SMILE_SPRITE) +
sizeof(NULL_SPRITE);
uint16_t* helper = copper_list = (uint16_t*) AllocMem(size, MEMF_CHIP);
memcpy(helper, COPPER_LIST_BEGIN, sizeof(COPPER_LIST_BEGIN));
helper += sizeof(COPPER_LIST_BEGIN) / sizeof(uint16_t);
uint16_t* spr_p_ptr = helper;
memcpy(helper, SPR_P, sizeof(SPR_P));
helper += sizeof(SPR_P) / sizeof(uint16_t);
copper_list_end = helper;
memcpy(helper, COPPER_LIST_END, sizeof(COPPER_LIST_END));
helper += sizeof(COPPER_LIST_END) / sizeof(uint16_t);
smile_sprite_ptr = (uint8_t*) helper;
memcpy(helper, SMILE_SPRITE, sizeof(SMILE_SPRITE));
helper += sizeof(SMILE_SPRITE) / sizeof(uint16_t);
uint16_t* null_sprite_ptr = helper;
memcpy(helper, NULL_SPRITE, sizeof(NULL_SPRITE));
uint16_t lo_smile_sprite_ptr = ((uint32_t) smile_sprite_ptr) & 0xFFFF;
uint16_t hi_smile_sprite_ptr = ((uint32_t) smile_sprite_ptr) >> 16;
uint16_t lo_null_sprite_ptr = ((uint32_t) null_sprite_ptr) & 0xFFFF;
uint16_t hi_null_sprite_ptr = ((uint32_t) null_sprite_ptr) >> 16;
spr_p_ptr[1] = hi_smile_sprite_ptr;
spr_p_ptr[3] = lo_smile_sprite_ptr;
for (int i = 0; i < 7; i++) {
spr_p_ptr[5 + i * 4] = hi_null_sprite_ptr;
spr_p_ptr[7 + i * 4] = lo_null_sprite_ptr;
}
uint16_t lo_screen_ptr = ((uint32_t) screen_ptr) & 0xFFFF;
uint16_t hi_screen_ptr = ((uint32_t) screen_ptr) >> 16;
copper_list_end[1] = hi_screen_ptr;
copper_list_end[3] = lo_screen_ptr;
}
void destroyCopperList() {
size_t size = sizeof(COPPER_LIST_BEGIN) +
sizeof(SPR_P) +
sizeof(COPPER_LIST_END) +
sizeof(SMILE_SPRITE) +
sizeof(NULL_SPRITE);
FreeMem(copper_list, size);
}
void setCopperList(uint16_t* cl) {
*COP1LCH =((uint32_t) cl) >> 16;
*COP1LCL =((uint32_t) cl) & 0xFFFF;
}
void waitFrame() {
do {
while (*VPOSR_LOW & 1);
} while (*VPOSHR_HIGH != 0x2a);
}
void waitFrame2() {
while (*VPOSHR_HIGH != 0x2a);
}
bool leftClick() {
return (*CIAA_PRA & (1 << 6)) == 0;
}
int main(int argc, char** argv) {
struct Library* gfxLib = OpenLibrary("graphics.library", 0);
GfxBase* gfxBase = (GfxBase*) gfxLib;
if (gfxBase) {
struct copinit* copinit = gfxBase->copinit;
CloseLibrary(gfxLib);
uint16_t old_INTENA = *INTENAR;
uint16_t old_DMACON = *DMACONR;
waitRaster(0x0138);
*INTENAW = 0x7FFF; // Disable all bits in INTENA
*INTREQW = 0x7FFF; // Idem
//*INTREQW = 0x7FFF; // Idem. Original Scoopex code do this twice. I have removed without problems.
*DMACONW = 0x7FFF; // Disable all bits in DMACON
*DMACONW = 0x87E0; // Setting DMA channels
createScreenBuffer(); // It's important to create screen buffer before Copper list
createCopperList();
setCopperList(copper_list);
// Wait loop
bool bar_lowering = true;
uint8_t bar_y_position = 0xAC;
while (true) {
waitFrame();
waitFrame2();
// Add 1 to sprite position (Smile icon)
smile_sprite_ptr[1]++;
bar_y_position = bar_lowering ? bar_y_position + 1 : bar_y_position - 1;
if (bar_y_position >= 0xF0)
bar_lowering = false;
if (bar_y_position <= 0x40)
bar_lowering = true;
*((uint8_t*) &copper_list_end[18]) = bar_y_position;
*((uint8_t*) &copper_list_end[22]) = bar_y_position + 1;
*((uint8_t*) &copper_list_end[26]) = bar_y_position + 2;
*((uint8_t*) &copper_list_end[30]) = bar_y_position + 3;
*((uint8_t*) &copper_list_end[34]) = bar_y_position + 4;
*((uint8_t*) &copper_list_end[38]) = bar_y_position + 5;
// Detecting left click to exit
if (leftClick())
break;
}
destroyCopperList();
destroyScreenBuffer();
*DMACONW = 0x7FFF; // Disabling DMACON
*DMACONW = old_DMACON | 0x8200;
*COP1LC32 = (uint32_t) copinit;
*INTENAW = old_INTENA | 0xC000;
} else {
fprintf(stderr, "Error opening graphics.library\n");
return 1;
}
return 0;
}