update ArduboyFX library
Update Arduboy FX library to v1.0.8 add manufacturer strings to boards.txt
This commit is contained in:
parent
e4eba41912
commit
fed21b40cb
|
@ -326,6 +326,7 @@ arduboy-fx.build.board=AVR_ARDUBOY
|
|||
arduboy-fx.build.vid=0x2341
|
||||
arduboy-fx.build.pid=0x8036
|
||||
arduboy-fx.build.variant=arduboy
|
||||
arduboy-fx.build.usb_manufacturer="Arduboy Inc"
|
||||
arduboy-fx.build.usb_product="Arduboy"
|
||||
arduboy-fx.build.board=AVR_ARDUBOY
|
||||
arduboy-fx.build.core=arduino:arduino
|
||||
|
@ -407,6 +408,7 @@ arduboy-fx-devkit.build.board=AVR_ARDUBOY
|
|||
arduboy-fx-devkit.build.vid=0x2341
|
||||
arduboy-fx-devkit.build.pid=0x8036
|
||||
arduboy-fx-devkit.build.variant=arduboy
|
||||
arduboy-fx-devkit.build.usb_manufacturer="Arduboy Inc"
|
||||
arduboy-fx-devkit.build.usb_product="Arduboy"
|
||||
arduboy-fx-devkit.build.board=AVR_ARDUBOY
|
||||
arduboy-fx-devkit.build.core=arduino:arduino
|
||||
|
@ -488,6 +490,7 @@ arduboy.build.board=AVR_ARDUBOY
|
|||
arduboy.build.vid=0x2341
|
||||
arduboy.build.pid=0x8036
|
||||
arduboy.build.variant=arduboy
|
||||
arduboy.build.usb_manufacturer="Arduboy Inc"
|
||||
arduboy.build.usb_product="Arduboy"
|
||||
arduboy.build.board=AVR_ARDUBOY
|
||||
arduboy.build.core=arduino:arduino
|
||||
|
@ -574,6 +577,7 @@ arduboy-devkit.build.board=AVR_ARDUBOY
|
|||
arduboy-devkit.build.vid=0x2341
|
||||
arduboy-devkit.build.pid=0x8036
|
||||
arduboy-devkit.build.variant=arduboy-devkit
|
||||
arduboy-devkit.build.usb_manufacturer="Arduboy Inc"
|
||||
arduboy-devkit.build.usb_product="ABDevKit"
|
||||
arduboy-devkit.build.board=AVR_ARDUBOY_DEVKIT
|
||||
arduboy-devkit.build.core=arduino:arduino
|
||||
|
@ -641,6 +645,7 @@ arduboy-devkit.menu.boot.cathy3kg.bootloader.file=cathy3k/arduboy3k-bootloader-g
|
|||
8bitcadexl.build.board=AVR_PROMICRO -DAB_ALTERNATE_WIRING
|
||||
8bitcadexl.build.vid=0x2341
|
||||
8bitcadexl.build.pid=0x8036
|
||||
8bitcadexl.build.usb_manufacturer="8bitCADE"
|
||||
8bitcadexl.build.usb_product="8bitCADE"
|
||||
8bitcadexl.build.core=arduino:arduino
|
||||
8bitcadexl.build.flash_cs=-DCART_CS_RX
|
||||
|
@ -724,6 +729,7 @@ arduboy-devkit.menu.boot.cathy3kg.bootloader.file=cathy3k/arduboy3k-bootloader-g
|
|||
8bitcadexlup.build.board=AVR_PROMICRO -DAB_ALTERNATE_WIRING
|
||||
8bitcadexlup.build.vid=0x2341
|
||||
8bitcadexlup.build.pid=0x8036
|
||||
8bitcadexlup.build.usb_manufacturer="8bitCADE"
|
||||
8bitcadexlup.build.usb_product="8bitCADE"
|
||||
8bitcadexlup.build.core=arduino:arduino
|
||||
8bitcadexlup.build.flash_cs=-DCART_CS_RX
|
||||
|
@ -807,6 +813,7 @@ microcade.build.variant=arduboy-promicro-alt
|
|||
microcade.build.board=AVR_PROMICRO -DAB_ALTERNATE_WIRING
|
||||
microcade.build.vid=0x2341
|
||||
microcade.build.pid=0x8036
|
||||
microcade.build.usb_manufacturer="microcade"
|
||||
microcade.build.usb_product="microcade"
|
||||
microcade.build.core=arduino:arduino
|
||||
microcade.build.flash_cs=-DCART_CS_RX
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* *****************************************************************************
|
||||
* FX gameState example v1.00 by Mr.Blinky Jan.2023 licenced under CC0
|
||||
* FX gameState example v1.01 by Mr.Blinky Jan-Feb.2023 licenced under CC0
|
||||
* *****************************************************************************
|
||||
*
|
||||
* This is a example showing how you can save and load game data to the FX flash
|
||||
|
@ -22,9 +22,9 @@
|
|||
*
|
||||
* The FX library has two functions for saving and loading game data:
|
||||
*
|
||||
* uint8_t FX::loadGameState(uint8_t* gameState, size_t size)
|
||||
* uint8_t FX::loadGameState(Type gameState)
|
||||
*
|
||||
* void FX::saveGameState(uint8_t* gameState, size_t size)
|
||||
* void FX::saveGameState(Type gameState)
|
||||
*
|
||||
* loadGameState
|
||||
* -------------
|
||||
|
@ -32,15 +32,12 @@
|
|||
* Loads previously saved game data. It returns 0 if there was no data to load
|
||||
* or 1 if the data was successfully loaded.
|
||||
*
|
||||
* gameState is a pointer to an uint8_t array or to a structure in RAM containing
|
||||
* your game data. When using a structure for the game data, the structure must be
|
||||
* cast to an uint8_t array by putting (uint8_t*)& in front of the structures name.
|
||||
* gameState is an object structure in RAM to where the game data will be loaded.
|
||||
* If the size of the object in ram differes from the size of previously saved
|
||||
* data, no data will be loaded.
|
||||
*
|
||||
* size is the size of the uint8_t array or structure in RAM and is usually
|
||||
* determined by using the sizeof() operator.
|
||||
*
|
||||
* When there is no game data loaded (result 0), the contents of the gameState
|
||||
* structure remains unchanged.
|
||||
* When no game data loaded (result 0), the contents of the gameState structure
|
||||
* remains unchanged.
|
||||
*
|
||||
* saveGameState
|
||||
* -------------
|
||||
|
@ -54,7 +51,7 @@
|
|||
* This process is fully transparent and you do not need to worry about it.
|
||||
* It just explains why sometimes this function may take a bit more time then usual.
|
||||
*
|
||||
* gameState and size are the same parameters as for the loadSaveData function.
|
||||
* gameState is an object structure in RAM which will be saved to external flash memory.
|
||||
*
|
||||
* initilizing FX chip when using save capabilities
|
||||
* ------------------------------------------------
|
||||
|
@ -135,7 +132,7 @@ void setup() {
|
|||
FX::begin(FX_DATA_PAGE, FX_SAVE_PAGE); // Initialize FX chip. When using FX save data,
|
||||
// FX_SAVE_PAGE must also be passed on in FX::begin.
|
||||
|
||||
if (!FX::loadGameState((uint8_t*) &gameState, sizeof(gameState))) // Load saveState from the 4K FX save data block. '(uint8_t*) &' is used
|
||||
if (!FX::loadGameState(gameState)) // Load saveState from the 4K FX save data block. '(uint8_t*) &' is used
|
||||
// here to cast a uint8_t pointer to the saveState structure.
|
||||
{
|
||||
// This code gets executed only when the function didn't load a saveState (function returned 0)
|
||||
|
@ -149,7 +146,7 @@ void setup() {
|
|||
gameState.count ++; // increase the number of times this sketch was run.
|
||||
}
|
||||
|
||||
FX::saveGameState((uint8_t*) &gameState, sizeof(gameState)); //Save the game state to 4K FX save block
|
||||
FX::saveGameState(gameState); //Save the game state to 4K FX save block
|
||||
|
||||
arduboy.clear();
|
||||
arduboy.setCursor(0,32 - 8);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name=ArduboyFX
|
||||
version=1.0.7
|
||||
version=1.0.8
|
||||
author=Mr.Blinky
|
||||
maintainer=mstr.blinky@gmail.com
|
||||
sentence=The Arduboy FX library.
|
||||
|
|
|
@ -11,8 +11,15 @@ FrameControl FX::frameControl;
|
|||
|
||||
uint8_t FX::writeByte(uint8_t data)
|
||||
{
|
||||
writeByteBeforeWait(data);
|
||||
return SPDR;
|
||||
SPDR = data;
|
||||
asm volatile("nop\n");
|
||||
uint8_t result;
|
||||
do
|
||||
{
|
||||
result = SPDR; //reading data here saves 1 extra cycle
|
||||
}
|
||||
while ((SPSR & (1 << SPIF)) == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -33,8 +40,9 @@ void FX::begin(uint16_t developmentDataPage)
|
|||
{
|
||||
disableOLED();
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
const uint8_t* vector = FX_DATA_VECTOR_KEY_POINTER;
|
||||
asm volatile(
|
||||
const uint8_t* vector = (const uint8_t*)FX_DATA_VECTOR_KEY_POINTER;
|
||||
asm volatile
|
||||
(
|
||||
"lpm r18, z+ \n"
|
||||
"lpm r19, z+ \n"
|
||||
"lpm r21, z+ \n"
|
||||
|
@ -68,8 +76,9 @@ void FX::begin(uint16_t developmentDataPage, uint16_t developmentSavePage)
|
|||
{
|
||||
disableOLED();
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
const uint8_t* vector = FX_DATA_VECTOR_KEY_POINTER;
|
||||
asm volatile(
|
||||
const uint8_t* vector = (const uint8_t*)FX_DATA_VECTOR_KEY_POINTER;
|
||||
asm volatile
|
||||
(
|
||||
"lpm r18, z+ \n"
|
||||
"lpm r19, z+ \n"
|
||||
"lpm r21, z+ \n"
|
||||
|
@ -118,6 +127,16 @@ void FX::begin(uint16_t developmentDataPage, uint16_t developmentSavePage)
|
|||
wakeUp();
|
||||
}
|
||||
|
||||
void FX::readJedecID(JedecID & id)
|
||||
{
|
||||
enable();
|
||||
writeByte(SFC_JEDEC_ID);
|
||||
id.manufacturer = readByte();
|
||||
id.device = readByte();
|
||||
id.size = readByte();
|
||||
disable();
|
||||
}
|
||||
|
||||
void FX::readJedecID(JedecID* id)
|
||||
{
|
||||
enable();
|
||||
|
@ -180,14 +199,15 @@ void FX::seekCommand(uint8_t command, uint24_t address)
|
|||
enable();
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
register uint8_t cmd asm("r24") = command; //assembly optimizer for AVR platform ~saves 12 bytes
|
||||
asm volatile(
|
||||
asm volatile
|
||||
(
|
||||
"call %x2 \n"
|
||||
"mov r24, %C[addr] \n"
|
||||
"call %x2 \n"
|
||||
"mov r24, %B[addr] \n"
|
||||
"call %x2 \n"
|
||||
"mov r24, %A[addr] \n"
|
||||
"call %x2 \n"
|
||||
"jmp %x2 \n"
|
||||
: [cmd] "+&r" (cmd)
|
||||
: [addr] "r" (address),
|
||||
[write] "i" (writeByte)
|
||||
|
@ -204,20 +224,25 @@ void FX::seekCommand(uint8_t command, uint24_t address)
|
|||
|
||||
void FX::seekData(uint24_t address)
|
||||
{
|
||||
uint24_t abs_address = address;
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
asm volatile( // assembly optimizer for AVR platform
|
||||
"lds r0, %[page]+0 \n"
|
||||
"add %B[addr], r0 \n"
|
||||
"lds r0, %[page]+1 \n"
|
||||
"adc %C[addr], r0 \n"
|
||||
:[addr] "+&r" (address)
|
||||
:[page] "" (&programDataPage)
|
||||
asm volatile
|
||||
(
|
||||
"mov %A[abs], %A[addr] \n"
|
||||
"lds %B[abs], %[page]+0 \n"
|
||||
"add %B[abs], %B[addr] \n"
|
||||
"lds %C[abs], %[page]+1 \n"
|
||||
"adc %C[abs], %C[addr] \n"
|
||||
:
|
||||
[abs] "=r" (abs_address)
|
||||
:[page] "" (&programDataPage),
|
||||
[addr] "r" (address)
|
||||
:
|
||||
);
|
||||
#else // C++ version for non AVR platforms
|
||||
address += (uint24_t)programDataPage << 8;
|
||||
abs_address = address + (uint24_t)programDataPage << 8;
|
||||
#endif
|
||||
seekCommand(SFC_READ, address);
|
||||
seekCommand(SFC_READ, abs_address);
|
||||
SPDR = 0;
|
||||
}
|
||||
|
||||
|
@ -225,7 +250,8 @@ void FX::seekData(uint24_t address)
|
|||
void FX::seekDataArray(uint24_t address, uint8_t index, uint8_t offset, uint8_t elementSize)
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
asm volatile (
|
||||
asm volatile
|
||||
(
|
||||
" mul %[index], %[size] \n"
|
||||
" brne .+2 \n" //treat size 0 as size 256
|
||||
" mov r1, %[index] \n"
|
||||
|
@ -236,43 +262,49 @@ void FX::seekDataArray(uint24_t address, uint8_t index, uint8_t offset, uint8_t
|
|||
" adc %B[address], r1 \n"
|
||||
" adc %C[address], r21 \n"
|
||||
" clr r1 \n"
|
||||
: [address] "+&r" (address)
|
||||
" jmp %x4 \n" //seekData
|
||||
:
|
||||
: [index] "r" (index),
|
||||
[offset] "r" (offset),
|
||||
[size] "r" (elementSize)
|
||||
[size] "r" (elementSize),
|
||||
[address] "r" (address),
|
||||
"" (seekData)
|
||||
: "r21"
|
||||
);
|
||||
#else
|
||||
address += size ? index * size + offset : index * 256 + offset;
|
||||
#endif
|
||||
seekData(address);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void FX::seekSave(uint24_t address)
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
asm volatile( // assembly optimizer for AVR platform
|
||||
"lds r0, %[page]+0 \n"
|
||||
"add %B[addr], r0 \n"
|
||||
"lds r0, %[page]+1 \n"
|
||||
"adc %C[addr], r0 \n"
|
||||
:[addr] "+&r" (address)
|
||||
:[page] "" (&programSavePage)
|
||||
uint24_t abs_address = address;
|
||||
asm volatile
|
||||
(
|
||||
"mov %A[abs], %A[addr] \n"
|
||||
"lds %B[abs], %[page]+0 \n"
|
||||
"add %B[abs], %B[addr] \n"
|
||||
"lds %C[abs], %[page]+1 \n"
|
||||
"adc %C[abs], %C[addr] \n"
|
||||
:
|
||||
[abs] "=r" (abs_address)
|
||||
:[page] "" (&programSavePage),
|
||||
[addr] "r" (address)
|
||||
:
|
||||
);
|
||||
#else // C++ version for non AVR platforms
|
||||
address += (uint24_t)programSavePage << 8;
|
||||
abs_address = address + (uint24_t)programSavePage << 8;
|
||||
#endif
|
||||
seekCommand(SFC_READ, address);
|
||||
seekCommand(SFC_READ, abs_address);
|
||||
SPDR = 0;
|
||||
}
|
||||
|
||||
|
||||
uint8_t FX::readPendingUInt8()
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
asm volatile("ArduboyFX_cpp_readPendingUInt8:\n"); // create label for calls in FX::readPendingUInt16
|
||||
#endif
|
||||
wait();
|
||||
uint8_t result = SPDR;
|
||||
SPDR = 0;
|
||||
|
@ -282,7 +314,8 @@ uint8_t FX::readPendingUInt8()
|
|||
|
||||
uint8_t FX::readPendingLastUInt8()
|
||||
{
|
||||
return readEnd();
|
||||
wait(); // wait for a pending read to complete
|
||||
return readUnsafeEnd(); // read last byte and disable flash
|
||||
}
|
||||
|
||||
|
||||
|
@ -291,10 +324,10 @@ uint16_t FX::readPendingUInt16()
|
|||
#ifdef ARDUINO_ARCH_AVR // Assembly implementation for AVR platform
|
||||
uint16_t result asm("r24"); // we want result to be assigned to r24,r25
|
||||
asm volatile
|
||||
( "ArduboyFX_cpp_readPendingUInt16: \n"
|
||||
"call ArduboyFX_cpp_readPendingUInt8 \n"
|
||||
(
|
||||
"call %x1 \n"
|
||||
"mov %B[val], r24 \n"
|
||||
"jmp ArduboyFX_cpp_readPendingUInt8 \n"
|
||||
"jmp %x1 \n"
|
||||
: [val] "=&r" (result)
|
||||
: "" (readPendingUInt8)
|
||||
:
|
||||
|
@ -311,7 +344,7 @@ uint16_t FX::readPendingLastUInt16()
|
|||
#ifdef ARDUINO_ARCH_AVR // Assembly implementation for AVR platform
|
||||
uint16_t result asm("r24"); // we want result to be assigned to r24,r25
|
||||
asm volatile
|
||||
( "ArduboyFX_cpp_readPendingLastUInt16: \n"
|
||||
(
|
||||
"call %x1 \n"
|
||||
"mov %B[val], r24 \n"
|
||||
"jmp %x2 \n"
|
||||
|
@ -333,9 +366,9 @@ uint24_t FX::readPendingUInt24()
|
|||
uint24_t result asm("r24"); // we want result to be assigned to r24,r25,r26
|
||||
asm volatile
|
||||
(
|
||||
"call ArduboyFX_cpp_readPendingUInt16 \n"
|
||||
"call %x1 \n"
|
||||
"mov %B[val], r24 \n"
|
||||
"call ArduboyFX_cpp_readPendingUInt8 \n"
|
||||
"call %x2 \n"
|
||||
"mov %A[val], r24 \n"
|
||||
"mov %C[val], r25 \n"
|
||||
: [val] "=&r" (result)
|
||||
|
@ -379,9 +412,9 @@ uint32_t FX::readPendingUInt32()
|
|||
uint32_t result asm("r24"); // we want result to be assigned to r24,r25,r26,r27
|
||||
asm volatile
|
||||
(
|
||||
"call ArduboyFX_cpp_readPendingUInt16 \n"
|
||||
"call %x1 \n"
|
||||
"movw %C[val], r24 \n"
|
||||
"call ArduboyFX_cpp_readPendingUInt16 \n"
|
||||
"call %x1 \n"
|
||||
: [val] "=&r" (result)
|
||||
: "" (readPendingUInt16)
|
||||
:
|
||||
|
@ -399,11 +432,12 @@ uint32_t FX::readPendingLastUInt32()
|
|||
uint32_t result asm("r24"); // we want result to be assigned to r24,r25,r26,r27
|
||||
asm volatile
|
||||
(
|
||||
"call ArduboyFX_cpp_readPendingUInt16 \n"
|
||||
"call %x1 \n"
|
||||
"movw %C[val], r24 \n"
|
||||
"call ArduboyFX_cpp_readPendingLastUInt16 \n"
|
||||
"call %x2 \n"
|
||||
: [val] "=&r" (result)
|
||||
: "" (readPendingUInt16)
|
||||
: "" (readPendingUInt16),
|
||||
"" (readPendingLastUInt16)
|
||||
:
|
||||
);
|
||||
return result;
|
||||
|
@ -415,15 +449,51 @@ uint32_t FX::readPendingLastUInt32()
|
|||
|
||||
void FX::readBytes(uint8_t* buffer, size_t length)
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
asm volatile(
|
||||
"1: \n"
|
||||
"call %x2 \n"
|
||||
"st z+,r24 \n"
|
||||
"subi %A[len], 1 \n"
|
||||
"sbci %B[len], 0 \n"
|
||||
"brne 1b \n"
|
||||
: "+&z" (buffer),
|
||||
[len] "+&d" (length)
|
||||
: "" (readPendingUInt8)
|
||||
: "r24"
|
||||
);
|
||||
#else
|
||||
for (size_t i = 0; i < length; i++)
|
||||
{
|
||||
buffer[i] = readPendingUInt8();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void FX::readBytesEnd(uint8_t* buffer, size_t length)
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
asm volatile(
|
||||
"1: \n"
|
||||
"subi %A[len], 1 \n"
|
||||
"sbci %B[len], 0 \n"
|
||||
"breq 2f \n"
|
||||
" \n"
|
||||
"call %x2 \n"
|
||||
"st z+, r24 \n"
|
||||
"rjmp 1b \n"
|
||||
"2: \n"
|
||||
"call %x3 \n"
|
||||
"st z, r24 \n"
|
||||
|
||||
: "+&z" (buffer),
|
||||
[len] "+&d" (length)
|
||||
: "" (readPendingUInt8),
|
||||
"" (readEnd)
|
||||
: "r24"
|
||||
);
|
||||
#else
|
||||
for (size_t i = 0; i <= length; i++)
|
||||
{
|
||||
if ((i+1) != length)
|
||||
|
@ -434,6 +504,7 @@ void FX::readBytesEnd(uint8_t* buffer, size_t length)
|
|||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -517,7 +588,7 @@ uint8_t FX::loadGameState(uint8_t* gameState, size_t size) // ~54 bytes
|
|||
return result;
|
||||
}
|
||||
|
||||
void FX::saveGameState(uint8_t* gameState, size_t size) // ~152 bytes locates free space in 4K save block and saves the GamesState.
|
||||
void FX::saveGameState(const uint8_t* gameState, size_t size) // ~152 bytes locates free space in 4K save block and saves the GamesState.
|
||||
{ // if there is not enough free space, the block is erased prior to saving
|
||||
register size_t sz asm("r18") = size;
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
|
@ -697,7 +768,7 @@ void FX::drawBitmap(int16_t x, int16_t y, uint24_t address, uint8_t frame, uint8
|
|||
skiptop = -y & -8; // optimized -y / 8 * 8
|
||||
if (height - skiptop <= HEIGHT) renderheight = height - skiptop;
|
||||
else renderheight = HEIGHT + (-y & 7);
|
||||
skiptop >>= 3;//pixels to displayrows
|
||||
skiptop = fastDiv8(skiptop); // pixels to displayrows
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -705,7 +776,7 @@ void FX::drawBitmap(int16_t x, int16_t y, uint24_t address, uint8_t frame, uint8
|
|||
if (y + height > HEIGHT) renderheight = HEIGHT - y;
|
||||
else renderheight = height;
|
||||
}
|
||||
uint24_t offset = (uint24_t)(frame * ((height+7) / 8) + skiptop) * width + skipleft;
|
||||
uint24_t offset = (uint24_t)(frame * (fastDiv8(height+(uint16_t)7)) + skiptop) * width + skipleft;
|
||||
if (mode & dbmMasked)
|
||||
{
|
||||
offset += offset; // double for masked bitmaps
|
||||
|
@ -874,20 +945,20 @@ void FX::drawBitmap(int16_t x, int16_t y, uint24_t address, uint8_t frame, uint8
|
|||
{
|
||||
seekData(address);
|
||||
address += width;
|
||||
mode &= ~(_BV(dbfExtraRow));
|
||||
if (yshift != 1 && displayrow < (HEIGHT / 8 - 1)) mode |= _BV(dbfExtraRow);
|
||||
mode &= ~((1 << dbfExtraRow));
|
||||
if (yshift != 1 && displayrow < (HEIGHT / 8 - 1)) mode |= (1 << dbfExtraRow);
|
||||
uint8_t rowmask = 0xFF;
|
||||
if (renderheight < 8) rowmask = lastmask;
|
||||
wait();
|
||||
for (uint8_t c = 0; c < renderwidth; c++)
|
||||
{
|
||||
uint8_t bitmapbyte = readUnsafe();
|
||||
if (mode & _BV(dbfReverseBlack)) bitmapbyte ^= rowmask;
|
||||
if (mode & (1 << dbfReverseBlack)) bitmapbyte ^= rowmask;
|
||||
uint8_t maskbyte = rowmask;
|
||||
if (mode & _BV(dbfWhiteBlack)) maskbyte = bitmapbyte;
|
||||
if (mode & _BV(dbfBlack)) bitmapbyte = 0;
|
||||
if (mode & (1 << dbfWhiteBlack)) maskbyte = bitmapbyte;
|
||||
if (mode & (1 << dbfBlack)) bitmapbyte = 0;
|
||||
uint16_t bitmap = multiplyUInt8(bitmapbyte, yshift);
|
||||
if (mode & _BV(dbfMasked))
|
||||
if (mode & (1 << dbfMasked))
|
||||
{
|
||||
wait();
|
||||
uint8_t tmp = readUnsafe();
|
||||
|
@ -898,12 +969,12 @@ void FX::drawBitmap(int16_t x, int16_t y, uint24_t address, uint8_t frame, uint8
|
|||
{
|
||||
uint8_t pixels = bitmap;
|
||||
uint8_t display = Arduboy2Base::sBuffer[displayoffset];
|
||||
if ((mode & _BV(dbfInvert)) == 0) pixels ^= display;
|
||||
if ((mode & (1 << dbfInvert)) == 0) pixels ^= display;
|
||||
pixels &= mask;
|
||||
pixels ^= display;
|
||||
Arduboy2Base::sBuffer[displayoffset] = pixels;
|
||||
}
|
||||
if (mode & _BV(dbfExtraRow))
|
||||
if (mode & (1 << dbfExtraRow))
|
||||
{
|
||||
uint8_t display = Arduboy2Base::sBuffer[displayoffset + WIDTH];
|
||||
uint8_t pixels = bitmap >> 8;
|
||||
|
@ -1318,5 +1389,3 @@ void FX::drawNumber(uint32_t n, int8_t digits) //
|
|||
while (digits < 0) {++digits; *--str = ' ';}
|
||||
drawString(str);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
#ifndef ARDUBOYFX_H
|
||||
#define ARDUBOYFX_H
|
||||
|
||||
// For uint8_t, uint16_t
|
||||
#include <stdint.h>
|
||||
|
||||
// For size_t
|
||||
#include <stddef.h>
|
||||
|
||||
// For ARDUINO_ARCH_AVR, PORTD, ...
|
||||
#include <Arduino.h>
|
||||
|
||||
// For Arduboy2Base::sBuffer, WIDTH, HEIGHT, CS_PORT ...
|
||||
#include <Arduboy2.h>
|
||||
|
||||
#ifdef CART_CS_RX
|
||||
|
@ -42,15 +52,15 @@ constexpr uint8_t dbfEndFrame = 6; // last bitmap image of a frame
|
|||
constexpr uint8_t dbfLastFrame = 7; // last bitmap image of the last frame
|
||||
|
||||
// drawBitmap modes with same behaviour as Arduboy library drawBitmap modes
|
||||
constexpr uint8_t dbmBlack = _BV(dbfReverseBlack) | // white pixels in bitmap will be drawn as black pixels on display
|
||||
_BV(dbfBlack) | // black pixels in bitmap will not change pixels on display
|
||||
_BV(dbfWhiteBlack); // (same as sprites drawErase)
|
||||
constexpr uint8_t dbmBlack = (1 << dbfReverseBlack) | // white pixels in bitmap will be drawn as black pixels on display
|
||||
(1 << dbfBlack) | // black pixels in bitmap will not change pixels on display
|
||||
(1 << dbfWhiteBlack); // (same as sprites drawErase)
|
||||
|
||||
constexpr uint8_t dbmWhite = _BV(dbfWhiteBlack); // white pixels in bitmap will be drawn as white pixels on display
|
||||
constexpr uint8_t dbmWhite = (1 << dbfWhiteBlack); // white pixels in bitmap will be drawn as white pixels on display
|
||||
// black pixels in bitmap will not change pixels on display
|
||||
//(same as sprites drawSelfMasked)
|
||||
|
||||
constexpr uint8_t dbmInvert = _BV(dbfInvert); // when a pixel in bitmap has a different color than on display the
|
||||
constexpr uint8_t dbmInvert = (1 << dbfInvert); // when a pixel in bitmap has a different color than on display the
|
||||
// pixel on display will be drawn as white. In all other cases the
|
||||
// pixel will be drawn as black
|
||||
// additional drawBitmap modes
|
||||
|
@ -58,14 +68,14 @@ constexpr uint8_t dbmNormal = 0; // White pixels in bitma
|
|||
constexpr uint8_t dbmOverwrite = 0; // Black pixels in bitmap will be drawn as black pixels on display
|
||||
// (Same as sprites drawOverwrite)
|
||||
|
||||
constexpr uint8_t dbmReverse = _BV(dbfReverseBlack); // White pixels in bitmap will be drawn as black pixels on display
|
||||
constexpr uint8_t dbmReverse = (1 << dbfReverseBlack); // White pixels in bitmap will be drawn as black pixels on display
|
||||
// Black pixels in bitmap will be drawn as white pixels on display
|
||||
|
||||
constexpr uint8_t dbmMasked = _BV(dbfMasked); // The bitmap contains a mask that will determine which pixels are
|
||||
constexpr uint8_t dbmMasked = (1 << dbfMasked); // The bitmap contains a mask that will determine which pixels are
|
||||
// drawn and which pixels remain unchanged on display
|
||||
// (same as sprites drawPlusMask)
|
||||
constexpr uint8_t dbmEndFrame = _BV(dbfEndFrame); // last bitmap of a frame but more frames
|
||||
constexpr uint8_t dbmLastFrame = _BV(dbfLastFrame); // last bitmap of a frame and at end of frames
|
||||
constexpr uint8_t dbmEndFrame = (1 << dbfEndFrame); // last bitmap of a frame but more frames
|
||||
constexpr uint8_t dbmLastFrame = (1 << dbfLastFrame); // last bitmap of a frame and at end of frames
|
||||
|
||||
// Note above modes may be combined like (dbmMasked | dbmReverse)
|
||||
|
||||
|
@ -78,15 +88,15 @@ constexpr uint8_t dcfMasked = 4; // character contains mask data
|
|||
constexpr uint8_t dcfProportional = 5; // use fonts width table to mimic proportional characters
|
||||
|
||||
//draw Font character modes
|
||||
constexpr uint8_t dcmBlack = _BV(dcfReverseBlack) | // white pixels in character will be drawn as black pixels on display
|
||||
_BV(dcfBlack) | // black pixels in character will not change pixels on display
|
||||
_BV(dcfWhiteBlack); // (same as sprites drawErase)
|
||||
constexpr uint8_t dcmBlack = (1 << dcfReverseBlack) | // white pixels in character will be drawn as black pixels on display
|
||||
(1 << dcfBlack) | // black pixels in character will not change pixels on display
|
||||
(1 << dcfWhiteBlack); // (same as sprites drawErase)
|
||||
|
||||
constexpr uint8_t dcmWhite = _BV(dcfWhiteBlack); // white pixels in character will be drawn as white pixels on display
|
||||
constexpr uint8_t dcmWhite = (1 << dcfWhiteBlack); // white pixels in character will be drawn as white pixels on display
|
||||
// black pixels in character will not change pixels on display
|
||||
//(same as sprites drawSelfMasked)
|
||||
|
||||
constexpr uint8_t dcmInvert = _BV(dcfInvert); // when a pixel in character has a different color than on display the
|
||||
constexpr uint8_t dcmInvert = (1 << dcfInvert); // when a pixel in character has a different color than on display the
|
||||
// pixel on display will be drawn as white. In all other cases the
|
||||
// pixel will be drawn as black
|
||||
// additional drawcharacter modes
|
||||
|
@ -94,12 +104,12 @@ constexpr uint8_t dcmNormal = 0; // White pixels in chara
|
|||
constexpr uint8_t dcmOverwrite = 0; // Black pixels in character will be drawn as black pixels on display
|
||||
// (Same as sprites drawOverwrite)
|
||||
|
||||
constexpr uint8_t dcmReverse = _BV(dcfReverseBlack); // White pixels in character will be drawn as black pixels on display
|
||||
constexpr uint8_t dcmReverse = (1 << dcfReverseBlack); // White pixels in character will be drawn as black pixels on display
|
||||
// Black pixels in character will be drawn as white pixels on display
|
||||
|
||||
constexpr uint8_t dcmMasked = _BV(dcfMasked); // The character contains a mask that will determine which pixels are
|
||||
constexpr uint8_t dcmMasked = (1 << dcfMasked); // The character contains a mask that will determine which pixels are
|
||||
|
||||
constexpr uint8_t dcmProportional = _BV(dcfProportional); // draw characters with variable spacing. When this mode is used a
|
||||
constexpr uint8_t dcmProportional = (1 << dcfProportional); // draw characters with variable spacing. When this mode is used a
|
||||
// 256 byte width table must precede the font data
|
||||
|
||||
// Note above modes may be combined like (dcmMasked | dcmProportional)
|
||||
|
@ -157,41 +167,48 @@ struct FrameData
|
|||
class FX
|
||||
{
|
||||
public:
|
||||
static inline void enableOLED() __attribute__((always_inline)) // selects OLED display.
|
||||
[[gnu::always_inline]]
|
||||
static inline void enableOLED() // selects OLED display.
|
||||
{
|
||||
CS_PORT &= ~(1 << CS_BIT);
|
||||
};
|
||||
|
||||
static inline void disableOLED() __attribute__((always_inline)) // deselects OLED display.
|
||||
[[gnu::always_inline]]
|
||||
static inline void disableOLED() // deselects OLED display.
|
||||
{
|
||||
CS_PORT |= (1 << CS_BIT);
|
||||
};
|
||||
|
||||
static inline void enable() __attribute__((always_inline)) // selects external flash memory and allows new commands
|
||||
[[gnu::always_inline]]
|
||||
static inline void enable() // selects external flash memory and allows new commands
|
||||
{
|
||||
FX_PORT &= ~(1 << FX_BIT);
|
||||
};
|
||||
|
||||
static inline void disable() __attribute__((always_inline)) // deselects external flash memory and ends the last command
|
||||
[[gnu::always_inline]]
|
||||
static inline void disable() // deselects external flash memory and ends the last command
|
||||
{
|
||||
FX_PORT |= (1 << FX_BIT);
|
||||
};
|
||||
|
||||
static inline void wait() __attribute__((always_inline)) // wait for a pending flash transfer to complete
|
||||
[[gnu::always_inline]]
|
||||
static inline void wait() // wait for a pending flash transfer to complete
|
||||
{
|
||||
while ((SPSR & _BV(SPIF)) == 0);
|
||||
while ((SPSR & (1 << SPIF)) == 0);
|
||||
}
|
||||
|
||||
static uint8_t writeByte(uint8_t data); // write a single byte to flash memory.
|
||||
|
||||
static inline void writeByteBeforeWait(uint8_t data) __attribute__((always_inline))
|
||||
[[gnu::always_inline]]
|
||||
static inline void writeByteBeforeWait(uint8_t data)
|
||||
{
|
||||
SPDR = data;
|
||||
asm volatile("nop\n");
|
||||
wait();
|
||||
}
|
||||
|
||||
static inline void writeByteAfterWait(uint8_t data) __attribute__((always_inline))
|
||||
[[gnu::always_inline]]
|
||||
static inline void writeByteAfterWait(uint8_t data)
|
||||
{
|
||||
wait();
|
||||
SPDR = data;
|
||||
|
@ -211,6 +228,10 @@ class FX
|
|||
|
||||
static void begin(uint16_t datapage, uint16_t savepage); // Initializes flash memory. Use when program depends on both data and save data in flash memory
|
||||
|
||||
/// @brief Reads the JedecID of the attached flash chip.
|
||||
/// @param id An object into which the ID will be read.
|
||||
static void readJedecID(JedecID & id);
|
||||
|
||||
static void readJedecID(JedecID* id);
|
||||
|
||||
static bool detect(); //detect presence of initialized flash memory
|
||||
|
@ -225,35 +246,84 @@ class FX
|
|||
|
||||
static void writeEnable();// Puts flash memory in write mode, required prior to any write command
|
||||
|
||||
[[gnu::noinline, gnu::naked]]
|
||||
static void seekCommand(uint8_t command, uint24_t address);// Write command and selects flash memory address. Required by any read or write command
|
||||
|
||||
static void seekData(uint24_t address); // selects flashaddress of program data area for reading and starts the first read
|
||||
/// @brief selects flash address of program data for reading and starts the first read
|
||||
/// @param address The base address of program data memory.
|
||||
|
||||
[[gnu::noinline]]
|
||||
static void seekData(uint24_t address);
|
||||
|
||||
/// @brief Seeks an element of an array.
|
||||
/// @tparam Type The type of the element to be read.
|
||||
/// @param address The base address of the array.
|
||||
/// @param index The index of the array element.
|
||||
template<typename Type>
|
||||
static void seekArrayElement(uint24_t address, uint8_t index)
|
||||
{
|
||||
// Note: By the laws of the language this should never happen.
|
||||
// This assert exists only as a precaution against e.g. weird compiler extensions.
|
||||
static_assert(sizeof(Type) > 0, "Cannot use a Type with a size of 0.");
|
||||
|
||||
seekData(address + (index * sizeof(Type)));
|
||||
}
|
||||
|
||||
/// @brief Seeks a member of an object that is an element of an array.
|
||||
/// @tparam Type The type of the elements in the array.
|
||||
/// @param address The base address of the array.
|
||||
/// @param index The index of the array element.
|
||||
/// @param offset The offset of the member of the array element.
|
||||
/// @note
|
||||
/// It is intended that the value of `offset` be acquired using the
|
||||
/// `offsetof` macro from `stddef.h`, as this is the safest way
|
||||
/// to obtain the offset of an object member.
|
||||
template<typename Type>
|
||||
static void seekArrayElementMember(uint24_t address, uint8_t index, size_t offset)
|
||||
{
|
||||
// Note: By the laws of the language this should never happen.
|
||||
// This assert exists only as a precaution against e.g. weird compiler extensions.
|
||||
static_assert(sizeof(Type) > 0, "Cannot use a Type with a size of 0.");
|
||||
|
||||
seekData(address + ((index * sizeof(Type)) + offset));
|
||||
}
|
||||
|
||||
[[gnu::noinline, gnu::naked]]
|
||||
static void seekDataArray(uint24_t address, uint8_t index, uint8_t offset, uint8_t elementSize);
|
||||
|
||||
static void seekSave(uint24_t address) __attribute__ ((noinline)); // selects flashaddress of program save area for reading and starts the first read
|
||||
[[gnu::noinline]]
|
||||
static void seekSave(uint24_t address); // selects flashaddress of program save area for reading and starts the first read
|
||||
|
||||
static inline uint8_t readUnsafe() __attribute__((always_inline)) // read flash data without performing any checks and starts the next read.
|
||||
[[gnu::always_inline]]
|
||||
static inline uint8_t readUnsafe() // read flash data without performing any checks and starts the next read.
|
||||
{
|
||||
uint8_t result = SPDR;
|
||||
SPDR = 0;
|
||||
return result;
|
||||
};
|
||||
|
||||
static inline uint8_t readUnsafeEnd() __attribute__((always_inline))
|
||||
[[gnu::always_inline]]
|
||||
static inline uint8_t readUnsafeEnd()
|
||||
{
|
||||
uint8_t result = SPDR;
|
||||
disable();
|
||||
return result;
|
||||
};
|
||||
|
||||
static uint8_t readPendingUInt8() __attribute__ ((noinline)); //read a prefetched byte from the current flash location
|
||||
[[gnu::noinline]]
|
||||
static uint8_t readPendingUInt8(); //read a prefetched byte from the current flash location
|
||||
|
||||
static uint8_t readPendingLastUInt8() __attribute__ ((noinline)); //depreciated use readEnd() instead (see below)
|
||||
/// @brief read the last prefetched byte from the current flash location and ends the read command.
|
||||
/// This function performs the same action as readEnd()
|
||||
|
||||
static uint16_t readPendingUInt16() __attribute__ ((noinline)) __attribute__ ((naked)); //read a partly prefetched 16-bit word from the current flash location
|
||||
[[gnu::noinline]]
|
||||
static uint8_t readPendingLastUInt8();
|
||||
|
||||
static uint16_t readPendingLastUInt16() __attribute__ ((noinline)) __attribute__ ((naked)); //read a partly prefetched 16-bit word from the current flash location
|
||||
[[gnu::noinline, gnu::naked]]
|
||||
static uint16_t readPendingUInt16(); //read a partly prefetched 16-bit word from the current flash location
|
||||
|
||||
[[gnu::noinline, gnu::naked]]
|
||||
static uint16_t readPendingLastUInt16(); //read a partly prefetched 16-bit word from the current flash location
|
||||
|
||||
static uint24_t readPendingUInt24() ; //read a partly prefetched 24-bit word from the current flash location
|
||||
|
||||
|
@ -263,19 +333,96 @@ class FX
|
|||
|
||||
static uint32_t readPendingLastUInt32(); //read a partly prefetched a 32-bit word from the current flash location
|
||||
|
||||
/// @brief Reads an object from the current flash location.
|
||||
/// @tparam Type The type of the object to be read.
|
||||
/// @param object An object into which the target object will be read.
|
||||
/// @warning
|
||||
/// `Type` should be:
|
||||
/// * _[trivially copyable](https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable)_
|
||||
/// * a _[standard-layout](https://en.cppreference.com/w/cpp/language/data_members#Standard-layout)_ type
|
||||
/// Attempting to read an object that does not meet these restrictions will result in _undefined behaviour_.
|
||||
template<typename Type>
|
||||
static void readObject(Type & object)
|
||||
{
|
||||
readBytes(reinterpret_cast<uint8_t *>(&object), sizeof(object));
|
||||
}
|
||||
|
||||
static void readBytes(uint8_t* buffer, size_t length);// read a number of bytes from the current flash location
|
||||
|
||||
static void readBytesEnd(uint8_t* buffer, size_t length); // read a number of bytes from the current flash location and ends the read command
|
||||
|
||||
static uint8_t readEnd() __attribute__ ((noinline)); //read the last prefetched byte from the current flash location and ends the read command
|
||||
/// @brief read the last prefetched byte from the current flash location and ends the read command
|
||||
|
||||
[[gnu::noinline]]
|
||||
static uint8_t readEnd();
|
||||
|
||||
/// @brief Reads an object from the specified address in the game's data section.
|
||||
/// @tparam Type The type of the object to be read.
|
||||
/// @param address The address of the object in flash memory.
|
||||
/// @param object An object into which the target object will be read.
|
||||
/// @warning
|
||||
/// `Type` should be:
|
||||
/// * _[trivially copyable](https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable)_
|
||||
/// * a _[standard-layout](https://en.cppreference.com/w/cpp/language/data_members#Standard-layout)_ type
|
||||
/// Attempting to read an object that does not meet these restrictions will result in _undefined behaviour_.
|
||||
template<typename Type>
|
||||
static void readDataObject(uint24_t address, Type & object)
|
||||
{
|
||||
readDataBytes(address, reinterpret_cast<uint8_t *>(&object), sizeof(object));
|
||||
}
|
||||
|
||||
static void readDataBytes(uint24_t address, uint8_t* buffer, size_t length);
|
||||
|
||||
/// @brief Reads an object from the specified address in the game's save section.
|
||||
/// @tparam Type The type of the object to be read.
|
||||
/// @param address The address of the object in flash memory.
|
||||
/// @param object An object into which the target object will be read.
|
||||
/// @warning
|
||||
/// `Type` should be:
|
||||
/// * _[trivially copyable](https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable)_
|
||||
/// * a _[standard-layout](https://en.cppreference.com/w/cpp/language/data_members#Standard-layout)_ type
|
||||
/// Attempting to read an object that does not meet these restrictions will result in _undefined behaviour_.
|
||||
template<typename Type>
|
||||
static void readSaveObject(uint24_t address, Type & object)
|
||||
{
|
||||
readSaveBytes(address, reinterpret_cast<uint8_t *>(&object), sizeof(object));
|
||||
}
|
||||
|
||||
static void readSaveBytes(uint24_t address, uint8_t* buffer, size_t length);
|
||||
|
||||
static uint8_t loadGameState(uint8_t* gameState, size_t size) __attribute__ ((noinline)); //loads GameState from program exclusive 4K save data block.
|
||||
/// @brief Loads a saved game state object from an exclusive 4KB save data block.
|
||||
/// @tparam Type The type of the object to be loaded.
|
||||
/// @param object The object into which the saved state will be loaded.
|
||||
/// @warning
|
||||
/// `Type` should be:
|
||||
/// * _[trivially copyable](https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable)_
|
||||
/// * a _[standard-layout](https://en.cppreference.com/w/cpp/language/data_members#Standard-layout)_ type
|
||||
/// Attempting to read an object that does not meet these restrictions will result in _undefined behaviour_.
|
||||
template<typename Type>
|
||||
static uint8_t loadGameState(Type & object)
|
||||
{
|
||||
return loadGameState((uint8_t*)(&object), sizeof(object));
|
||||
}
|
||||
|
||||
static void saveGameState(uint8_t* gameState, size_t size) __attribute__ ((noinline)); // Saves GameState in RAM to programes exclusive 4K save data block.
|
||||
[[gnu::noinline]]
|
||||
static uint8_t loadGameState(uint8_t* gameState, size_t size); //loads GameState from program exclusive 4K save data block.
|
||||
|
||||
/// @brief Saves a game state object into an exclusive 4KB save data block.
|
||||
/// @tparam Type The type of the object to be saved.
|
||||
/// @param object The object to be saved.
|
||||
/// @warning
|
||||
/// `Type` should be:
|
||||
/// * _[trivially copyable](https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable)_
|
||||
/// * a _[standard-layout](https://en.cppreference.com/w/cpp/language/data_members#Standard-layout)_ type
|
||||
/// Attempting to read an object that does not meet these restrictions will result in _undefined behaviour_.
|
||||
template<typename Type>
|
||||
static void saveGameState(const Type & object)
|
||||
{
|
||||
saveGameState(reinterpret_cast<const uint8_t *>(&object), sizeof(object));
|
||||
}
|
||||
|
||||
[[gnu::noinline]]
|
||||
static void saveGameState(const uint8_t* gameState, size_t size); // Saves GameState in RAM to programes exclusive 4K save data block.
|
||||
|
||||
static void eraseSaveBlock(uint16_t page); // erases 4K flash block
|
||||
|
||||
|
@ -283,13 +430,16 @@ class FX
|
|||
|
||||
static void waitWhileBusy(); // wait for outstanding erase or write to finish
|
||||
|
||||
static void drawBitmap(int16_t x, int16_t y, uint24_t address, uint8_t frame, uint8_t mode) __attribute__((noinline));
|
||||
[[gnu::noinline]]
|
||||
static void drawBitmap(int16_t x, int16_t y, uint24_t address, uint8_t frame, uint8_t mode);
|
||||
|
||||
static void setFrame(uint24_t frame, uint8_t repeat)__attribute__ ((noinline));
|
||||
[[gnu::noinline]]
|
||||
static void setFrame(uint24_t frame, uint8_t repeat);
|
||||
|
||||
static uint8_t drawFrame();
|
||||
|
||||
static uint24_t drawFrame(uint24_t address) __attribute__((noinline)); // draw a list of bitmap images located at address
|
||||
[[gnu::noinline]]
|
||||
static uint24_t drawFrame(uint24_t address); // draw a list of bitmap images located at address
|
||||
|
||||
static void readDataArray(uint24_t address, uint8_t index, uint8_t offset, uint8_t elementSize, uint8_t* buffer, size_t length);
|
||||
|
||||
|
@ -350,7 +500,8 @@ class FX
|
|||
|
||||
/* general optimized functions */
|
||||
|
||||
static inline uint16_t multiplyUInt8 (uint8_t a, uint8_t b) __attribute__((always_inline))
|
||||
[[gnu::always_inline]]
|
||||
static inline uint16_t multiplyUInt8 (uint8_t a, uint8_t b)
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
uint16_t result;
|
||||
|
@ -369,7 +520,8 @@ class FX
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline uint8_t bitShiftLeftUInt8(uint8_t bit) __attribute__((always_inline)) //fast (1 << (bit & 7))
|
||||
[[gnu::always_inline]]
|
||||
static inline uint8_t bitShiftLeftUInt8(uint8_t bit) //fast (1 << (bit & 7))
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
uint8_t result;
|
||||
|
@ -391,7 +543,8 @@ class FX
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline uint8_t bitShiftRightUInt8(uint8_t bit) __attribute__((always_inline)) //fast (0x80 >> (bit & 7))
|
||||
[[gnu::always_inline]]
|
||||
static inline uint8_t bitShiftRightUInt8(uint8_t bit) //fast (0x80 >> (bit & 7))
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
uint8_t result;
|
||||
|
@ -413,7 +566,8 @@ class FX
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline uint8_t bitShiftLeftMaskUInt8(uint8_t bit) __attribute__((always_inline)) //fast (0xFF << (bit & 7) & 0xFF)
|
||||
[[gnu::always_inline]]
|
||||
static inline uint8_t bitShiftLeftMaskUInt8(uint8_t bit) //fast (0xFF << (bit & 7) & 0xFF)
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
uint8_t result;
|
||||
|
@ -436,7 +590,8 @@ class FX
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline uint8_t bitShiftRightMaskUInt8(uint8_t bit) __attribute__((always_inline)) //fast (0xFF >> (bit & 7))
|
||||
[[gnu::always_inline]]
|
||||
static inline uint8_t bitShiftRightMaskUInt8(uint8_t bit) //fast (0xFF >> (bit & 7))
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
uint8_t result;
|
||||
|
@ -459,6 +614,46 @@ class FX
|
|||
#endif
|
||||
}
|
||||
|
||||
[[gnu::always_inline]]
|
||||
static inline int16_t fastDiv8(int16_t i)
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
asm volatile(
|
||||
"asr %B[i] \n"
|
||||
"ror %A[i] \n"
|
||||
"asr %B[i] \n"
|
||||
"ror %A[i] \n"
|
||||
"asr %B[i] \n"
|
||||
"ror %A[i] \n"
|
||||
: [i] "+r" (i)
|
||||
: "0" (i)
|
||||
);
|
||||
return i;
|
||||
#else
|
||||
return i >> 3;
|
||||
#endif
|
||||
};
|
||||
|
||||
[[gnu::always_inline]]
|
||||
static inline uint16_t fastDiv8(uint16_t i)
|
||||
{
|
||||
#ifdef ARDUINO_ARCH_AVR
|
||||
asm volatile(
|
||||
"lsr %B[i] \n"
|
||||
"ror %A[i] \n"
|
||||
"lsr %B[i] \n"
|
||||
"ror %A[i] \n"
|
||||
"lsr %B[i] \n"
|
||||
"ror %A[i] \n"
|
||||
: [i] "+r" (i)
|
||||
: "0" (i)
|
||||
);
|
||||
return i;
|
||||
#else
|
||||
return i >> 3;
|
||||
#endif
|
||||
};
|
||||
|
||||
static uint16_t programDataPage; // program read only data area in flash memory
|
||||
static uint16_t programSavePage; // program read and write data area in flash memory
|
||||
static Font font;
|
||||
|
|
Loading…
Reference in New Issue