19#include "hardware/dma.h"
20#include "hardware/gpio.h"
21#include "pico/divider.h"
40#ifndef PICO9918_INT_GPIO
41#error "PICO9918_INT_GPIO must be defined by the host build (the GPIO driving /INT)"
44#ifdef PICO9918_INT_ACTIVE_HIGH
45#define PICO9918_HOST_SET_INT(active) gpio_put(PICO9918_INT_GPIO, (active))
47#define PICO9918_HOST_SET_INT(active) gpio_put(PICO9918_INT_GPIO, !(active))
54#define PICO9918_SECTION_SCRATCH_X(name) __attribute__((section(".scratch_x." #name)))
55#define PICO9918_SECTION_SCRATCH_Y(name) __attribute__((section(".scratch_y." #name)))
59#define PICO9918_UNINITIALIZED(decl) __uninitialized_ram(decl)
65#if PICO9918_COLD_IN_FLASH
66#define PICO9918_IN_FLASH_FUNC(fn) __attribute__((section(".flashcode." __STRING(fn)), noinline)) fn
68#define PICO9918_IN_FLASH_FUNC(fn) fn
120#ifndef PICO9918_FILL_BORDER
121#define PICO9918_FILL_BORDER 2u
124#define PICO9918_FILL32_INIT(inst, srcPtr) \
127 dma_channel_config _cfg = dma_channel_get_default_config(inst); \
128 channel_config_set_read_increment(&_cfg, false); \
129 channel_config_set_write_increment(&_cfg, true); \
130 channel_config_set_transfer_data_size(&_cfg, DMA_SIZE_32); \
131 dma_channel_set_config((inst), &_cfg, false); \
132 dma_channel_set_read_addr((inst), (srcPtr), false); \
135#define PICO9918_FILL32_SET_COUNT(inst, n) dma_channel_set_trans_count((inst), (n), false)
136#define PICO9918_FILL32_TRIGGER(inst, dstPtr) dma_channel_set_write_addr((inst), (dstPtr), true)
137#define PICO9918_FILL32_WAIT(inst) dma_channel_wait_for_finish_blocking(inst)
150#ifndef PICO9918_FILL_MASKS
151#define PICO9918_FILL_MASKS 5u
154#ifndef PICO9918_FILL_LINE
155#define PICO9918_FILL_LINE 6u
159#define PICO9918_COPY 7u
162extern dma_channel_config pico9918_copy_byte;
163extern dma_channel_config pico9918_copy_word;
166#define PICO9918_COPY_STATE() \
167 dma_channel_config pico9918_copy_byte; \
168 dma_channel_config pico9918_copy_word;
170#define PICO9918_COPY_INIT(inst) \
173 dma_channel_config _cfg = dma_channel_get_default_config(inst); \
174 channel_config_set_write_increment(&_cfg, true); \
175 channel_config_set_high_priority(&_cfg, true); \
176 channel_config_set_transfer_data_size(&_cfg, DMA_SIZE_8); \
177 pico9918_copy_byte = _cfg; \
178 channel_config_set_transfer_data_size(&_cfg, DMA_SIZE_32); \
179 pico9918_copy_word = _cfg; \
180 dma_channel_set_config((inst), &pico9918_copy_byte, false); \
183#define PICO9918_COPY_SET_WIDTH(inst, wordAligned) \
184 dma_channel_set_config((inst), (wordAligned) ? &pico9918_copy_word : &pico9918_copy_byte, false)
186#define PICO9918_COPY_SET_SRC(inst, srcPtr) dma_channel_set_read_addr((inst), (srcPtr), false)
187#define PICO9918_COPY_SET_DST(inst, dstPtr) dma_channel_set_write_addr((inst), (dstPtr), false)
188#define PICO9918_COPY_TRIGGER(inst, n) dma_channel_set_trans_count((inst), (n), true)
189#define PICO9918_COPY_WAIT(inst) dma_channel_wait_for_finish_blocking(inst)
193#define PICO9918_DIVMOD_U32(n, d, q, r) \
196 divmod_result_t _dm = divmod_u32u32((n), (d)); \
197 (q) = to_quotient_u32(_dm); \
198 (r) = to_remainder_u32(_dm); \
208#define PICO9918_DMA_CLAIM() \
209 dma_claim_mask((1u << PICO9918_FILL_BORDER) | (1u << PICO9918_FILL_MASKS) | \
210 (1u << PICO9918_FILL_LINE) | (1u << PICO9918_COPY))
243typedef uint16_t PICO9918_PIXEL_T;
245#define PICO9918_PIXEL_FROM_RGB12(rgb) ((PICO9918_PIXEL_T)(((rgb) & 0xFF0F) | ((((rgb) & 0xFF0F) >> 12) << 4)))
249#define PICO9918_PIXEL_FROM_RGB12_PAIR(packed) \
250 ((packed) ^ (((packed) ^ ((packed) >> 8)) & 0x00F000F0u))
256#define PICO9918_PIXEL_PAIR(p) \
258 uint32_t _v = (p), _f = 0x10001u; \
259 __asm__("mul %0, %1" : "+l"(_v) : "l"(_f) : "cc"); \
262#define PICO9918_LOW16(x) \
264 uint32_t _l, _x = (x); \
265 __asm__("uxth %0, %1" : "=l"(_l) : "l"(_x)); \
269#define PICO9918_PIXEL_PAIR(p) ((uint32_t)(p) * 0x10001u)
270#define PICO9918_LOW16(x) ((uint32_t)(uint16_t)(x))
274#define PICO9918_PIXEL_DARKEN(p) ((PICO9918_PIXEL_T)(((p) >> 2) & 0x333))
280#define PICO9918_PIXEL_PAIR_DIM(w) (((w) >> 1) & 0x07770777u)
287typedef uint32_t PICO9918_INK_T;
288#define PICO9918_INK_PIXELS 2
289#define PICO9918_INK_FILL(fg) PICO9918_PIXEL_PAIR(fg)
290#define PICO9918_INK_DARKEN(w) (((w) >> 2) & 0x03330333u)
291#define PICO9918_INK_ONE(k) (0xffffu << ((k) * 16))
297typedef uint32_t PICO9918_PALETTE_LUT_T;
304#include "hardware/interp.h"
312#define PICO9918_EXPAND_INIT(lut) \
315 const uint8_t _shift[4] = {0, 8, 14, 22}; \
316 for (uint _i = 0; _i < 4; ++_i) \
318 interp_hw_t* _interp = (_i & 2) ? interp1 : interp0; \
319 const uint _lane = _i & 1; \
320 interp_config _c = interp_default_config(); \
321 interp_config_set_shift(&_c, _shift[_i]); \
322 interp_config_set_mask(&_c, 2, 9); \
323 interp_config_set_cross_input(&_c, _lane == 1); \
324 interp_set_config(_interp, _lane, &_c); \
325 interp_set_base(_interp, _lane, (uintptr_t)(lut)); \
329#define PICO9918_EXPAND_INDEXED(dst, src, n, lut) \
332 const uint32_t* _s = (const uint32_t*)(src); \
333 const uint32_t* _e = _s + (n) / 4; \
334 uint32_t* _d = (uint32_t*)(dst); \
337 uint32_t _w = *_s++; \
338 interp1->accum[0] = _w; \
339 interp0->accum[0] = _w << 2; \
340 _d[0] = *(const uint32_t*)interp0->peek[0]; \
341 _d[1] = *(const uint32_t*)interp0->peek[1]; \
342 _d[2] = *(const uint32_t*)interp1->peek[0]; \
343 _d[3] = *(const uint32_t*)interp1->peek[1]; \
345 interp1->accum[0] = _w; \
346 interp0->accum[0] = _w << 2; \
347 _d[4] = *(const uint32_t*)interp0->peek[0]; \
348 _d[5] = *(const uint32_t*)interp0->peek[1]; \
349 _d[6] = *(const uint32_t*)interp1->peek[0]; \
350 _d[7] = *(const uint32_t*)interp1->peek[1]; \
361#define PICO9918_EXPAND_INIT(lut) ((void)0)
363#define PICO9918_EXPAND_INDEXED(dst, src, n, lut) \
366 const uint8_t* _s = (const uint8_t*)(src); \
367 const uint8_t* _e = _s + (n); \
368 uint32_t* _d = (uint32_t*)(dst); \
369 const PICO9918_PALETTE_LUT_T* _l = (lut); \
392#define PICO9918_EXPAND_INDEXED_WIDE(dst, src, n, lut) \
395 const uint8_t* _s = (const uint8_t*)(src); \
396 const uint8_t* _e = _s + (n); \
397 uint32_t* _d = (uint32_t*)(dst); \
398 const PICO9918_PALETTE_LUT_T* _l = (lut); \
401 _d[0] = (_l[_s[0]] & 0xffff) | (_l[_s[1]] << 16); \
402 _d[1] = (_l[_s[2]] & 0xffff) | (_l[_s[3]] << 16); \
403 _d[2] = (_l[_s[4]] & 0xffff) | (_l[_s[5]] << 16); \
404 _d[3] = (_l[_s[6]] & 0xffff) | (_l[_s[7]] << 16); \