18 October 2019, 18:47 | #1 |
Registered User
Join Date: Dec 2016
Location: England
Posts: 87
|
Converting Photon's tuts to C
Hey everyone, I've decided it might be an idea to convert Photon's excellent assembly tutorials to C, so I'm not just copying and pasting.
I might even post them up on GitHub if there's any interest. Anyway, I'm undecided on an aspect, I can't decide whether to do them 1 to 1 conversion, like this (tut4): Code:
#include <exec/types.h> #define VPOSR 0xdff004 #define VHPOSR 0xdff006 #define INTENAR 0xdff01c #define INTENA 0xdff09a #define COLOR00 0xdff180 #define CIAPRAA 0xbfe001 int main() { volatile UBYTE *vhposr = (UBYTE *)VHPOSR; volatile UBYTE *vposr_lo = (UBYTE *)VPOSR + 1; // point to low byte UWORD *color00 = (UWORD *)COLOR00; UWORD *intena = (UWORD *)INTENA; // line starting position UBYTE yPos = 0xac; // line direction BYTE yDir = 1; // save interrupts UWORD oldInt = *(UWORD *)INTENAR; // disable all interrupts *intena = 0x7fff; // do main loop until mouse pressed while(*(volatile UBYTE *)CIAPRAA & 64) { // wait for start of frame if((*vposr_lo & 1) == 0 && *vhposr == 0x2c) { *color00 = 0; // bg black // update line y position yPos += yDir; // bounce line if(yPos > 0xf0 || yPos < 0x40) { yDir = -yDir; } // do literally nothing until we reach yPos while(*vhposr != yPos) {} *color00 = 0xfff; // bg white // now do nothing until we're not on yPos while(*vhposr == yPos) {} *color00 = 0x116; // bg blue } } // restore interrupts *intena = oldInt | 0xc000; return 0; } Or, do it "properly" using headers like this: Code:
#include <proto/exec.h> #include <hardware/cia.h> #include <hardware/custom.h> #define HIBYTE(theword) (UBYTE)(theword >> 8) #define LOBYTE(theword) (UBYTE)(theword & 0xff) extern struct Custom custom; extern struct CIA ciaa; int main() { // line starting position UBYTE yPos = 0xac; // line direction BYTE yDir = 1; // Save interrupts and DMA UWORD oldInt = custom.intenar; // disable all interrupts custom.intena = 0x7fff; // loop until mouse clicked while(ciaa.ciapra & CIAF_GAMEPORT0) { // wait for start of frame if((custom.vposr & 1) == 0 && HIBYTE(custom.vhposr) == 0x2c) { custom.color[0] = 0; // bg black // update line y position yPos += yDir; // bounce line if(yPos > 0xf0 || yPos < 0x40) { yDir = -yDir; } // do literally nothing until we reach yPos while(HIBYTE(custom.vhposr) != yPos) {} custom.color[0] = 0xfff; // bg white // now do nothing until we're not on yPos while(HIBYTE(custom.vhposr) == yPos) {} custom.color[0] = 0x116; // bg blue } } // restore interrupts and DMA custom.intena = oldInt | 0x8000; return 0; } Code:
move.w custom.vhposr,d1 lsr.w #8,d1 Ideally I'd want same code as Code:
olatile UBYTE *vhposr = (UBYTE *)0xdff006; Last edited by Spec-Chum; 18 October 2019 at 19:27. |
18 October 2019, 19:13 | #2 |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
+1 for doing it "properly", using headers.
|
18 October 2019, 21:29 | #3 |
Zone Friend
Join Date: May 2006
Location: France
Posts: 1,862
|
Nice keep them coming one guy on YouTube was showing how to bang the Amiga HW in C but unfortunately he stopped after making 3 of them.
https://m.youtube.com/user/weiju |
18 October 2019, 21:51 | #4 |
Registered User
Join Date: Sep 2007
Location: Stockholm
Posts: 4,357
|
If you're going to use C, use the system C headers. You've already bypassed the assembly programmer's argument about minimising assembly times and external dependencies.
|
18 October 2019, 22:09 | #5 |
Zone Friend
Join Date: Mar 2004
Location: Middle Earth
Age: 40
Posts: 2,130
|
Good work and keep it up , I don't think it will compile with freeDICE as freeDICE does not allow bit manipulations, but I will try it with NorthC
|
18 October 2019, 22:22 | #6 | |
Registered User
Join Date: Dec 2016
Location: England
Posts: 87
|
Quote:
Started with vbcc, then tried bebbo's GCC 6.5, now on Bartman's GCC 8.3, which I think I'll maybe stick to due to the VSCode integrated debugging. I do already know 68k, but I've not used C for years so figured using C on this would be 2 birds one stone. |
|
18 October 2019, 22:28 | #7 |
ex. demoscener "Bigmama"
Join Date: Jun 2012
Location: Fyn / Denmark
Posts: 1,643
|
custom.vhposr is probably (correctly) marked volatile, which means the compiler needs to read all 16 bits and thus can't skip the shift instruction, I suppose.
|
18 October 2019, 22:38 | #8 | |
Registered User
Join Date: Dec 2016
Location: England
Posts: 87
|
Quote:
EDIT: Scrap that, I was wrong, the tutorial code is doing btst #0,$dff005 and cmp.b #$2c,$dff006, not a move! |
|
18 October 2019, 23:04 | #9 |
ex. demoscener "Bigmama"
Join Date: Jun 2012
Location: Fyn / Denmark
Posts: 1,643
|
It's not about expectations or hardware limitations. Since the register is 16 bits, the compiler has no choice, as it has to obey it being volatile.
|
18 October 2019, 23:07 | #10 |
Registered User
Join Date: Dec 2016
Location: England
Posts: 87
|
|
19 October 2019, 15:57 | #11 |
Registered User
Join Date: Dec 2016
Location: England
Posts: 87
|
Had a bit of spare time (how rare is that nowadays!) so tut7 done, obviously can't do much with the tutorial parts about ORG and labels etc so 100% anyone reading my source to watch the video, which goes without saying for all of them, really.
The single .c file is getting a little larger now and I'm contempating splitting it, putting the #define's into a header file at least, but that goes further from the asm source, so I'm divided. That said, this isn't a C coding tutorial, as such, so I'm not trying to show best practices or anything, so I might just leave it so it's easier to compare to the original source. Anyway, here's tut7: Code:
#include "support/gcc8_c_support.h" #include <proto/exec.h> #include <proto/graphics.h> #include <hardware/cia.h> #include <hardware/custom.h> #include <graphics/copper.h> #include <graphics/gfxbase.h> #define HIBYTE(theword) (theword >> 8) #define LOBYTE(theword) (theword & 0xff) #define CMOVE(addr, data) addr, data #define CWAIT(vhpos, flags) vhpos, flags #define CEND 0xffff, 0xfffe #define WAITRAS1 28 struct ExecBase *SysBase; struct GfxBase *GfxBase; struct copinit *oldCopinit; volatile struct Custom *custom = (struct Custom *)0xdff000; volatile struct CIA *ciaa = (struct CIA *)0xbfe001; // __attribute__((section("tut.MEMF_CHIP"))) UWORD copperlist[] = { CMOVE(0x01fc, 0x0000), // set FMODE to slow for AGA CMOVE(0x0100, 0x0200), // no bitplanes, but need color burst CMOVE(0x0180, 0x0349), CWAIT(0x2b07, 0xfffe), CMOVE(0x0180, 0x056c), CWAIT(0x2c07, 0xfffe), CMOVE(0x0180, 0x0113), // waitras1: CWAIT(0x8007, 0xfffe), CMOVE(0x0180, 0x0055), // waitras2: CWAIT(0x8107, 0xfffe), CMOVE(0x0180, 0x00aa), // waitras3: CWAIT(0x8207, 0xfffe), CMOVE(0x0180, 0x00ff), // waitras4: CWAIT(0x8307, 0xfffe), CMOVE(0x0180, 0x00aa), // waitras5: CWAIT(0x8407, 0xfffe), CMOVE(0x0180, 0x0055), // waitras6: CWAIT(0x8507, 0xfffe), CMOVE(0x0180, 0x0113), CWAIT(0xffdf, 0xfffe), CWAIT(0x2c07, 0xfffe), CMOVE(0x0180, 0x056c), CWAIT(0x2d07, 0xfffe), CMOVE(0x0180, 0x0349), CEND }; int main() { SysBase = *(struct ExecBase**)4L; UBYTE *clptr = AllocMem(sizeof(copperlist), MEMF_CHIP); CopyMem(copperlist, clptr, sizeof(copperlist)); // open gfx lib and save original copperlist GfxBase = (struct GfxBase*)OldOpenLibrary("graphics.library"); oldCopinit = GfxBase->copinit; CloseLibrary((struct Library *)GfxBase); // line starting position UWORD yPos = 0xac; // line direction WORD yDir = 1; // Save interrupts and DMA UWORD oldInt = custom->intenar; // disable all interrupts custom->intena = 0x7fff; // initiate our copper custom->cop1lc = (ULONG)clptr; // loop until mouse clicked while(ciaa->ciapra & CIAF_GAMEPORT0) { // wait for start of frame ** wframe ** if((custom->vposr & 1) == 0 && HIBYTE(custom->vhposr) == 0x2a) { while(HIBYTE(custom->vhposr) == 0x2a) { } // wframe2 // update line y position yPos += yDir; // bounce line if(yPos > 0xf0 || yPos < 0x40) { yDir = -yDir; } for(UWORD waitras = 0; waitras < 6; waitras++) { clptr[WAITRAS1 + (waitras * 8)] = yPos + waitras; } } } // restore original copper custom->cop1lc = (ULONG)oldCopinit; // free copperlist memory FreeMem(clptr, sizeof(copperlist)); // restore interrupts custom->intena = oldInt | 0xc000; return 0; } |
19 October 2019, 21:30 | #12 |
Zone Friend
Join Date: May 2006
Location: France
Posts: 1,862
|
Is all your translation to C here or do you have them elsewhere?
|
19 October 2019, 22:35 | #13 | |
Registered User
Join Date: Dec 2016
Location: England
Posts: 87
|
Quote:
Actually, I think tut 2 is for vbcc lol I need to rework the others so they're all Bartman's GCC 8.3 as that's what I've settled on, mainly for the debugging feature. I might even #ifdef so it compiles on all 3, but that seems a bit overkill for now. I'm just after opinions on the structure for now, as I'd hate to get like 20 tuts in then decide I want to do something different and have to change all the others to conform. |
|
20 October 2019, 00:37 | #14 |
Registered User
Join Date: Dec 2016
Location: England
Posts: 87
|
OK, I've updated and attached all the original ones I did to use Bartman's GCC 8.3 now - this one here
All you need to do is install his VSCode extension, which is fully self contained, initialise a folder as per his instructions, replace the main.c he provides as an example with one of mine and press F5, which should, hopefully, run first time. When I upload to git I'll only do the .c files as the VSCode extension customises the .d files to the initialised directory. |
20 October 2019, 20:15 | #15 |
Registered User
Join Date: Dec 2016
Location: England
Posts: 87
|
I've done a .gitignore file to remove all the unneeded files and uploaded to GitHub
You should be able to just install Bartman's VSCode GCC extension, open one of my folders and press F5 for it to run. Hopefully. |
21 October 2019, 03:21 | #16 | |
Registered User
Join Date: Dec 2018
Location: Málaga
Posts: 61
|
Quote:
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; } |
|
21 October 2019, 09:37 | #17 | |
Registered User
Join Date: Dec 2016
Location: England
Posts: 87
|
Quote:
You've taken the traditional c coding style, with functions and stdlib, whereas I've gone the more direct asm source to c approach. Sadly I don't think bartman's gcc will work with this as, apart from memcpy, there's no stdlib. |
|
21 October 2019, 10:47 | #18 |
Registered User
Join Date: Jan 2017
Location: Antwerp / Belgium
Posts: 189
|
This really is a super interesting thread.
Thanks guys! Really appreciate it - I've been trying to get my head around "hardware banging with C" for some time :-) |
21 October 2019, 14:15 | #19 |
bye
Join Date: Jun 2016
Location: Some / Where
Posts: 681
|
I adapted tutorial 9 a bit - less allocations, more use of headers...
Code:
// Scoopex Tutorial 9 for Bebbo GCC 6.5.0b #include <proto/exec.h> #include <graphics/gfxbase.h> #include <hardware/cia.h> #include <hardware/custom.h> #include <stdint.h> #include <string.h> #define bool short #define true 1 #define false 0 // omit command line parsing - smalle executable extern void __initlibraries(void); void __nocommandline (void){ __initlibraries();} extern struct GfxBase * GfxBase; extern struct Custom custom; extern struct CIA ciaa; #define WIDTH 320 #define HEIGHT 256 __chip uint8_t screen_ptr[WIDTH*HEIGHT/8]; uint8_t* smile_sprite_ptr = 0; uint16_t* copper_list = 0; uint16_t* copper_list_end = 0; __chip 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 }; __chip uint16_t NULL_SPRITE[] = { 0x2a20,0x2b00, 0,0, 0,0 }; __chip 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 }; __chip 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 }; __chip 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 ((custom.vpos32 & mask) != maskedValue); } void fillScreenBuffer() { const size_t bitplane_size = WIDTH * HEIGHT / 8; 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++ = custom.vhposr; } } void createCopperList() { copper_list = COPPER_LIST_BEGIN; uint16_t* spr_p_ptr = SPR_P; copper_list_end = COPPER_LIST_END; smile_sprite_ptr = (uint8_t*)SMILE_SPRITE; uint16_t* null_sprite_ptr = 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 setCopperList(uint16_t* cl) { custom.cop1lc = (ULONG)cl; } void waitFrame() { do { while (custom.vposr & 1); } while (custom.vhposr_h != 0x2a); } void waitFrame2() { while (custom.vhposr_h != 0x2a); } bool leftClick() { return (ciaa.ciapra & (1 << 6)) == 0; } int main(int argc, char** argv) { struct copinit* copinit = GfxBase->copinit; uint16_t old_INTENA = custom.intenar; uint16_t old_DMACON = custom.dmaconr; waitRaster(0x0138); custom.intena = 0x7FFF; // Disable all bits in INTENA custom.intreq = 0x7FFF; // Idem custom.intreq = 0x7FFF; // Idem //*INTREQW = 0x7FFF; // Idem. Original Scoopex code do this twice. I have removed without problems. custom.dmacon = 0x7FFF; // Disable all bits in DMACON custom.dmacon = 0x87E0; // Setting DMA channels fillScreenBuffer(); // 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; } custom.dmacon = 0x7FFF; // Disabling DMACON custom.dmacon = old_DMACON | 0x8200; custom.cop1lc = (uint32_t) copinit; custom.intena = old_INTENA | 0xC000; return 0; } Code:
m68k-amigaos-gcc -Os -msmall-code -fomit-frame-pointer -mcrt=nix13 tut9.c -o tut9 [/code] EDIT: add -msmall-code and -fomit-frame-pointer saves few more bytes. Last edited by bebbo; 21 October 2019 at 14:53. |
21 October 2019, 14:46 | #20 |
Registered User
Join Date: Dec 2016
Location: England
Posts: 87
|
If I get chance I'll do tut9 tonight.
Be interesting to compare file sizes. As stated above, I've taken a different approach in that I'm consciously mirroring the asm source to a degree. I do check the compiler output tho, and it's pretty good. |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
So I 'cracked' Photon Storm. What do you guys think? | MethodGit | Coders. General | 3 | 05 August 2012 02:41 |
Photon's A1700 | Photon | Hardware mods | 43 | 25 December 2011 15:30 |
Photon Storm | Marlon | request.Old Rare Games | 11 | 07 September 2007 19:34 |
asm tuts | BippyM | Coders. Tutorials | 61 | 12 January 2007 15:39 |
Photon Storm | Tim Janssen | request.Old Rare Games | 9 | 12 September 2002 22:02 |
|
|