mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-12 07:44:18 +00:00
This was introducing a mysterious "line" artifact on text rendering in new systems. Probably need to do some real on-device testing of this change because the automated tests won't catch a dirty bit error on the LCD.
586 lines
20 KiB
Rust
586 lines
20 KiB
Rust
// Copyright (c) 2022 Sam Blenny
|
|
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
//
|
|
use super::cliprect::ClipRect;
|
|
use crate::GlyphSprite;
|
|
use crate::platform::{FrBuf, WIDTH, WORDS_PER_LINE};
|
|
|
|
/// Null glyph to use when everything else fails
|
|
pub const NULL_GLYPH: [u32; 8] = [0, 0x5500AA, 0x5500AA, 0x5500AA, 0x5500AA, 0x5500AA, 0, 0];
|
|
pub const NULL_GLYPH_SPRITE: GlyphSprite = GlyphSprite {
|
|
glyph: &NULL_GLYPH,
|
|
wide: 8u8,
|
|
high: 12u8,
|
|
kern: 1,
|
|
ch: '\u{0}',
|
|
invert: false,
|
|
insert: false,
|
|
double: false,
|
|
large: false,
|
|
};
|
|
|
|
/// Unicode replacement character
|
|
pub const REPLACEMENT: char = '\u{FFFD}';
|
|
|
|
/// Blit a glyph with XOR at point; caller is responsible for word wrap.
|
|
///
|
|
/// Examples of word alignment for destination frame buffer:
|
|
/// 1. Fits in word: xr:1..7 => (data[0].bit_30)->(data[0].bit_26), mask:0x7c00_0000
|
|
/// 2. Spans words: xr:30..36 => (data[0].bit_01)->(data[1].bit_29), mask:[0x0000_0003,0xe000_000]
|
|
///
|
|
/// Point `p` is specified as a tuple of `(isize, isize)` where index 0 is the x-coord, and 1 is the y-coord
|
|
pub fn xor_glyph(fb: &mut FrBuf, p: (isize, isize), gs: &GlyphSprite, xor: bool, cr: ClipRect) {
|
|
let px = p.0;
|
|
let py = p.1;
|
|
const SPRITE_PX: isize = 16;
|
|
const SPRITE_WORDS: isize = 8;
|
|
if gs.glyph.len() < SPRITE_WORDS as usize {
|
|
// Fail silently if the glyph slice was too small
|
|
// TODO: Maybe return an error? Not sure which way is better.
|
|
return;
|
|
}
|
|
let high = gs.high as isize;
|
|
let wide = gs.wide as isize;
|
|
if high > SPRITE_PX || wide > SPRITE_PX {
|
|
// Fail silently if glyph height or width is out of spec
|
|
// TODO: Maybe return an error?
|
|
return;
|
|
}
|
|
// Calculate word alignment for destination buffer
|
|
let x0 = px;
|
|
if x0 >= cr.max.x as isize {
|
|
log::trace!("out the right");
|
|
return;
|
|
} // out the right hand side
|
|
let x1 = px + wide - 1;
|
|
if x1 < cr.min.x as isize {
|
|
log::trace!("out the left");
|
|
return;
|
|
} // out the left hand side
|
|
let dest_low_word = x0 >> 5;
|
|
let dest_high_word = x1 >> 5;
|
|
let px_in_dest_low_word = 32 - (x0 & 0x1f);
|
|
// Blit it (use glyph height to avoid blitting empty rows)
|
|
let mut row_base = py * WORDS_PER_LINE as isize;
|
|
let row_upper_limit = cr.max.y as isize * WORDS_PER_LINE as isize;
|
|
let row_lower_limit = cr.min.y as isize * WORDS_PER_LINE as isize;
|
|
for y in 0..high as usize {
|
|
if row_base >= row_upper_limit {
|
|
log::trace!("off the bottom");
|
|
// Clip anything that would run off the end of the frame buffer
|
|
break;
|
|
}
|
|
if row_base >= row_lower_limit {
|
|
// Unpack pixels for this glyph row.
|
|
// CAUTION: some math magic happening here...
|
|
// when y==0, this does (glyph[0] >> 0) & mask,
|
|
// when y==1, this does (glyph[0] >> 16) & mask,
|
|
// when y==2, this does (glyph[1] >> 0) & mask,
|
|
// ...
|
|
let mask = 0x0000ffff as u32;
|
|
let shift = (y as u32 & 1) << 4;
|
|
let pattern = (gs.glyph[y >> 1] >> shift) & mask;
|
|
|
|
// compute partial masks to prevent glyphs from "spilling over" the clip rectangle
|
|
let mut partial_mask_lo = 0xffff_ffff;
|
|
let mut partial_mask_hi = 0xffff_ffff;
|
|
if x0 < cr.min.x as isize || x1 >= cr.max.x as isize {
|
|
let x0a = if x0 < cr.min.x as isize { cr.min.x as isize } else { x0 };
|
|
let x1a = if x1 >= cr.max.x as isize { cr.max.x as isize } else { x1 };
|
|
let mut ones = (1u64 << ((x1a - x0a) as u64 + 1)) - 1;
|
|
ones <<= x0a as u64 & 0x1f;
|
|
partial_mask_lo = ones as u32;
|
|
partial_mask_hi = (ones >> 32) as u32;
|
|
}
|
|
// XOR glyph pixels onto destination buffer. Note that despite the masks above, we will not render
|
|
// partial glyphs that cross the absolute bounds of the left and right edge of the screen.
|
|
if x0 >= 0 && x1 < WIDTH as isize {
|
|
if xor {
|
|
fb[(row_base + dest_low_word) as usize] ^=
|
|
(pattern << (32 - px_in_dest_low_word)) & partial_mask_lo;
|
|
} else {
|
|
fb[(row_base + dest_low_word) as usize] &=
|
|
0xffff_ffff ^ ((pattern << (32 - px_in_dest_low_word)) & partial_mask_lo);
|
|
}
|
|
if wide > px_in_dest_low_word {
|
|
if xor {
|
|
fb[(row_base + dest_high_word) as usize] ^=
|
|
(pattern >> px_in_dest_low_word) & partial_mask_hi;
|
|
} else {
|
|
fb[(row_base + dest_high_word) as usize] &=
|
|
0xffff_ffff ^ ((pattern >> px_in_dest_low_word) & partial_mask_hi);
|
|
}
|
|
}
|
|
#[cfg(any(feature = "hosted", feature = "renode", feature = "precursor"))]
|
|
{
|
|
fb[(row_base as usize + WORDS_PER_LINE - 1) as usize] |= 0x1_0000; // set the dirty bit on the line
|
|
}
|
|
} else {
|
|
log::trace!("absolute x/y fail");
|
|
}
|
|
} else {
|
|
log::trace!("off the top");
|
|
}
|
|
|
|
// Advance destination offset using + instead of * to maybe save some CPU cycles
|
|
row_base += WORDS_PER_LINE as isize;
|
|
}
|
|
}
|
|
|
|
/// Blit a glyph that is based off of 32x sprites.
|
|
pub fn xor_glyph_large(fb: &mut FrBuf, p: (isize, isize), gs: &GlyphSprite, xor: bool, cr: ClipRect) {
|
|
let px = p.0;
|
|
let py = p.1;
|
|
const SPRITE_PX: isize = 32;
|
|
const SPRITE_WORDS: isize = 8;
|
|
if gs.glyph.len() < SPRITE_WORDS as usize {
|
|
// Fail silently if the glyph slice was too small
|
|
// TODO: Maybe return an error? Not sure which way is better.
|
|
log::info!("len err: {}", gs.glyph.len());
|
|
return;
|
|
}
|
|
let high = gs.high as isize / 2;
|
|
let wide = (gs.wide as isize / 2).max(1);
|
|
if high > SPRITE_PX || wide > SPRITE_PX {
|
|
// Fail silently if glyph height or width is out of spec
|
|
// TODO: Maybe return an error?
|
|
log::info!("high/wide err");
|
|
return;
|
|
}
|
|
// Calculate word alignment for destination buffer
|
|
let x0 = px;
|
|
if x0 >= cr.max.x as isize {
|
|
log::trace!("out the right");
|
|
return;
|
|
} // out the right hand side
|
|
let x1 = px + (wide << 1) - 1;
|
|
if x1 < cr.min.x as isize {
|
|
log::trace!("out the left");
|
|
return;
|
|
} // out the left hand side
|
|
let dest_low_word = x0 >> 5;
|
|
let mut dest_high_word = x1 >> 5;
|
|
// fixup case where a glyph is very narrow and and gs.wide / 2 is rounded down to 0.
|
|
// this happens on things like '.' and '1'.
|
|
if dest_high_word == dest_low_word {
|
|
dest_high_word += 1;
|
|
}
|
|
let px_in_dest_low_word = 32 - (x0 & 0x1f);
|
|
// Blit it (use glyph height to avoid blitting empty rows)
|
|
let mut row_base = py * WORDS_PER_LINE as isize;
|
|
let row_upper_limit = cr.max.y as isize * WORDS_PER_LINE as isize;
|
|
let row_lower_limit = cr.min.y as isize * WORDS_PER_LINE as isize;
|
|
let glyph = gs.glyph;
|
|
// Blit the large glyph
|
|
for src in glyph {
|
|
if row_base >= row_upper_limit {
|
|
// Clip anything that would run off the end of the frame buffer
|
|
break;
|
|
}
|
|
if row_base >= row_lower_limit {
|
|
// compute partial masks to prevent glyphs from "spilling over" the clip rectangle
|
|
let mut partial_mask_lo = 0xffff_ffff;
|
|
let mut partial_mask_hi = 0xffff_ffff;
|
|
let x1_2x = px + ((gs.wide as isize) << 1) - 1;
|
|
if x0 < cr.min.x as isize || x1_2x >= cr.max.x as isize {
|
|
let x0a = if x0 < cr.min.x as isize { cr.min.x as isize } else { x0 };
|
|
let x1a = if x1_2x >= cr.max.x as isize { cr.max.x as isize } else { x1_2x };
|
|
let mut ones = (1u64 << ((x1a - x0a) as u64 + 1)) - 1;
|
|
ones <<= x0a as u64 & 0x1f;
|
|
partial_mask_lo = ones as u32;
|
|
partial_mask_hi = (ones >> 32) as u32;
|
|
}
|
|
|
|
// XOR glyph pixels onto destination buffer
|
|
if x0 >= 0 && x1_2x < WIDTH as isize {
|
|
if xor {
|
|
fb[(row_base + dest_low_word) as usize] ^=
|
|
(src << (32 - px_in_dest_low_word)) & partial_mask_lo;
|
|
} else {
|
|
fb[(row_base + dest_low_word) as usize] &=
|
|
0xffff_ffff ^ ((src << (32 - px_in_dest_low_word)) & partial_mask_lo);
|
|
}
|
|
if (wide << 1) >= px_in_dest_low_word {
|
|
if xor {
|
|
fb[(row_base + dest_high_word) as usize] ^=
|
|
(src >> px_in_dest_low_word) & partial_mask_hi;
|
|
} else {
|
|
fb[(row_base + dest_high_word) as usize] &=
|
|
0xffff_ffff ^ ((src >> px_in_dest_low_word) & partial_mask_hi);
|
|
}
|
|
}
|
|
#[cfg(any(feature = "hosted", feature = "renode", feature = "precursor"))]
|
|
{
|
|
fb[(row_base as usize + WORDS_PER_LINE - 1) as usize] |= 0x1_0000; // set the dirty bit on the line
|
|
}
|
|
}
|
|
}
|
|
// Advance destination offset using + instead of * to maybe save some CPU cycles
|
|
row_base += WORDS_PER_LINE as isize;
|
|
}
|
|
}
|
|
|
|
/// Blit a 2x scaled glyph with XOR at point; caller is responsible for word wrap.
|
|
///
|
|
/// This is similar to xor_glyph(). But, instead of using 16px sprites for input
|
|
/// and output, this takes 16px sprites as input and blits 32px sprites as output.
|
|
pub fn xor_glyph_2x(fb: &mut FrBuf, p: (isize, isize), gs: &GlyphSprite, xor: bool, cr: ClipRect) {
|
|
let px = p.0;
|
|
let py = p.1;
|
|
const SPRITE_PX: isize = 16;
|
|
const SPRITE_WORDS: isize = 8;
|
|
if gs.glyph.len() < SPRITE_WORDS as usize {
|
|
// Fail silently if the glyph slice was too small
|
|
// TODO: Maybe return an error? Not sure which way is better.
|
|
return;
|
|
}
|
|
let high = gs.high as isize / 2;
|
|
let wide = (gs.wide as isize / 2).max(1);
|
|
if high > SPRITE_PX || wide > SPRITE_PX {
|
|
// Fail silently if glyph height or width is out of spec
|
|
// TODO: Maybe return an error?
|
|
return;
|
|
}
|
|
// Calculate word alignment for destination buffer
|
|
let x0 = px;
|
|
if x0 >= cr.max.x as isize {
|
|
log::trace!("out the right");
|
|
return;
|
|
} // out the right hand side
|
|
let x1 = px + (wide << 1) - 1;
|
|
if x1 < cr.min.x as isize {
|
|
log::trace!("out the left");
|
|
return;
|
|
} // out the left hand side
|
|
let dest_low_word = x0 >> 5;
|
|
let mut dest_high_word = x1 >> 5;
|
|
if dest_high_word == dest_low_word {
|
|
dest_high_word += 1;
|
|
}
|
|
let px_in_dest_low_word = 32 - (x0 & 0x1f);
|
|
// Blit it (use glyph height to avoid blitting empty rows)
|
|
let mut row_base = py * WORDS_PER_LINE as isize;
|
|
let row_upper_limit = cr.max.y as isize * WORDS_PER_LINE as isize;
|
|
let row_lower_limit = cr.min.y as isize * WORDS_PER_LINE as isize;
|
|
let glyph = gs.glyph;
|
|
// Scale up 2x
|
|
let mut glyph_2x = [0u32; 32];
|
|
let mask = 0x0000ffff as u32;
|
|
for y in 0..high as usize {
|
|
let shift = (y as u32 & 1) << 4;
|
|
let pattern = (glyph[y >> 1] >> shift) & mask;
|
|
let low_2x = LUT_2X[(pattern & 0xff) as usize] as u32;
|
|
let high_2x = LUT_2X[((pattern >> 8) & 0xff) as usize] as u32;
|
|
let both_2x = low_2x | (high_2x << 16);
|
|
let index_2x = y << 1;
|
|
glyph_2x[index_2x] = both_2x;
|
|
glyph_2x[index_2x + 1] = both_2x;
|
|
}
|
|
// Blit the scaled up glyph
|
|
for src in glyph_2x {
|
|
if row_base >= row_upper_limit {
|
|
// Clip anything that would run off the end of the frame buffer
|
|
break;
|
|
}
|
|
if row_base >= row_lower_limit {
|
|
// compute partial masks to prevent glyphs from "spilling over" the clip rectangle
|
|
let mut partial_mask_lo = 0xffff_ffff;
|
|
let mut partial_mask_hi = 0xffff_ffff;
|
|
let x1_2x = px + ((gs.wide as isize) << 1) - 1;
|
|
if x0 < cr.min.x as isize || x1_2x >= cr.max.x as isize {
|
|
let x0a = if x0 < cr.min.x as isize { cr.min.x as isize } else { x0 };
|
|
let x1a = if x1_2x >= cr.max.x as isize { cr.max.x as isize } else { x1_2x };
|
|
let mut ones = (1u64 << ((x1a - x0a) as u64 + 1)) - 1;
|
|
ones <<= x0a as u64 & 0x1f;
|
|
partial_mask_lo = ones as u32;
|
|
partial_mask_hi = (ones >> 32) as u32;
|
|
}
|
|
|
|
// XOR glyph pixels onto destination buffer
|
|
if x0 >= 0 && x1_2x < WIDTH as isize {
|
|
if xor {
|
|
fb[(row_base + dest_low_word) as usize] ^=
|
|
(src << (32 - px_in_dest_low_word)) & partial_mask_lo;
|
|
} else {
|
|
fb[(row_base + dest_low_word) as usize] &=
|
|
0xffff_ffff ^ ((src << (32 - px_in_dest_low_word)) & partial_mask_lo);
|
|
}
|
|
if (wide << 1) >= px_in_dest_low_word {
|
|
if xor {
|
|
fb[(row_base + dest_high_word) as usize] ^=
|
|
(src >> px_in_dest_low_word) & partial_mask_hi;
|
|
} else {
|
|
fb[(row_base + dest_high_word) as usize] &=
|
|
0xffff_ffff ^ ((src >> px_in_dest_low_word) & partial_mask_hi);
|
|
}
|
|
}
|
|
#[cfg(any(feature = "hosted", feature = "renode", feature = "precursor"))]
|
|
{
|
|
fb[(row_base as usize + WORDS_PER_LINE - 1) as usize] |= 0x1_0000; // set the dirty bit on the line
|
|
}
|
|
}
|
|
}
|
|
// Advance destination offset using + instead of * to maybe save some CPU cycles
|
|
row_base += WORDS_PER_LINE as isize;
|
|
}
|
|
}
|
|
|
|
/// Lookup table to speed up 2x scaling by expanding u8 index to u16 value
|
|
pub const LUT_2X: [u16; 256] = [
|
|
0b0000000000000000,
|
|
0b0000000000000011,
|
|
0b0000000000001100,
|
|
0b0000000000001111,
|
|
0b0000000000110000,
|
|
0b0000000000110011,
|
|
0b0000000000111100,
|
|
0b0000000000111111,
|
|
0b0000000011000000,
|
|
0b0000000011000011,
|
|
0b0000000011001100,
|
|
0b0000000011001111,
|
|
0b0000000011110000,
|
|
0b0000000011110011,
|
|
0b0000000011111100,
|
|
0b0000000011111111,
|
|
0b0000001100000000,
|
|
0b0000001100000011,
|
|
0b0000001100001100,
|
|
0b0000001100001111,
|
|
0b0000001100110000,
|
|
0b0000001100110011,
|
|
0b0000001100111100,
|
|
0b0000001100111111,
|
|
0b0000001111000000,
|
|
0b0000001111000011,
|
|
0b0000001111001100,
|
|
0b0000001111001111,
|
|
0b0000001111110000,
|
|
0b0000001111110011,
|
|
0b0000001111111100,
|
|
0b0000001111111111,
|
|
0b0000110000000000,
|
|
0b0000110000000011,
|
|
0b0000110000001100,
|
|
0b0000110000001111,
|
|
0b0000110000110000,
|
|
0b0000110000110011,
|
|
0b0000110000111100,
|
|
0b0000110000111111,
|
|
0b0000110011000000,
|
|
0b0000110011000011,
|
|
0b0000110011001100,
|
|
0b0000110011001111,
|
|
0b0000110011110000,
|
|
0b0000110011110011,
|
|
0b0000110011111100,
|
|
0b0000110011111111,
|
|
0b0000111100000000,
|
|
0b0000111100000011,
|
|
0b0000111100001100,
|
|
0b0000111100001111,
|
|
0b0000111100110000,
|
|
0b0000111100110011,
|
|
0b0000111100111100,
|
|
0b0000111100111111,
|
|
0b0000111111000000,
|
|
0b0000111111000011,
|
|
0b0000111111001100,
|
|
0b0000111111001111,
|
|
0b0000111111110000,
|
|
0b0000111111110011,
|
|
0b0000111111111100,
|
|
0b0000111111111111,
|
|
0b0011000000000000,
|
|
0b0011000000000011,
|
|
0b0011000000001100,
|
|
0b0011000000001111,
|
|
0b0011000000110000,
|
|
0b0011000000110011,
|
|
0b0011000000111100,
|
|
0b0011000000111111,
|
|
0b0011000011000000,
|
|
0b0011000011000011,
|
|
0b0011000011001100,
|
|
0b0011000011001111,
|
|
0b0011000011110000,
|
|
0b0011000011110011,
|
|
0b0011000011111100,
|
|
0b0011000011111111,
|
|
0b0011001100000000,
|
|
0b0011001100000011,
|
|
0b0011001100001100,
|
|
0b0011001100001111,
|
|
0b0011001100110000,
|
|
0b0011001100110011,
|
|
0b0011001100111100,
|
|
0b0011001100111111,
|
|
0b0011001111000000,
|
|
0b0011001111000011,
|
|
0b0011001111001100,
|
|
0b0011001111001111,
|
|
0b0011001111110000,
|
|
0b0011001111110011,
|
|
0b0011001111111100,
|
|
0b0011001111111111,
|
|
0b0011110000000000,
|
|
0b0011110000000011,
|
|
0b0011110000001100,
|
|
0b0011110000001111,
|
|
0b0011110000110000,
|
|
0b0011110000110011,
|
|
0b0011110000111100,
|
|
0b0011110000111111,
|
|
0b0011110011000000,
|
|
0b0011110011000011,
|
|
0b0011110011001100,
|
|
0b0011110011001111,
|
|
0b0011110011110000,
|
|
0b0011110011110011,
|
|
0b0011110011111100,
|
|
0b0011110011111111,
|
|
0b0011111100000000,
|
|
0b0011111100000011,
|
|
0b0011111100001100,
|
|
0b0011111100001111,
|
|
0b0011111100110000,
|
|
0b0011111100110011,
|
|
0b0011111100111100,
|
|
0b0011111100111111,
|
|
0b0011111111000000,
|
|
0b0011111111000011,
|
|
0b0011111111001100,
|
|
0b0011111111001111,
|
|
0b0011111111110000,
|
|
0b0011111111110011,
|
|
0b0011111111111100,
|
|
0b0011111111111111,
|
|
0b1100000000000000,
|
|
0b1100000000000011,
|
|
0b1100000000001100,
|
|
0b1100000000001111,
|
|
0b1100000000110000,
|
|
0b1100000000110011,
|
|
0b1100000000111100,
|
|
0b1100000000111111,
|
|
0b1100000011000000,
|
|
0b1100000011000011,
|
|
0b1100000011001100,
|
|
0b1100000011001111,
|
|
0b1100000011110000,
|
|
0b1100000011110011,
|
|
0b1100000011111100,
|
|
0b1100000011111111,
|
|
0b1100001100000000,
|
|
0b1100001100000011,
|
|
0b1100001100001100,
|
|
0b1100001100001111,
|
|
0b1100001100110000,
|
|
0b1100001100110011,
|
|
0b1100001100111100,
|
|
0b1100001100111111,
|
|
0b1100001111000000,
|
|
0b1100001111000011,
|
|
0b1100001111001100,
|
|
0b1100001111001111,
|
|
0b1100001111110000,
|
|
0b1100001111110011,
|
|
0b1100001111111100,
|
|
0b1100001111111111,
|
|
0b1100110000000000,
|
|
0b1100110000000011,
|
|
0b1100110000001100,
|
|
0b1100110000001111,
|
|
0b1100110000110000,
|
|
0b1100110000110011,
|
|
0b1100110000111100,
|
|
0b1100110000111111,
|
|
0b1100110011000000,
|
|
0b1100110011000011,
|
|
0b1100110011001100,
|
|
0b1100110011001111,
|
|
0b1100110011110000,
|
|
0b1100110011110011,
|
|
0b1100110011111100,
|
|
0b1100110011111111,
|
|
0b1100111100000000,
|
|
0b1100111100000011,
|
|
0b1100111100001100,
|
|
0b1100111100001111,
|
|
0b1100111100110000,
|
|
0b1100111100110011,
|
|
0b1100111100111100,
|
|
0b1100111100111111,
|
|
0b1100111111000000,
|
|
0b1100111111000011,
|
|
0b1100111111001100,
|
|
0b1100111111001111,
|
|
0b1100111111110000,
|
|
0b1100111111110011,
|
|
0b1100111111111100,
|
|
0b1100111111111111,
|
|
0b1111000000000000,
|
|
0b1111000000000011,
|
|
0b1111000000001100,
|
|
0b1111000000001111,
|
|
0b1111000000110000,
|
|
0b1111000000110011,
|
|
0b1111000000111100,
|
|
0b1111000000111111,
|
|
0b1111000011000000,
|
|
0b1111000011000011,
|
|
0b1111000011001100,
|
|
0b1111000011001111,
|
|
0b1111000011110000,
|
|
0b1111000011110011,
|
|
0b1111000011111100,
|
|
0b1111000011111111,
|
|
0b1111001100000000,
|
|
0b1111001100000011,
|
|
0b1111001100001100,
|
|
0b1111001100001111,
|
|
0b1111001100110000,
|
|
0b1111001100110011,
|
|
0b1111001100111100,
|
|
0b1111001100111111,
|
|
0b1111001111000000,
|
|
0b1111001111000011,
|
|
0b1111001111001100,
|
|
0b1111001111001111,
|
|
0b1111001111110000,
|
|
0b1111001111110011,
|
|
0b1111001111111100,
|
|
0b1111001111111111,
|
|
0b1111110000000000,
|
|
0b1111110000000011,
|
|
0b1111110000001100,
|
|
0b1111110000001111,
|
|
0b1111110000110000,
|
|
0b1111110000110011,
|
|
0b1111110000111100,
|
|
0b1111110000111111,
|
|
0b1111110011000000,
|
|
0b1111110011000011,
|
|
0b1111110011001100,
|
|
0b1111110011001111,
|
|
0b1111110011110000,
|
|
0b1111110011110011,
|
|
0b1111110011111100,
|
|
0b1111110011111111,
|
|
0b1111111100000000,
|
|
0b1111111100000011,
|
|
0b1111111100001100,
|
|
0b1111111100001111,
|
|
0b1111111100110000,
|
|
0b1111111100110011,
|
|
0b1111111100111100,
|
|
0b1111111100111111,
|
|
0b1111111111000000,
|
|
0b1111111111000011,
|
|
0b1111111111001100,
|
|
0b1111111111001111,
|
|
0b1111111111110000,
|
|
0b1111111111110011,
|
|
0b1111111111111100,
|
|
0b1111111111111111,
|
|
];
|