v1.1.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Modules Pages
vram.h
1 /* -*- mode: C; c-basic-offset: 4; intent-tabs-mode: nil -*-
2  *
3  * Sifteo SDK
4  *
5  * Copyright <c> 2012 Sifteo, Inc.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  */
25 
26 #ifndef _SIFTEO_ABI_VRAM_H
27 #define _SIFTEO_ABI_VRAM_H
28 
29 #include <sifteo/abi/types.h>
30 
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34 
35 /*
36  * _SYSVideoRAM is a representation of the 1KB of RAM resident in each
37  * cube, which is used for storing the state of its graphics engine.
38  *
39  * The combination of this VRAM and the cube's current flash memory
40  * contents must contain all information necessary to compose a frame
41  * of graphics.
42  *
43  * The specific layout of this RAM may change depending on video mode
44  * settings. This union describes multiple different ways to access
45  * the VRAM.
46  */
47 
48 // Total size of VRAM, in bytes
49 #define _SYS_VRAM_BYTES 1024
50 #define _SYS_VRAM_BYTE_MASK (_SYS_VRAM_BYTES - 1)
51 
52 // Total size of VRAM, in words
53 #define _SYS_VRAM_WORDS (_SYS_VRAM_BYTES / 2)
54 #define _SYS_VRAM_WORD_MASK (_SYS_VRAM_WORDS - 1)
55 
56 #define _SYS_VRAM_BG0_WIDTH 18 // Width/height of BG0 tile grid
57 #define _SYS_VRAM_BG1_WIDTH 16 // Width/height of BG1 bitmap
58 #define _SYS_VRAM_BG1_TILES 144 // Total number of opaque tiles in BG1
59 #define _SYS_VRAM_BG2_WIDTH 16 // Width/height of BG2 tile grid
60 #define _SYS_VRAM_SPRITES 8 // Total number of linear sprites
61 #define _SYS_SPRITES_PER_LINE 4 // Maximum visible sprites per scanline
62 #define _SYS_CHROMA_KEY 0x4f // Chroma key MSB
63 #define _SYS_CKEY_BIT_EOL 0x40 // Chroma-key special bit, end-of-line
64 
65 // Bits for 'flags'
66 
67 #define _SYS_VF_RESERVED 0x01 // Reserved, must be zero
68 #define _SYS_VF_TOGGLE 0x02 // Toggle bit, to trigger a new frame render
69 #define _SYS_VF_SYNC 0x04 // Sync with LCD vertical refresh
70 #define _SYS_VF_CONTINUOUS 0x08 // Render continuously, without waiting for toggle
71 #define _SYS_VF_A21 0x10 // Flash A21 bank select
72 #define _SYS_VF_XY_SWAP 0x20 // Swap X and Y axes during render
73 #define _SYS_VF_X_FLIP 0x40 // Flip X axis during render
74 #define _SYS_VF_Y_FLIP 0x80 // Flip Y axis during render
75 
76 // Values for 'mode'
77 
78 #define _SYS_VM_MASK 0x3c // Mask of valid bits in VM_MASK
79 
80 #define _SYS_VM_POWERDOWN 0x00 // Power saving mode, LCD is off
81 #define _SYS_VM_BG0_ROM 0x04 // BG0, with tile data from internal ROM
82 #define _SYS_VM_SOLID 0x08 // Solid color, from colormap[0]
83 #define _SYS_VM_FB32 0x0c // 32x32 pixel 16-color framebuffer
84 #define _SYS_VM_FB64 0x10 // 64x64 pixel 2-color framebuffer
85 #define _SYS_VM_FB128 0x14 // 128x48 pixel 2-color framebuffer
86 #define _SYS_VM_BG0 0x18 // Background BG0: 18x18 grid
87 #define _SYS_VM_BG0_BG1 0x1c // BG0, plus overlay BG1: 16x16 bitmap + 144 indices
88 #define _SYS_VM_BG0_SPR_BG1 0x20 // BG0, multiple linear sprites, then BG1
89 #define _SYS_VM_BG2 0x24 // Background BG2: 16x16 grid with affine transform
90 #define _SYS_VM_STAMP 0x28 // Reconfigurable 16-color framebuffer with transparency
91 #define _SYS_VM_SLEEP 0x3c // Puts cube to sleep after fading out display
92 
93 // Important VRAM addresses
94 
95 #define _SYS_VA_BG0_TILES 0x000
96 #define _SYS_VA_BG2_TILES 0x000
97 #define _SYS_VA_BG2_AFFINE 0x200
98 #define _SYS_VA_BG2_BORDER 0x20c
99 #define _SYS_VA_BG1_TILES 0x288
100 #define _SYS_VA_COLORMAP 0x300
101 #define _SYS_VA_BG1_BITMAP 0x3a8
102 #define _SYS_VA_SPR 0x3c8
103 #define _SYS_VA_BG1_XY 0x3f8
104 #define _SYS_VA_BG0_XY 0x3fa
105 #define _SYS_VA_FIRST_LINE 0x3fc
106 #define _SYS_VA_NUM_LINES 0x3fd
107 #define _SYS_VA_MODE 0x3fe
108 #define _SYS_VA_FLAGS 0x3ff
109 #define _SYS_VA_STAMP_PITCH 0x320
110 
111 struct _SYSSpriteInfo {
112  /*
113  * Sprite sizes must be powers of two, and the
114  * size/position must both be negated.
115  *
116  * Sprites can be disabled by setting height to zero.
117  * A zero width with nonzero height will give undefined
118  * results.
119  */
120  int8_t mask_y; // 0x00 (-height), 0 == disable
121  int8_t mask_x; // 0x01 (-width)
122  int8_t pos_y; // 0x02 (-top)
123  int8_t pos_x; // 0x03 (-left)
124  uint16_t tile; // 0x04 Address in 7:7 format
125 };
126 
127 // Equivalent to an augmented matrix (3x2), in 8.8 fixed-point
128 struct _SYSAffine {
129  int16_t cx; // X initial value
130  int16_t cy; // Y initial value
131  int16_t xx; // X delta, for every horizontal pixel
132  int16_t xy; // Y delta, for every horizontal pixel
133  int16_t yx; // X delta, for every vertical pixel
134  int16_t yy; // Y delta, for every vertical pixel
135 };
136 
137 union _SYSVideoRAM {
138  uint8_t bytes[_SYS_VRAM_BYTES];
139  uint16_t words[_SYS_VRAM_WORDS];
140 
141  struct {
142  uint16_t bg0_tiles[324]; // 0x000 - 0x287
143  uint16_t bg1_tiles[144]; // 0x288 - 0x3a7
144  uint16_t bg1_bitmap[16]; // 0x3a8 - 0x3c7
145  struct _SYSSpriteInfo spr[8]; // 0x3c8 - 0x3f7
146  int8_t bg1_x; // 0x3f8
147  int8_t bg1_y; // 0x3f9
148  uint8_t bg0_x; // 0x3fa 0 <= x <= 143
149  uint8_t bg0_y; // 0x3fb 0 <= y <= 143
150  uint8_t first_line; // 0x3fc 0 <= x <= 127
151  uint8_t num_lines; // 0x3fd 1 <= x <= 128
152  uint8_t mode; // 0x3fe
153  uint8_t flags; // 0x3ff
154  };
155 
156  struct {
157  uint8_t fb[768]; // 0x000 - 0x2ff
158  uint16_t colormap[16]; // 0x300 - 0x31f
159  uint8_t stamp_pitch; // 0x320
160  uint8_t stamp_height; // 0x321
161  uint8_t stamp_x; // 0x322
162  uint8_t stamp_width; // 0x323
163  uint8_t stamp_key; // 0x324
164  };
165 
166  struct {
167  uint16_t bg2_tiles[256]; // 0x000 - 0x1ff
168  struct _SYSAffine bg2_affine; // 0x200 - 0x20b
169  uint16_t bg2_border; // 0x20c - 0x20d
170  };
171 };
172 
173 /*
174  * The _SYSVideoBuffer is a low-level data structure that serves to
175  * collect graphics state updates so that the system can send them
176  * over the radio to cubes.
177  *
178  * These buffers allow the system to send graphics data at the most
179  * optimal time, in the most optimal format, and without any
180  * unnecessary redundancy.
181  *
182  * VRAM is organized as a 1 kB array of bytes or words. We keep a few
183  * bitmaps at different resolutions, for the synchronization protocol
184  * below. These bitmaps are ordered MSB-first.
185  *
186  * Synchronization Protocol
187  * ------------------------
188  *
189  * To support the system's asynchronous access requirements, these
190  * buffers have a very strict synchronization protocol that user code
191  * must observe:
192  *
193  * 1. Set the 'lock' bit(s) for any words you plan to update,
194  * using an atomic store.
195  *
196  * 2. Update the VRAM buffer, using any method and in any order you like.
197  *
198  * 3. Set change bits in cm1, using an atomic OR such as
199  * __builtin_or_and_fetch().
200  *
201  * 4. Set change bits in cm16, using an atomic OR. After this point the
202  * system may start sending data over the radio at any time.
203  *
204  * 5. Soon after step (4), clear the lock bits you set in (1). Since
205  * the system treats lock bits as read-only, you can do this using
206  * a plain atomic store.
207  *
208  * Note that cm16 is the primary trigger that the system uses in order
209  * to determine if hardware VRAM needs to be updated. The lock bits do
210  * not prevent the system from reading VRAM, but rather they're used as
211  * part of the following invariant:
212  *
213  * - For any given word, we are guaranteed that the hardware's value
214  * matches the current buffered value if and only if the 'lock' bit
215  * is zero and the 'cm1' bit is zero.
216  *
217  * If not for the lock bits, this invariant would not be possible to
218  * maintain, since the system would have no idea when userspace code
219  * has modified the buffer, if it hasn't yet set the cm1 bits.
220  *
221  * Streaming over the radio can begin any time after cm16 has been
222  * updated. For bandwidth efficiency, it's best to wait until after a
223  * large update, then OR a single value with cm16 in order to trigger
224  * the update.
225  *
226  * The system may still start streaming updates while the 'lock' bit
227  * is set, but it will not be able to use the full range of protocol
228  * optimization techniques, since some of these rely on knowing for
229  * certain the values of words that have already been transmitted. So
230  * it is recommended that userspace clear the 'lock' bits as soon as
231  * possible after cm16 is set.
232  *
233  * Asynchronous Pipeline
234  * ---------------------
235  *
236  * When working with the graphics subsystem, it's helpful to keep in mind
237  * the pipeline of asynchronous rendering stages:
238  *
239  * 1. Changes are written to a locked vbuf (lock)
240  * 2. The vbuf is unlocked, changes can start to stream over the air (cm16 <- lock)
241  * 3. Streaming is finished (cm16 <- 0)
242  * 4. The cube hardware begins rendering a frame
243  * 5. The cube acknowledges rendering completion
244  *
245  * At any of these stages, a video buffer change can 'invalidate' the
246  * ongoing rendering, meaning we may need to render an additional frame before
247  * the final intended output is actually present on the display. Rendering is
248  * only considered to be 'finished' if we make it through steps 3-5 without
249  * any modifications to the video buffer.
250  *
251  * Paint Control
252  * -------------
253  *
254  * The _SYS_paint() call is a no-op for cubes who have had no drawing occur.
255  * This state is tracked, separately from the dirty bits, using a NEED_PAINT
256  * flag. This flag is cleared by _SYS_paint() itself, whereas the actual dirty
257  * bits are propagated through the firmware's model of the render pipeline.
258  * Userspace code can force a cube to redraw by setting NEED_PAINT, even
259  * without making any VRAM changes.
260  *
261  * This flag is set automatically by _SYS_vbuf_lock().
262  */
263 
264 #define _SYS_VBF_NEED_PAINT (1 << 0) // Request a paint operation
265 // All other bits are reserved for system use.
266 
267 struct _SYSVideoBuffer {
268  uint32_t flags;
269  uint32_t lock;
270  uint32_t cm16;
271  uint32_t cm1[16];
272  union _SYSVideoRAM vram;
273 };
274 
275 /*
276  * In general, the system likes working with raw _SYSVideoBuffers: but in
277  * userspace, it's very common to want to know both the _SYSVideoBuffer and
278  * the ID of the cube it's currently attached with. For these cases, we
279  * provide a standardized memory layout.
280  */
281 
282 struct _SYSAttachedVideoBuffer {
283  _SYSCubeID cube;
284  uint8_t reserved[3];
285  struct _SYSVideoBuffer vbuf;
286 };
287 
288 /*
289  * Tiles in the _SYSVideoBuffer are typically encoded in 7:7 format, in
290  * which a 14-bit tile ID is packed into the upper 7 bits of each byte
291  * in a 16-bit word.
292  */
293 
294 #define _SYS_TILE77(_idx) ((((_idx) << 2) & 0xFE00) | \
295  (((_idx) << 1) & 0x00FE))
296 
297 #define _SYS_INVERSE_TILE77(_t77) ((((_t77) & 0xFE00) >> 2) | \
298  (((_t77) & 0x00FE) >> 1))
299 
300 #ifdef __cplusplus
301 } // extern "C"
302 #endif
303 
304 #endif