mirror of
https://github.com/isometimes/rpi4-osdev
synced 2024-11-25 19:50:40 +00:00
Added code for part5-framebuffer and part6-breakout, write-up todo
This commit is contained in:
parent
db57c87753
commit
2cf8a98743
24 changed files with 1830 additions and 0 deletions
19
part5-framebuffer/Makefile
Normal file
19
part5-framebuffer/Makefile
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
CFILES = $(wildcard *.c)
|
||||||
|
OFILES = $(CFILES:.c=.o)
|
||||||
|
GCCFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles
|
||||||
|
GCCPATH = ../../gcc-arm-9.2-2019.12-x86_64-aarch64-none-elf/bin
|
||||||
|
|
||||||
|
all: clean kernel8.img
|
||||||
|
|
||||||
|
boot.o: boot.S
|
||||||
|
$(GCCPATH)/aarch64-none-elf-gcc $(GCCFLAGS) -c boot.S -o boot.o
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(GCCPATH)/aarch64-none-elf-gcc $(GCCFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
kernel8.img: boot.o $(OFILES)
|
||||||
|
$(GCCPATH)/aarch64-none-elf-ld -nostdlib -nostartfiles boot.o $(OFILES) -T link.ld -o kernel8.elf
|
||||||
|
$(GCCPATH)/aarch64-none-elf-objcopy -O binary kernel8.elf kernel8.img
|
||||||
|
|
||||||
|
clean:
|
||||||
|
/bin/rm kernel8.elf *.o *.img > /dev/null 2> /dev/null || true
|
30
part5-framebuffer/boot.S
Normal file
30
part5-framebuffer/boot.S
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
.section ".text.boot" // Make sure the linker puts this at the start of the kernel image
|
||||||
|
|
||||||
|
.global _start // Execution starts here
|
||||||
|
|
||||||
|
_start:
|
||||||
|
// Check processor ID is zero (executing on main core), else hang
|
||||||
|
mrs x1, mpidr_el1
|
||||||
|
and x1, x1, #3
|
||||||
|
cbz x1, 2f
|
||||||
|
// We're not on the main core, so hang in an infinite wait loop
|
||||||
|
1: wfe
|
||||||
|
b 1b
|
||||||
|
2: // We're on the main core!
|
||||||
|
|
||||||
|
// Set stack to start below our code
|
||||||
|
ldr x1, =_start
|
||||||
|
mov sp, x1
|
||||||
|
|
||||||
|
// Clean the BSS section
|
||||||
|
ldr x1, =__bss_start // Start address
|
||||||
|
ldr w2, =__bss_size // Size of the section
|
||||||
|
3: cbz w2, 4f // Quit loop if zero
|
||||||
|
str xzr, [x1], #8
|
||||||
|
sub w2, w2, #1
|
||||||
|
cbnz w2, 3b // Loop if non-zero
|
||||||
|
|
||||||
|
// Jump to our main() routine in C (make sure it doesn't return)
|
||||||
|
4: bl main
|
||||||
|
// In case it does return, halt the master core too
|
||||||
|
b 1b
|
172
part5-framebuffer/fb.c
Normal file
172
part5-framebuffer/fb.c
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
#include "io.h"
|
||||||
|
#include "mb.h"
|
||||||
|
#include "terminal.h"
|
||||||
|
|
||||||
|
unsigned int width, height, pitch, isrgb;
|
||||||
|
unsigned char *fb;
|
||||||
|
|
||||||
|
// Refer to https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface in write-up!
|
||||||
|
void fb_init()
|
||||||
|
{
|
||||||
|
mbox[0] = 35*4; // Length of message in bytes
|
||||||
|
mbox[1] = MBOX_REQUEST;
|
||||||
|
|
||||||
|
mbox[2] = MBOX_TAG_SETPHYWH; // Tag identifier
|
||||||
|
mbox[3] = 8; // Value size in bytes
|
||||||
|
mbox[4] = 8; // Value size in bytes (again!)
|
||||||
|
mbox[5] = 1920; // Value(width)
|
||||||
|
mbox[6] = 1080; // Value(height)
|
||||||
|
|
||||||
|
mbox[7] = MBOX_TAG_SETVIRTWH;
|
||||||
|
mbox[8] = 8;
|
||||||
|
mbox[9] = 8;
|
||||||
|
mbox[10] = 1920;
|
||||||
|
mbox[11] = 1080;
|
||||||
|
|
||||||
|
mbox[12] = MBOX_TAG_SETVIRTOFF;
|
||||||
|
mbox[13] = 8;
|
||||||
|
mbox[14] = 8;
|
||||||
|
mbox[15] = 0; // Value(x)
|
||||||
|
mbox[16] = 0; // Value(y)
|
||||||
|
|
||||||
|
mbox[17] = MBOX_TAG_SETDEPTH;
|
||||||
|
mbox[18] = 4;
|
||||||
|
mbox[19] = 4;
|
||||||
|
mbox[20] = 32; // Bits per pixel
|
||||||
|
|
||||||
|
mbox[21] = MBOX_TAG_SETPXLORDR;
|
||||||
|
mbox[22] = 4;
|
||||||
|
mbox[23] = 4;
|
||||||
|
mbox[24] = 1; // RGB
|
||||||
|
|
||||||
|
mbox[25] = MBOX_TAG_GETFB;
|
||||||
|
mbox[26] = 8;
|
||||||
|
mbox[27] = 8;
|
||||||
|
mbox[28] = 4096; // FrameBufferInfo.pointer
|
||||||
|
mbox[29] = 0; // FrameBufferInfo.size
|
||||||
|
|
||||||
|
mbox[30] = MBOX_TAG_GETPITCH;
|
||||||
|
mbox[31] = 4;
|
||||||
|
mbox[32] = 4;
|
||||||
|
mbox[33] = 0; // Bytes per line
|
||||||
|
|
||||||
|
mbox[34] = MBOX_TAG_LAST;
|
||||||
|
|
||||||
|
// Check call is successful and we have a pointer with depth 32
|
||||||
|
if (mbox_call(MBOX_CH_PROP) && mbox[20] == 32 && mbox[28] != 0) {
|
||||||
|
mbox[28] &= 0x3FFFFFFF; // Convert GPU address to ARM address
|
||||||
|
width = mbox[10]; // Actual physical width
|
||||||
|
height = mbox[11]; // Actual physical height
|
||||||
|
pitch = mbox[33]; // Number of bytes per line
|
||||||
|
isrgb = mbox[24]; // Pixel order
|
||||||
|
fb = (unsigned char *)((long)mbox[28]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawPixel(int x, int y, unsigned char attr)
|
||||||
|
{
|
||||||
|
int offs = (y * pitch) + (x * 4);
|
||||||
|
*((unsigned int*)(fb + offs)) = vgapal[attr & 0x0f];
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawChar(unsigned char ch, int x, int y, unsigned char attr)
|
||||||
|
{
|
||||||
|
unsigned char *glyph = (unsigned char *)&font + (ch < FONT_NUMGLYPHS ? ch : 0) * FONT_BPG;
|
||||||
|
|
||||||
|
for (int i=1;i<=FONT_HEIGHT;i++) {
|
||||||
|
for (int j=0;j<FONT_WIDTH;j++) {
|
||||||
|
unsigned char mask = 1 << j;
|
||||||
|
unsigned char col = (*glyph & mask) ? attr & 0x0f : (attr & 0xf0) >> 4;
|
||||||
|
|
||||||
|
drawPixel(x+j, y+i, col);
|
||||||
|
}
|
||||||
|
glyph += FONT_BPL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawString(int x, int y, char *s, unsigned char attr)
|
||||||
|
{
|
||||||
|
while(*s) {
|
||||||
|
if (*s == '\r') {
|
||||||
|
x = 0;
|
||||||
|
} else if(*s == '\n') {
|
||||||
|
x = 0; y += FONT_HEIGHT;
|
||||||
|
} else {
|
||||||
|
drawChar(*s, x, y, attr);
|
||||||
|
x += FONT_WIDTH;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawRect(int x1, int y1, int x2, int y2, unsigned char attr, int fill)
|
||||||
|
{
|
||||||
|
int y=y1;
|
||||||
|
|
||||||
|
while (y <= y2) {
|
||||||
|
int x=x1;
|
||||||
|
while (x <= x2) {
|
||||||
|
if (fill || (x == x1 || x == x2) || (y == y1 || y == y2)) drawPixel(x, y, attr);
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawLine(int x1, int y1, int x2, int y2, unsigned char attr)
|
||||||
|
{
|
||||||
|
int dx, dy, p, x, y;
|
||||||
|
|
||||||
|
dx = x2-x1;
|
||||||
|
dy = y2-y1;
|
||||||
|
x = x1;
|
||||||
|
y = y1;
|
||||||
|
p = 2*dy-dx;
|
||||||
|
|
||||||
|
while (x<x2) {
|
||||||
|
if (p >= 0) {
|
||||||
|
drawPixel(x,y,attr);
|
||||||
|
y++;
|
||||||
|
p = p+2*dy-2*dx;
|
||||||
|
} else {
|
||||||
|
drawPixel(x,y,attr);
|
||||||
|
p = p+2*dy;
|
||||||
|
}
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawCircle(int x0, int y0, int radius, unsigned char attr, int fill)
|
||||||
|
{
|
||||||
|
int x = radius;
|
||||||
|
int y = 0;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
while (x >= y) {
|
||||||
|
if (fill) {
|
||||||
|
drawLine(x0 - y, y0 + x, x0 + y, y0 + x, attr);
|
||||||
|
drawLine(x0 - x, y0 + y, x0 + x, y0 + y, attr);
|
||||||
|
drawLine(x0 - x, y0 - y, x0 + x, y0 - y, attr);
|
||||||
|
drawLine(x0 - y, y0 - x, x0 + y, y0 - x, attr);
|
||||||
|
} else {
|
||||||
|
drawPixel(x0 - y, y0 + x, attr);
|
||||||
|
drawPixel(x0 + y, y0 + x, attr);
|
||||||
|
drawPixel(x0 - x, y0 + y, attr);
|
||||||
|
drawPixel(x0 + x, y0 + y, attr);
|
||||||
|
drawPixel(x0 - x, y0 - y, attr);
|
||||||
|
drawPixel(x0 + x, y0 - y, attr);
|
||||||
|
drawPixel(x0 - y, y0 - x, attr);
|
||||||
|
drawPixel(x0 + y, y0 - x, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err <= 0) {
|
||||||
|
y += 1;
|
||||||
|
err += 2*y + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err > 0) {
|
||||||
|
x -= 1;
|
||||||
|
err -= 2*x + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
part5-framebuffer/fb.h
Normal file
7
part5-framebuffer/fb.h
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
void fb_init();
|
||||||
|
void drawPixel(int x, int y, unsigned char attr);
|
||||||
|
void drawChar(unsigned char ch, int x, int y, unsigned char attr);
|
||||||
|
void drawString(int x, int y, char *s, unsigned char attr);
|
||||||
|
void drawRect(int x1, int y1, int x2, int y2, unsigned char attr, int fill);
|
||||||
|
void drawCircle(int x0, int y0, int radius, unsigned char attr, int fill);
|
||||||
|
void drawLine(int x1, int y1, int x2, int y2, unsigned char attr);
|
166
part5-framebuffer/io.c
Normal file
166
part5-framebuffer/io.c
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
// GPIO
|
||||||
|
|
||||||
|
enum {
|
||||||
|
GPFSEL0 = PERIPHERAL_BASE + 0x200000,
|
||||||
|
GPSET0 = PERIPHERAL_BASE + 0x20001C,
|
||||||
|
GPCLR0 = PERIPHERAL_BASE + 0x200028,
|
||||||
|
GPPUPPDN0 = PERIPHERAL_BASE + 0x2000E4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
GPIO_MAX_PIN = 53,
|
||||||
|
GPIO_FUNCTION_OUT = 1,
|
||||||
|
GPIO_FUNCTION_ALT5 = 2,
|
||||||
|
GPIO_FUNCTION_ALT3 = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
Pull_None = 0,
|
||||||
|
Pull_Down = 1, // Are down and up the right way around?
|
||||||
|
Pull_Up = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
void mmio_write(long reg, unsigned int val) { *(volatile unsigned int *)reg = val; }
|
||||||
|
unsigned int mmio_read(long reg) { return *(volatile unsigned int *)reg; }
|
||||||
|
|
||||||
|
unsigned int gpio_call(unsigned int pin_number, unsigned int value, unsigned int base, unsigned int field_size, unsigned int field_max) {
|
||||||
|
unsigned int field_mask = (1 << field_size) - 1;
|
||||||
|
|
||||||
|
if (pin_number > field_max) return 0;
|
||||||
|
if (value > field_mask) return 0;
|
||||||
|
|
||||||
|
unsigned int num_fields = 32 / field_size;
|
||||||
|
unsigned int reg = base + ((pin_number / num_fields) * 4);
|
||||||
|
unsigned int shift = (pin_number % num_fields) * field_size;
|
||||||
|
|
||||||
|
unsigned int curval = mmio_read(reg);
|
||||||
|
curval &= ~(field_mask << shift);
|
||||||
|
curval |= value << shift;
|
||||||
|
mmio_write(reg, curval);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int gpio_set (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPSET0, 1, GPIO_MAX_PIN); }
|
||||||
|
unsigned int gpio_clear (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPCLR0, 1, GPIO_MAX_PIN); }
|
||||||
|
unsigned int gpio_pull (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPPUPPDN0, 2, GPIO_MAX_PIN); }
|
||||||
|
unsigned int gpio_function(unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPFSEL0, 3, GPIO_MAX_PIN); }
|
||||||
|
|
||||||
|
void gpio_useAsAlt3(unsigned int pin_number) {
|
||||||
|
gpio_pull(pin_number, Pull_None);
|
||||||
|
gpio_function(pin_number, GPIO_FUNCTION_ALT3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_useAsAlt5(unsigned int pin_number) {
|
||||||
|
gpio_pull(pin_number, Pull_None);
|
||||||
|
gpio_function(pin_number, GPIO_FUNCTION_ALT5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_initOutputPinWithPullNone(unsigned int pin_number) {
|
||||||
|
gpio_pull(pin_number, Pull_None);
|
||||||
|
gpio_function(pin_number, GPIO_FUNCTION_OUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_setPinOutputBool(unsigned int pin_number, unsigned int onOrOff) {
|
||||||
|
if (onOrOff) {
|
||||||
|
gpio_set(pin_number, 1);
|
||||||
|
} else {
|
||||||
|
gpio_clear(pin_number, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UART
|
||||||
|
|
||||||
|
enum {
|
||||||
|
AUX_BASE = PERIPHERAL_BASE + 0x215000,
|
||||||
|
AUX_IRQ = AUX_BASE,
|
||||||
|
AUX_ENABLES = AUX_BASE + 4,
|
||||||
|
AUX_MU_IO_REG = AUX_BASE + 64,
|
||||||
|
AUX_MU_IER_REG = AUX_BASE + 68,
|
||||||
|
AUX_MU_IIR_REG = AUX_BASE + 72,
|
||||||
|
AUX_MU_LCR_REG = AUX_BASE + 76,
|
||||||
|
AUX_MU_MCR_REG = AUX_BASE + 80,
|
||||||
|
AUX_MU_LSR_REG = AUX_BASE + 84,
|
||||||
|
AUX_MU_MSR_REG = AUX_BASE + 88,
|
||||||
|
AUX_MU_SCRATCH = AUX_BASE + 92,
|
||||||
|
AUX_MU_CNTL_REG = AUX_BASE + 96,
|
||||||
|
AUX_MU_STAT_REG = AUX_BASE + 100,
|
||||||
|
AUX_MU_BAUD_REG = AUX_BASE + 104,
|
||||||
|
AUX_UART_CLOCK = 500000000,
|
||||||
|
UART_MAX_QUEUE = 16 * 1024
|
||||||
|
};
|
||||||
|
|
||||||
|
#define AUX_MU_BAUD(baud) ((AUX_UART_CLOCK/(baud*8))-1)
|
||||||
|
|
||||||
|
unsigned char uart_output_queue[UART_MAX_QUEUE];
|
||||||
|
unsigned int uart_output_queue_write = 0;
|
||||||
|
unsigned int uart_output_queue_read = 0;
|
||||||
|
|
||||||
|
void uart_init() {
|
||||||
|
mmio_write(AUX_ENABLES, 1); //enable UART1
|
||||||
|
mmio_write(AUX_MU_IER_REG, 0);
|
||||||
|
mmio_write(AUX_MU_CNTL_REG, 0);
|
||||||
|
mmio_write(AUX_MU_LCR_REG, 3); //8 bits
|
||||||
|
mmio_write(AUX_MU_MCR_REG, 0);
|
||||||
|
mmio_write(AUX_MU_IER_REG, 0);
|
||||||
|
mmio_write(AUX_MU_IIR_REG, 0xC6); //disable interrupts
|
||||||
|
mmio_write(AUX_MU_BAUD_REG, AUX_MU_BAUD(115200));
|
||||||
|
gpio_useAsAlt5(14);
|
||||||
|
gpio_useAsAlt5(15);
|
||||||
|
mmio_write(AUX_MU_CNTL_REG, 3); //enable RX/TX
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int uart_isOutputQueueEmpty() {
|
||||||
|
return uart_output_queue_read == uart_output_queue_write;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int uart_isReadByteReady() { return mmio_read(AUX_MU_LSR_REG) & 0x01; }
|
||||||
|
unsigned int uart_isWriteByteReady() { return mmio_read(AUX_MU_LSR_REG) & 0x20; }
|
||||||
|
|
||||||
|
unsigned char uart_readByte() {
|
||||||
|
while (!uart_isReadByteReady());
|
||||||
|
return (unsigned char)mmio_read(AUX_MU_IO_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_writeByteBlockingActual(unsigned char ch) {
|
||||||
|
while (!uart_isWriteByteReady());
|
||||||
|
mmio_write(AUX_MU_IO_REG, (unsigned int)ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_loadOutputFifo() {
|
||||||
|
while (!uart_isOutputQueueEmpty() && uart_isWriteByteReady()) {
|
||||||
|
uart_writeByteBlockingActual(uart_output_queue[uart_output_queue_read]);
|
||||||
|
uart_output_queue_read = (uart_output_queue_read + 1) & (UART_MAX_QUEUE - 1); // Don't overrun
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_writeByteBlocking(unsigned char ch) {
|
||||||
|
unsigned int next = (uart_output_queue_write + 1) & (UART_MAX_QUEUE - 1); // Don't overrun
|
||||||
|
|
||||||
|
while (next == uart_output_queue_read) uart_loadOutputFifo();
|
||||||
|
|
||||||
|
uart_output_queue[uart_output_queue_write] = ch;
|
||||||
|
uart_output_queue_write = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_writeText(char *buffer) {
|
||||||
|
while (*buffer) {
|
||||||
|
if (*buffer == '\n') uart_writeByteBlocking('\r');
|
||||||
|
uart_writeByteBlocking(*buffer++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_drainOutputQueue() {
|
||||||
|
while (!uart_isOutputQueueEmpty()) uart_loadOutputFifo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_update() {
|
||||||
|
uart_loadOutputFifo();
|
||||||
|
|
||||||
|
if (uart_isReadByteReady()) {
|
||||||
|
unsigned char ch = uart_readByte();
|
||||||
|
if (ch == '\r') uart_writeText("\n"); else uart_writeByteBlocking(ch);
|
||||||
|
}
|
||||||
|
}
|
11
part5-framebuffer/io.h
Normal file
11
part5-framebuffer/io.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#define PERIPHERAL_BASE 0xFE000000
|
||||||
|
|
||||||
|
void uart_init();
|
||||||
|
void uart_writeText(char *buffer);
|
||||||
|
void uart_loadOutputFifo();
|
||||||
|
unsigned char uart_readByte();
|
||||||
|
unsigned int uart_isReadByteReady();
|
||||||
|
void uart_writeByteBlocking(unsigned char ch);
|
||||||
|
void uart_update();
|
||||||
|
void mmio_write(long reg, unsigned int val);
|
||||||
|
unsigned int mmio_read(long reg);
|
23
part5-framebuffer/kernel.c
Normal file
23
part5-framebuffer/kernel.c
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#include "io.h"
|
||||||
|
#include "fb.h"
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
uart_init();
|
||||||
|
fb_init();
|
||||||
|
|
||||||
|
drawRect(150,150,400,400,0x03,0);
|
||||||
|
drawRect(300,300,350,350,0x02,1);
|
||||||
|
|
||||||
|
drawCircle(960,540,250,0x0e,0);
|
||||||
|
drawCircle(960,540,50,0x04,1);
|
||||||
|
|
||||||
|
drawPixel(250,250,0x0e);
|
||||||
|
|
||||||
|
drawChar('O',500,500,0x05);
|
||||||
|
drawString(100,100,"Hello world!",0x0f);
|
||||||
|
|
||||||
|
drawLine(100,500,350,700,0x0c);
|
||||||
|
|
||||||
|
while (1);
|
||||||
|
}
|
19
part5-framebuffer/link.ld
Normal file
19
part5-framebuffer/link.ld
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x80000; /* Kernel load address for AArch64 */
|
||||||
|
.text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }
|
||||||
|
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }
|
||||||
|
PROVIDE(_data = .);
|
||||||
|
.data : { *(.data .data.* .gnu.linkonce.d*) }
|
||||||
|
.bss (NOLOAD) : {
|
||||||
|
. = ALIGN(16);
|
||||||
|
__bss_start = .;
|
||||||
|
*(.bss .bss.*)
|
||||||
|
*(COMMON)
|
||||||
|
__bss_end = .;
|
||||||
|
}
|
||||||
|
_end = .;
|
||||||
|
|
||||||
|
/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
|
||||||
|
}
|
||||||
|
__bss_size = (__bss_end - __bss_start)>>3;
|
39
part5-framebuffer/mb.c
Normal file
39
part5-framebuffer/mb.c
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
// The buffer must be 16-byte aligned as only the upper 28 bits of the address can be passed via the mailbox
|
||||||
|
volatile unsigned int __attribute__((aligned(16))) mbox[36];
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VIDEOCORE_MBOX = (PERIPHERAL_BASE + 0x0000B880),
|
||||||
|
MBOX_READ = (VIDEOCORE_MBOX + 0x0),
|
||||||
|
MBOX_POLL = (VIDEOCORE_MBOX + 0x10),
|
||||||
|
MBOX_SENDER = (VIDEOCORE_MBOX + 0x14),
|
||||||
|
MBOX_STATUS = (VIDEOCORE_MBOX + 0x18),
|
||||||
|
MBOX_CONFIG = (VIDEOCORE_MBOX + 0x1C),
|
||||||
|
MBOX_WRITE = (VIDEOCORE_MBOX + 0x20),
|
||||||
|
MBOX_RESPONSE = 0x80000000,
|
||||||
|
MBOX_FULL = 0x80000000,
|
||||||
|
MBOX_EMPTY = 0x40000000
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int mbox_call(unsigned char ch)
|
||||||
|
{
|
||||||
|
// 28-bit address (MSB) and 4-bit value (LSB)
|
||||||
|
unsigned int r = ((unsigned int)((long) &mbox) &~ 0xF) | (ch & 0xF);
|
||||||
|
|
||||||
|
// Wait until we can write
|
||||||
|
while (mmio_read(MBOX_STATUS) & MBOX_FULL);
|
||||||
|
|
||||||
|
/* write the address of our message to the mailbox with channel identifier */
|
||||||
|
mmio_write(MBOX_WRITE, r);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// Is there a reply?
|
||||||
|
while (mmio_read(MBOX_STATUS) & MBOX_EMPTY);
|
||||||
|
|
||||||
|
// Is it a reply to our message?
|
||||||
|
if (r == mmio_read(MBOX_READ)) return mbox[1]==MBOX_RESPONSE; // Is it successful?
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
34
part5-framebuffer/mb.h
Normal file
34
part5-framebuffer/mb.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
extern volatile unsigned int mbox[36];
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MBOX_REQUEST = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MBOX_CH_POWER = 0,
|
||||||
|
MBOX_CH_FB = 1,
|
||||||
|
MBOX_CH_VUART = 2,
|
||||||
|
MBOX_CH_VCHIQ = 3,
|
||||||
|
MBOX_CH_LEDS = 4,
|
||||||
|
MBOX_CH_BTNS = 5,
|
||||||
|
MBOX_CH_TOUCH = 6,
|
||||||
|
MBOX_CH_COUNT = 7,
|
||||||
|
MBOX_CH_PROP = 8 // Request from ARM for response by VideoCore
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MBOX_TAG_SETPOWER = 0x28001,
|
||||||
|
MBOX_TAG_SETCLKRATE = 0x38002,
|
||||||
|
|
||||||
|
MBOX_TAG_SETPHYWH = 0x48003,
|
||||||
|
MBOX_TAG_SETVIRTWH = 0x48004,
|
||||||
|
MBOX_TAG_SETVIRTOFF = 0x48009,
|
||||||
|
MBOX_TAG_SETDEPTH = 0x48005,
|
||||||
|
MBOX_TAG_SETPXLORDR = 0x48006,
|
||||||
|
MBOX_TAG_GETFB = 0x40001,
|
||||||
|
MBOX_TAG_GETPITCH = 0x40008,
|
||||||
|
|
||||||
|
MBOX_TAG_LAST = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int mbox_call(unsigned char ch);
|
253
part5-framebuffer/terminal.h
Normal file
253
part5-framebuffer/terminal.h
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
unsigned int vgapal[] = {
|
||||||
|
0x000000,
|
||||||
|
0x0000AA,
|
||||||
|
0x00AA00,
|
||||||
|
0x00AAAA,
|
||||||
|
0xAA0000,
|
||||||
|
0xAA00AA,
|
||||||
|
0xAA5500,
|
||||||
|
0xAAAAAA,
|
||||||
|
0x555555,
|
||||||
|
0x5555FF,
|
||||||
|
0x55FF55,
|
||||||
|
0x55FFFF,
|
||||||
|
0xFF5555,
|
||||||
|
0xFF55FF,
|
||||||
|
0xFFFF55,
|
||||||
|
0xFFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FONT_WIDTH = 8,
|
||||||
|
FONT_HEIGHT = 8,
|
||||||
|
FONT_BPG = 8, // Bytes per glyph
|
||||||
|
FONT_BPL = 1, // Bytes per line
|
||||||
|
FONT_NUMGLYPHS = 224
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned char font[FONT_NUMGLYPHS][FONT_BPG] = {
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space)
|
||||||
|
{ 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!)
|
||||||
|
{ 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (")
|
||||||
|
{ 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#)
|
||||||
|
{ 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($)
|
||||||
|
{ 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%)
|
||||||
|
{ 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&)
|
||||||
|
{ 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (')
|
||||||
|
{ 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (()
|
||||||
|
{ 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ())
|
||||||
|
{ 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*)
|
||||||
|
{ 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.)
|
||||||
|
{ 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/)
|
||||||
|
{ 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0)
|
||||||
|
{ 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1)
|
||||||
|
{ 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2)
|
||||||
|
{ 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3)
|
||||||
|
{ 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4)
|
||||||
|
{ 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5)
|
||||||
|
{ 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6)
|
||||||
|
{ 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7)
|
||||||
|
{ 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8)
|
||||||
|
{ 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9)
|
||||||
|
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:)
|
||||||
|
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (;)
|
||||||
|
{ 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<)
|
||||||
|
{ 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=)
|
||||||
|
{ 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>)
|
||||||
|
{ 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?)
|
||||||
|
{ 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@)
|
||||||
|
{ 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A)
|
||||||
|
{ 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B)
|
||||||
|
{ 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C)
|
||||||
|
{ 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D)
|
||||||
|
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E)
|
||||||
|
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F)
|
||||||
|
{ 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G)
|
||||||
|
{ 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H)
|
||||||
|
{ 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I)
|
||||||
|
{ 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J)
|
||||||
|
{ 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K)
|
||||||
|
{ 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L)
|
||||||
|
{ 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M)
|
||||||
|
{ 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N)
|
||||||
|
{ 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O)
|
||||||
|
{ 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P)
|
||||||
|
{ 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q)
|
||||||
|
{ 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R)
|
||||||
|
{ 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S)
|
||||||
|
{ 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T)
|
||||||
|
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U)
|
||||||
|
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V)
|
||||||
|
{ 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W)
|
||||||
|
{ 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X)
|
||||||
|
{ 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y)
|
||||||
|
{ 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z)
|
||||||
|
{ 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([)
|
||||||
|
{ 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\)
|
||||||
|
{ 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (])
|
||||||
|
{ 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_)
|
||||||
|
{ 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`)
|
||||||
|
{ 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a)
|
||||||
|
{ 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b)
|
||||||
|
{ 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c)
|
||||||
|
{ 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d)
|
||||||
|
{ 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e)
|
||||||
|
{ 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f)
|
||||||
|
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g)
|
||||||
|
{ 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h)
|
||||||
|
{ 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i)
|
||||||
|
{ 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j)
|
||||||
|
{ 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k)
|
||||||
|
{ 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l)
|
||||||
|
{ 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m)
|
||||||
|
{ 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n)
|
||||||
|
{ 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o)
|
||||||
|
{ 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p)
|
||||||
|
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q)
|
||||||
|
{ 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r)
|
||||||
|
{ 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s)
|
||||||
|
{ 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t)
|
||||||
|
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u)
|
||||||
|
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v)
|
||||||
|
{ 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w)
|
||||||
|
{ 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x)
|
||||||
|
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y)
|
||||||
|
{ 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z)
|
||||||
|
{ 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({)
|
||||||
|
{ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|)
|
||||||
|
{ 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (})
|
||||||
|
{ 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007F
|
||||||
|
{ 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x18, 0x30, 0x1E}, // U+00C7 (C cedille)
|
||||||
|
{ 0x00, 0x33, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00FC (u umlaut)
|
||||||
|
{ 0x38, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // U+00E9 (e aigu)
|
||||||
|
{ 0x7E, 0xC3, 0x3C, 0x60, 0x7C, 0x66, 0xFC, 0x00}, // U+00E2 (a circumflex)
|
||||||
|
{ 0x33, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E4 (a umlaut)
|
||||||
|
{ 0x07, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E0 (a grave)
|
||||||
|
{ 0x0C, 0x0C, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E5 (a ring)
|
||||||
|
{ 0x00, 0x00, 0x1E, 0x03, 0x03, 0x1E, 0x30, 0x1C}, // U+00E7 (c cedille)
|
||||||
|
{ 0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00}, // U+00EA (e circumflex)
|
||||||
|
{ 0x33, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // U+00EB (e umlaut)
|
||||||
|
{ 0x07, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // U+00E8 (e grave)
|
||||||
|
{ 0x33, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00EF (i umlaut)
|
||||||
|
{ 0x3E, 0x63, 0x1C, 0x18, 0x18, 0x18, 0x3C, 0x00}, // U+00EE (i circumflex)
|
||||||
|
{ 0x07, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00EC (i grave)
|
||||||
|
{ 0x63, 0x1C, 0x36, 0x63, 0x7F, 0x63, 0x63, 0x00}, // U+00C4 (A umlaut)
|
||||||
|
{ 0x0C, 0x0C, 0x00, 0x1E, 0x33, 0x3F, 0x33, 0x00}, // U+00C5 (A ring)
|
||||||
|
{ 0x07, 0x00, 0x3F, 0x06, 0x1E, 0x06, 0x3F, 0x00}, // U+00C8 (E grave)
|
||||||
|
{ 0x00, 0x00, 0xFE, 0x30, 0xFE, 0x33, 0xFE, 0x00}, // U+00E6 (ae)
|
||||||
|
{ 0x7C, 0x36, 0x33, 0x7F, 0x33, 0x33, 0x73, 0x00}, // U+00C6 (AE)
|
||||||
|
{ 0x1E, 0x33, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F4 (o circumflex)
|
||||||
|
{ 0x00, 0x33, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F6 (o umlaut)
|
||||||
|
{ 0x00, 0x07, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F2 (o grave)
|
||||||
|
{ 0x1E, 0x33, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00FB (u circumflex)
|
||||||
|
{ 0x00, 0x07, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00F9 (u grave)
|
||||||
|
{ 0x00, 0x33, 0x00, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+00FF (y umlaut)
|
||||||
|
{ 0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00}, // U+00D6 (O umlaut)
|
||||||
|
{ 0x33, 0x00, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+00DC (U umlaut)
|
||||||
|
{ 0x18, 0x18, 0x7E, 0x03, 0x03, 0x7E, 0x18, 0x18}, // U+00A2 (dollarcents)
|
||||||
|
{ 0x1C, 0x36, 0x26, 0x0F, 0x06, 0x67, 0x3F, 0x00}, // U+00A3 (pound sterling)
|
||||||
|
{ 0x33, 0x33, 0x1E, 0x3F, 0x0C, 0x3F, 0x0C, 0x0C}, // U+00A5 (yen)
|
||||||
|
{ 0x7C, 0xC6, 0x1C, 0x36, 0x36, 0x1C, 0x33, 0x1E}, // U+00A7 (paragraph)
|
||||||
|
{ 0x70, 0xD8, 0x18, 0x3C, 0x18, 0x18, 0x1B, 0x0E}, // U+0192 (dutch florijn)
|
||||||
|
{ 0x38, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E1 (a aigu)
|
||||||
|
{ 0x1C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00ED (i augu)
|
||||||
|
{ 0x00, 0x38, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F3 (o aigu)
|
||||||
|
{ 0x00, 0x38, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00FA (u aigu)
|
||||||
|
{ 0x00, 0x1F, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x00}, // U+00F1 (n ~)
|
||||||
|
{ 0x3F, 0x00, 0x33, 0x37, 0x3F, 0x3B, 0x33, 0x00}, // U+00D1 (N ~)
|
||||||
|
{ 0x3C, 0x36, 0x36, 0x7C, 0x00, 0x00, 0x00, 0x00}, // U+00AA (superscript a)
|
||||||
|
{ 0x1C, 0x36, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00}, // U+00BA (superscript 0)
|
||||||
|
{ 0x0C, 0x00, 0x0C, 0x06, 0x03, 0x33, 0x1E, 0x00}, // U+00BF (inverted ?)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x3F, 0x03, 0x03, 0x00, 0x00}, // U+2310 (gun pointing right)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x3F, 0x30, 0x30, 0x00, 0x00}, // U+00AC (gun pointing left)
|
||||||
|
{ 0xC3, 0x63, 0x33, 0x7B, 0xCC, 0x66, 0x33, 0xF0}, // U+00BD (1/2)
|
||||||
|
{ 0xC3, 0x63, 0x33, 0xBD, 0xEC, 0xF6, 0xF3, 0x03}, // U+00BC (1/4)
|
||||||
|
{ 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00}, // U+00A1 (inverted !)
|
||||||
|
{ 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00}, // U+00AB (<<)
|
||||||
|
{ 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00}, // U+00BB (>>)
|
||||||
|
{ 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00}, // U+2591 (25% solid)
|
||||||
|
{ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA}, // U+2592 (50% solid)
|
||||||
|
{ 0xFF, 0xAA, 0xFF, 0x55, 0xFF, 0xAA, 0xFF, 0x55}, // U+2593 (75% solid)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, // U+2502 (thin vertical)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08}, // U+2524 (down L, left L, up L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x0F, 0x08, 0x0F, 0x08, 0x08}, // U+2561 (up L, down L, left D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x14, 0x17, 0x14, 0x14, 0x14}, // U+2562 (up D, down D, left L)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x1F, 0x14, 0x14, 0x14}, // U+2556 (down D, left L)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x0F, 0x08, 0x0F, 0x08, 0x08}, // U+2555 (down L, left D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x17, 0x10, 0x17, 0x14, 0x14}, // U+2563 (up D, down D, left D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14}, // U+2551 (double vertical)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x1F, 0x10, 0x17, 0x14, 0x14}, // U+2557 (down D, left D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x17, 0x10, 0x1F, 0x00, 0x00}, // U+255D (up D, left D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x14, 0x1F, 0x00, 0x00, 0x00}, // U+255C (up D, left L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x0F, 0x08, 0x0F, 0x00, 0x00}, // U+255B (up L, left D)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x08, 0x08}, // U+2510 (down L, left L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x08, 0xf8, 0x00, 0x00, 0x00}, // U+2514 (up L, right L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x08, 0xff, 0x00, 0x00, 0x00}, // U+2534 (up L, right L, left L)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0xff, 0x08, 0x08, 0x08}, // U+252C (down L, right L, left L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x08, 0xf8, 0x08, 0x08, 0x08}, // U+251C (down L, right L, up L)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00}, // U+2500 (thin horizontal)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08}, // U+253C (up L, right L, left L, down L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0xF8, 0x08, 0xF8, 0x08, 0x08}, // U+255E (up L, down L, right D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x14, 0xF4, 0x14, 0x14, 0x14}, // U+255F (up D, down D, right L)
|
||||||
|
{ 0x14, 0x14, 0x14, 0xF4, 0x04, 0xFC, 0x00, 0x00}, // U+255A (up D, right D)
|
||||||
|
{ 0x00, 0x00, 0x00, 0xFC, 0x04, 0xF4, 0x14, 0x14}, // U+2554 (down D, right D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0xF7, 0x00, 0xFF, 0x00, 0x00}, // U+2569 (left D, right D, up D)
|
||||||
|
{ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x14, 0x14}, // U+2566 (left D, right D, down D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0xF4, 0x04, 0xF4, 0x14, 0x14}, // U+2560 (up D, down D, right D)
|
||||||
|
{ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00}, // U+2550 (double horizontal)
|
||||||
|
{ 0x14, 0x14, 0x14, 0xF7, 0x00, 0xF7, 0x14, 0x14}, // U+256C (left D, right D, down D, up D)
|
||||||
|
{ 0x08, 0x08, 0x08, 0xFF, 0x00, 0xFF, 0x00, 0x00}, // U+2567 (left D, right D, up L)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x14, 0xFF, 0x00, 0x00, 0x00}, // U+2568 (left L, right L, up D)
|
||||||
|
{ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x08, 0x08}, // U+2564 (left D, right D, down L)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0xFF, 0x14, 0x14, 0x14}, // U+2565 (left L, right L, down D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x14, 0xFC, 0x00, 0x00, 0x00}, // U+2559 (up D, right L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0xF8, 0x08, 0xF8, 0x00, 0x00}, // U+2558 (up L, right D)
|
||||||
|
{ 0x00, 0x00, 0x00, 0xF8, 0x08, 0xF8, 0x08, 0x08}, // U+2552 (down L, right D)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0xFC, 0x14, 0x14, 0x14}, // U+2553 (down D, right L)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x14, 0xFF, 0x14, 0x14, 0x14}, // U+256B (left L, right L, down D, up D)
|
||||||
|
{ 0x08, 0x08, 0x08, 0xFF, 0x08, 0xFF, 0x08, 0x08}, // U+256A (left D, right D, down L, up L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x08, 0x0f, 0x00, 0x00, 0x00}, // U+2518 (up L, left L)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0xf8, 0x08, 0x08, 0x08}, // U+250C (down L, right L)
|
||||||
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // U+2588 (solid)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}, // U+2584 (bottom half)
|
||||||
|
{ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F}, // U+258C (left half)
|
||||||
|
{ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0}, // U+2590 (right half)
|
||||||
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, // U+2580 (top half)
|
||||||
|
};
|
19
part6-breakout/Makefile
Normal file
19
part6-breakout/Makefile
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
CFILES = $(wildcard *.c)
|
||||||
|
OFILES = $(CFILES:.c=.o)
|
||||||
|
GCCFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles
|
||||||
|
GCCPATH = ../../gcc-arm-9.2-2019.12-x86_64-aarch64-none-elf/bin
|
||||||
|
|
||||||
|
all: clean kernel8.img
|
||||||
|
|
||||||
|
boot.o: boot.S
|
||||||
|
$(GCCPATH)/aarch64-none-elf-gcc $(GCCFLAGS) -c boot.S -o boot.o
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(GCCPATH)/aarch64-none-elf-gcc $(GCCFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
kernel8.img: boot.o $(OFILES)
|
||||||
|
$(GCCPATH)/aarch64-none-elf-ld -nostdlib -nostartfiles boot.o $(OFILES) -T link.ld -o kernel8.elf
|
||||||
|
$(GCCPATH)/aarch64-none-elf-objcopy -O binary kernel8.elf kernel8.img
|
||||||
|
|
||||||
|
clean:
|
||||||
|
/bin/rm kernel8.elf *.o *.img > /dev/null 2> /dev/null || true
|
30
part6-breakout/boot.S
Normal file
30
part6-breakout/boot.S
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
.section ".text.boot" // Make sure the linker puts this at the start of the kernel image
|
||||||
|
|
||||||
|
.global _start // Execution starts here
|
||||||
|
|
||||||
|
_start:
|
||||||
|
// Check processor ID is zero (executing on main core), else hang
|
||||||
|
mrs x1, mpidr_el1
|
||||||
|
and x1, x1, #3
|
||||||
|
cbz x1, 2f
|
||||||
|
// We're not on the main core, so hang in an infinite wait loop
|
||||||
|
1: wfe
|
||||||
|
b 1b
|
||||||
|
2: // We're on the main core!
|
||||||
|
|
||||||
|
// Set stack to start below our code
|
||||||
|
ldr x1, =_start
|
||||||
|
mov sp, x1
|
||||||
|
|
||||||
|
// Clean the BSS section
|
||||||
|
ldr x1, =__bss_start // Start address
|
||||||
|
ldr w2, =__bss_size // Size of the section
|
||||||
|
3: cbz w2, 4f // Quit loop if zero
|
||||||
|
str xzr, [x1], #8
|
||||||
|
sub w2, w2, #1
|
||||||
|
cbnz w2, 3b // Loop if non-zero
|
||||||
|
|
||||||
|
// Jump to our main() routine in C (make sure it doesn't return)
|
||||||
|
4: bl main
|
||||||
|
// In case it does return, halt the master core too
|
||||||
|
b 1b
|
252
part6-breakout/breakout.c
Normal file
252
part6-breakout/breakout.c
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
#include "fb.h"
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
// The screen
|
||||||
|
#define WIDTH 1920
|
||||||
|
#define HEIGHT 1080
|
||||||
|
#define MARGIN 75
|
||||||
|
#define VIRTWIDTH (WIDTH-(2*MARGIN))
|
||||||
|
#define FONT_BPG 8
|
||||||
|
|
||||||
|
// For the bricks
|
||||||
|
#define ROWS 5
|
||||||
|
#define COLS 10
|
||||||
|
unsigned int bricks = ROWS * COLS;
|
||||||
|
|
||||||
|
// Gameplay
|
||||||
|
#define NUM_LIVES 3
|
||||||
|
|
||||||
|
// OBJECT TRACKING
|
||||||
|
|
||||||
|
struct Object
|
||||||
|
{
|
||||||
|
unsigned int type;
|
||||||
|
unsigned int x;
|
||||||
|
unsigned int y;
|
||||||
|
unsigned int width;
|
||||||
|
unsigned int height;
|
||||||
|
unsigned char alive;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OBJ_NONE = 0,
|
||||||
|
OBJ_BRICK = 1,
|
||||||
|
OBJ_PADDLE = 2,
|
||||||
|
OBJ_BALL = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int numobjs = 0;
|
||||||
|
struct Object objects[(ROWS * COLS) + (2 * NUM_LIVES)];
|
||||||
|
struct Object *ball;
|
||||||
|
struct Object *paddle;
|
||||||
|
|
||||||
|
void removeObject(struct Object *object)
|
||||||
|
{
|
||||||
|
drawRect(object->x, object->y, object->x + object->width, object->y + object->height, 0, 1);
|
||||||
|
object->alive = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void moveObject(struct Object *object, int xoff, int yoff)
|
||||||
|
{
|
||||||
|
moveRect(object->x, object->y, object->width, object->height, xoff, yoff, 0x00);
|
||||||
|
object->x = object->x + xoff;
|
||||||
|
object->y = object->y + yoff;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Object *objectAt(unsigned int x, unsigned int y)
|
||||||
|
{
|
||||||
|
for (int i=0; i<numobjs;i++) {
|
||||||
|
if (x >= objects[i].x && x <= objects[i].x + objects[i].width) {
|
||||||
|
if (y >= objects[i].y && y <= objects[i].y + objects[i].height) {
|
||||||
|
if (&objects[i] != ball && objects[i].alive == 1) {
|
||||||
|
return &objects[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Object *detectCollision(int xoff, int yoff)
|
||||||
|
{
|
||||||
|
struct Object *collision;
|
||||||
|
|
||||||
|
unsigned int x = ball->x + xoff;
|
||||||
|
unsigned int y = ball->y + yoff;
|
||||||
|
|
||||||
|
collision = objectAt(x,y);
|
||||||
|
if (collision) return collision;
|
||||||
|
|
||||||
|
collision = objectAt(x + ball->width, y);
|
||||||
|
if (collision) return collision;
|
||||||
|
|
||||||
|
collision = objectAt(x, y + ball->height);
|
||||||
|
if (collision) return collision;
|
||||||
|
|
||||||
|
collision = objectAt(x + ball->width, y + ball->height);
|
||||||
|
if (collision) return collision;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// KEY HANDLER
|
||||||
|
|
||||||
|
unsigned char getUart()
|
||||||
|
{
|
||||||
|
unsigned char ch = 0;
|
||||||
|
|
||||||
|
if (uart_isReadByteReady()) ch = uart_readByte();
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OBJECT INITIALISERS
|
||||||
|
|
||||||
|
void initBricks()
|
||||||
|
{
|
||||||
|
int brickwidth = 32;
|
||||||
|
int brickheight = 8;
|
||||||
|
int brickspacer = 20;
|
||||||
|
int brickcols[5] = { 0x01, 0x02, 0x0E, 0x04, 0x06 };
|
||||||
|
|
||||||
|
int ybrick = MARGIN + brickheight;
|
||||||
|
|
||||||
|
for (int i=0; i<ROWS; i++) {
|
||||||
|
int xbrick = MARGIN + (VIRTWIDTH/COLS/2) - (brickwidth/2);
|
||||||
|
|
||||||
|
for (int j = 0; j<COLS; j++) {
|
||||||
|
drawRect(xbrick, ybrick, xbrick+brickwidth, ybrick+brickheight, brickcols[i], 1);
|
||||||
|
|
||||||
|
objects[numobjs].type = OBJ_BRICK;
|
||||||
|
objects[numobjs].x = xbrick;
|
||||||
|
objects[numobjs].y = ybrick;
|
||||||
|
objects[numobjs].width = brickwidth;
|
||||||
|
objects[numobjs].height = brickheight;
|
||||||
|
objects[numobjs].alive = 1;
|
||||||
|
numobjs++;
|
||||||
|
|
||||||
|
xbrick += (VIRTWIDTH/COLS);
|
||||||
|
}
|
||||||
|
ybrick = ybrick + brickspacer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initBall()
|
||||||
|
{
|
||||||
|
int ballradius = 15;
|
||||||
|
|
||||||
|
drawCircle(WIDTH/2, HEIGHT/2, ballradius, 0x05, 1);
|
||||||
|
|
||||||
|
objects[numobjs].type = OBJ_BALL;
|
||||||
|
objects[numobjs].x = (WIDTH/2) - ballradius;
|
||||||
|
objects[numobjs].y = (HEIGHT/2) - ballradius;
|
||||||
|
objects[numobjs].width = ballradius * 2;
|
||||||
|
objects[numobjs].height = ballradius * 2;
|
||||||
|
objects[numobjs].alive = 1;
|
||||||
|
ball = &objects[numobjs];
|
||||||
|
numobjs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initPaddle()
|
||||||
|
{
|
||||||
|
int paddlewidth = 80;
|
||||||
|
int paddleheight = 20;
|
||||||
|
|
||||||
|
drawRect((WIDTH-paddlewidth)/2, (HEIGHT-MARGIN-paddleheight), (WIDTH-paddlewidth)/2 + paddlewidth, (HEIGHT-MARGIN), 0x01, 1);
|
||||||
|
|
||||||
|
objects[numobjs].type = OBJ_PADDLE;
|
||||||
|
objects[numobjs].x = (WIDTH-paddlewidth)/2;
|
||||||
|
objects[numobjs].y = (HEIGHT-MARGIN-paddleheight);
|
||||||
|
objects[numobjs].width = paddlewidth;
|
||||||
|
objects[numobjs].height = paddleheight;
|
||||||
|
objects[numobjs].alive = 1;
|
||||||
|
paddle = &objects[numobjs];
|
||||||
|
numobjs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawScoreboard(int score, int lives)
|
||||||
|
{
|
||||||
|
char tens = score / 10; score -= (10 * tens);
|
||||||
|
char ones = score;
|
||||||
|
|
||||||
|
char string[] = "Score: 0xx Lives: x\0\0";
|
||||||
|
|
||||||
|
string[8] = tens + 0x30;
|
||||||
|
string[9] = ones + 0x30;
|
||||||
|
string[20] = (char)lives + 0x30;
|
||||||
|
|
||||||
|
drawString((WIDTH/2)-252, MARGIN-25, string, 0x0f, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void game()
|
||||||
|
{
|
||||||
|
struct Object *foundObject;
|
||||||
|
unsigned char ch = 0;
|
||||||
|
|
||||||
|
int lives = NUM_LIVES;
|
||||||
|
int points = 0;
|
||||||
|
|
||||||
|
int velocity_x = 1;
|
||||||
|
int velocity_y = 3;
|
||||||
|
|
||||||
|
uart_init();
|
||||||
|
initBricks();
|
||||||
|
initBall();
|
||||||
|
initPaddle();
|
||||||
|
drawScoreboard(points, lives);
|
||||||
|
|
||||||
|
while (!getUart()); // Wait for keypress to start game
|
||||||
|
|
||||||
|
while (lives > 0 && bricks > 0) {
|
||||||
|
// Get any waiting input and flush the buffer
|
||||||
|
if ( ( ch = getUart() ) ) {
|
||||||
|
if (ch == 'l') if (paddle->x + paddle->width + (paddle->width / 2) <= WIDTH-MARGIN) moveObject(paddle, paddle->width / 2, 0);
|
||||||
|
if (ch == 'h') if (paddle->x >= MARGIN+(paddle->width / 2)) moveObject(paddle, -(paddle->width / 2), 0);
|
||||||
|
}
|
||||||
|
uart_loadOutputFifo();
|
||||||
|
|
||||||
|
// Are we going to hit anything?
|
||||||
|
foundObject = detectCollision(velocity_x, velocity_y);
|
||||||
|
|
||||||
|
if (foundObject) {
|
||||||
|
if (foundObject == paddle) {
|
||||||
|
velocity_y = -velocity_y;
|
||||||
|
// Are we going to hit the side of the paddle
|
||||||
|
if (ball->x + ball->width + velocity_x == paddle->x || ball->x + velocity_x == paddle->x + paddle->width) velocity_x = -velocity_x;
|
||||||
|
} else if (foundObject->type == OBJ_BRICK) {
|
||||||
|
removeObject(foundObject);
|
||||||
|
velocity_y = -velocity_y;
|
||||||
|
bricks--;
|
||||||
|
points++;
|
||||||
|
drawScoreboard(points, lives);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_msec(4000); // Wait for a tenth of a second
|
||||||
|
moveObject(ball, velocity_x, velocity_y);
|
||||||
|
|
||||||
|
// Check we're in the game arena still
|
||||||
|
if (ball->x + ball->width >= WIDTH-MARGIN) {
|
||||||
|
velocity_x = -velocity_x;
|
||||||
|
} else if (ball->x <= MARGIN) {
|
||||||
|
velocity_x = -velocity_x;
|
||||||
|
} else if (ball->y + ball->height >= HEIGHT-MARGIN) {
|
||||||
|
lives--;
|
||||||
|
|
||||||
|
removeObject(ball);
|
||||||
|
removeObject(paddle);
|
||||||
|
|
||||||
|
initBall();
|
||||||
|
initPaddle();
|
||||||
|
drawScoreboard(points, lives);
|
||||||
|
} else if (ball->y <= MARGIN) {
|
||||||
|
velocity_y = -velocity_y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int zoom = WIDTH/192;
|
||||||
|
int strwidth = 10 * FONT_BPG * zoom;
|
||||||
|
int strheight = FONT_BPG * zoom;
|
||||||
|
|
||||||
|
if (bricks == 0) drawString((WIDTH/2)-(strwidth/2), (HEIGHT/2)-(strheight/2), "Well done!", 0x02, zoom);
|
||||||
|
else drawString((WIDTH/2)-(strwidth/2), (HEIGHT/2)-(strheight/2), "Game over!", 0x04, zoom);
|
||||||
|
}
|
1
part6-breakout/breakout.h
Normal file
1
part6-breakout/breakout.h
Normal file
|
@ -0,0 +1 @@
|
||||||
|
void game();
|
214
part6-breakout/fb.c
Normal file
214
part6-breakout/fb.c
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
#include "io.h"
|
||||||
|
#include "mb.h"
|
||||||
|
#include "terminal.h"
|
||||||
|
|
||||||
|
unsigned int width, height, pitch, isrgb;
|
||||||
|
unsigned char *fb;
|
||||||
|
|
||||||
|
// Refer to https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface in write-up!
|
||||||
|
void fb_init()
|
||||||
|
{
|
||||||
|
mbox[0] = 35*4; // Length of message in bytes
|
||||||
|
mbox[1] = MBOX_REQUEST;
|
||||||
|
|
||||||
|
mbox[2] = MBOX_TAG_SETPHYWH; // Tag identifier
|
||||||
|
mbox[3] = 8; // Value size in bytes
|
||||||
|
mbox[4] = 8; // Value size in bytes (again!)
|
||||||
|
mbox[5] = 1920; // Value(width)
|
||||||
|
mbox[6] = 1080; // Value(height)
|
||||||
|
|
||||||
|
mbox[7] = MBOX_TAG_SETVIRTWH;
|
||||||
|
mbox[8] = 8;
|
||||||
|
mbox[9] = 8;
|
||||||
|
mbox[10] = 1920;
|
||||||
|
mbox[11] = 1080;
|
||||||
|
|
||||||
|
mbox[12] = MBOX_TAG_SETVIRTOFF;
|
||||||
|
mbox[13] = 8;
|
||||||
|
mbox[14] = 8;
|
||||||
|
mbox[15] = 0; // Value(x)
|
||||||
|
mbox[16] = 0; // Value(y)
|
||||||
|
|
||||||
|
mbox[17] = MBOX_TAG_SETDEPTH;
|
||||||
|
mbox[18] = 4;
|
||||||
|
mbox[19] = 4;
|
||||||
|
mbox[20] = 32; // Bits per pixel
|
||||||
|
|
||||||
|
mbox[21] = MBOX_TAG_SETPXLORDR;
|
||||||
|
mbox[22] = 4;
|
||||||
|
mbox[23] = 4;
|
||||||
|
mbox[24] = 1; // RGB
|
||||||
|
|
||||||
|
mbox[25] = MBOX_TAG_GETFB;
|
||||||
|
mbox[26] = 8;
|
||||||
|
mbox[27] = 8;
|
||||||
|
mbox[28] = 4096; // FrameBufferInfo.pointer
|
||||||
|
mbox[29] = 0; // FrameBufferInfo.size
|
||||||
|
|
||||||
|
mbox[30] = MBOX_TAG_GETPITCH;
|
||||||
|
mbox[31] = 4;
|
||||||
|
mbox[32] = 4;
|
||||||
|
mbox[33] = 0; // Bytes per line
|
||||||
|
|
||||||
|
mbox[34] = MBOX_TAG_LAST;
|
||||||
|
|
||||||
|
// Check call is successful and we have a pointer with depth 32
|
||||||
|
if (mbox_call(MBOX_CH_PROP) && mbox[20] == 32 && mbox[28] != 0) {
|
||||||
|
mbox[28] &= 0x3FFFFFFF; // Convert GPU address to ARM address
|
||||||
|
width = mbox[10]; // Actual physical width
|
||||||
|
height = mbox[11]; // Actual physical height
|
||||||
|
pitch = mbox[33]; // Number of bytes per line
|
||||||
|
isrgb = mbox[24]; // Pixel order
|
||||||
|
fb = (unsigned char *)((long)mbox[28]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawPixel(int x, int y, unsigned char attr)
|
||||||
|
{
|
||||||
|
int offs = (y * pitch) + (x * 4);
|
||||||
|
*((unsigned int*)(fb + offs)) = vgapal[attr & 0x0f];
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawChar(unsigned char ch, int x, int y, unsigned char attr, int zoom)
|
||||||
|
{
|
||||||
|
unsigned char *glyph = (unsigned char *)&font + (ch < FONT_NUMGLYPHS ? ch : 0) * FONT_BPG;
|
||||||
|
|
||||||
|
for (int i=1;i<=(FONT_HEIGHT*zoom);i++) {
|
||||||
|
for (int j=0;j<(FONT_WIDTH*zoom);j++) {
|
||||||
|
unsigned char mask = 1 << (j/zoom);
|
||||||
|
unsigned char col = (*glyph & mask) ? attr & 0x0f : (attr & 0xf0) >> 4;
|
||||||
|
|
||||||
|
drawPixel(x+j, y+i, col);
|
||||||
|
}
|
||||||
|
glyph += (i%zoom) ? 0 : FONT_BPL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawString(int x, int y, char *s, unsigned char attr, int zoom)
|
||||||
|
{
|
||||||
|
while(*s) {
|
||||||
|
if (*s == '\r') {
|
||||||
|
x = 0;
|
||||||
|
} else if(*s == '\n') {
|
||||||
|
x = 0; y += FONT_HEIGHT;
|
||||||
|
} else {
|
||||||
|
drawChar(*s, x, y, attr, zoom);
|
||||||
|
x += (FONT_WIDTH*zoom);
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawRect(int x1, int y1, int x2, int y2, unsigned char attr, int fill)
|
||||||
|
{
|
||||||
|
int y=y1;
|
||||||
|
|
||||||
|
while (y <= y2) {
|
||||||
|
int x=x1;
|
||||||
|
while (x <= x2) {
|
||||||
|
if (fill || (x == x1 || x == x2) || (y == y1 || y == y2)) drawPixel(x, y, attr);
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void moveRect(int oldx, int oldy, int width, int height, int shiftx, int shifty, unsigned char attr)
|
||||||
|
{
|
||||||
|
unsigned int newx = oldx + shiftx, newy = oldy + shifty;
|
||||||
|
unsigned int xcount = 0, ycount = 0;
|
||||||
|
unsigned int bitmap[width][height]; // This is very unsafe if it's too big for the stack...
|
||||||
|
unsigned int offs;
|
||||||
|
|
||||||
|
// Save the bitmap
|
||||||
|
while (xcount < width) {
|
||||||
|
while (ycount < height) {
|
||||||
|
offs = ((oldy + ycount) * pitch) + ((oldx + xcount) * 4);
|
||||||
|
|
||||||
|
bitmap[xcount][ycount] = *((unsigned int*)(fb + offs));
|
||||||
|
ycount++;
|
||||||
|
}
|
||||||
|
ycount=0;
|
||||||
|
xcount++;
|
||||||
|
}
|
||||||
|
// Wipe it out with background colour
|
||||||
|
drawRect(oldx, oldy, oldx + width, oldy + width, attr, 1);
|
||||||
|
// Draw it again
|
||||||
|
for (int i=newx;i<newx + width;i++) {
|
||||||
|
for (int j=newy;j<newy + height;j++) {
|
||||||
|
offs = (j * pitch) + (i * 4);
|
||||||
|
*((unsigned int*)(fb + offs)) = bitmap[i-newx][j-newy];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawLine(int x1, int y1, int x2, int y2, unsigned char attr)
|
||||||
|
{
|
||||||
|
int dx, dy, p, x, y;
|
||||||
|
|
||||||
|
dx = x2-x1;
|
||||||
|
dy = y2-y1;
|
||||||
|
x = x1;
|
||||||
|
y = y1;
|
||||||
|
p = 2*dy-dx;
|
||||||
|
|
||||||
|
while (x<x2) {
|
||||||
|
if (p >= 0) {
|
||||||
|
drawPixel(x,y,attr);
|
||||||
|
y++;
|
||||||
|
p = p+2*dy-2*dx;
|
||||||
|
} else {
|
||||||
|
drawPixel(x,y,attr);
|
||||||
|
p = p+2*dy;
|
||||||
|
}
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawCircle(int x0, int y0, int radius, unsigned char attr, int fill)
|
||||||
|
{
|
||||||
|
int x = radius;
|
||||||
|
int y = 0;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
while (x >= y) {
|
||||||
|
if (fill) {
|
||||||
|
drawLine(x0 - y, y0 + x, x0 + y, y0 + x, attr);
|
||||||
|
drawLine(x0 - x, y0 + y, x0 + x, y0 + y, attr);
|
||||||
|
drawLine(x0 - x, y0 - y, x0 + x, y0 - y, attr);
|
||||||
|
drawLine(x0 - y, y0 - x, x0 + y, y0 - x, attr);
|
||||||
|
} else {
|
||||||
|
drawPixel(x0 - y, y0 + x, attr);
|
||||||
|
drawPixel(x0 + y, y0 + x, attr);
|
||||||
|
drawPixel(x0 - x, y0 + y, attr);
|
||||||
|
drawPixel(x0 + x, y0 + y, attr);
|
||||||
|
drawPixel(x0 - x, y0 - y, attr);
|
||||||
|
drawPixel(x0 + x, y0 - y, attr);
|
||||||
|
drawPixel(x0 - y, y0 - x, attr);
|
||||||
|
drawPixel(x0 + y, y0 - x, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err <= 0) {
|
||||||
|
y += 1;
|
||||||
|
err += 2*y + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err > 0) {
|
||||||
|
x -= 1;
|
||||||
|
err -= 2*x + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait_msec(unsigned int n)
|
||||||
|
{
|
||||||
|
register unsigned long f, t, r;
|
||||||
|
|
||||||
|
// Get the current counter frequency
|
||||||
|
asm volatile ("mrs %0, cntfrq_el0" : "=r"(f));
|
||||||
|
// Read the current counter
|
||||||
|
asm volatile ("mrs %0, cntpct_el0" : "=r"(t));
|
||||||
|
// Calculate expire value for counter
|
||||||
|
t+=((f/1000)*n)/1000;
|
||||||
|
do{asm volatile ("mrs %0, cntpct_el0" : "=r"(r));}while(r<t);
|
||||||
|
}
|
9
part6-breakout/fb.h
Normal file
9
part6-breakout/fb.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
void fb_init();
|
||||||
|
void drawPixel(int x, int y, unsigned char attr);
|
||||||
|
void drawChar(unsigned char ch, int x, int y, unsigned char attr, int zoom);
|
||||||
|
void drawString(int x, int y, char *s, unsigned char attr, int zoom);
|
||||||
|
void drawRect(int x1, int y1, int x2, int y2, unsigned char attr, int fill);
|
||||||
|
void drawCircle(int x0, int y0, int radius, unsigned char attr, int fill);
|
||||||
|
void drawLine(int x1, int y1, int x2, int y2, unsigned char attr);
|
||||||
|
void moveRect(int oldx, int oldy, int width, int height, int shiftx, int shifty, unsigned char attr);
|
||||||
|
void wait_msec(unsigned int n);
|
166
part6-breakout/io.c
Normal file
166
part6-breakout/io.c
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
// GPIO
|
||||||
|
|
||||||
|
enum {
|
||||||
|
GPFSEL0 = PERIPHERAL_BASE + 0x200000,
|
||||||
|
GPSET0 = PERIPHERAL_BASE + 0x20001C,
|
||||||
|
GPCLR0 = PERIPHERAL_BASE + 0x200028,
|
||||||
|
GPPUPPDN0 = PERIPHERAL_BASE + 0x2000E4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
GPIO_MAX_PIN = 53,
|
||||||
|
GPIO_FUNCTION_OUT = 1,
|
||||||
|
GPIO_FUNCTION_ALT5 = 2,
|
||||||
|
GPIO_FUNCTION_ALT3 = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
Pull_None = 0,
|
||||||
|
Pull_Down = 1, // Are down and up the right way around?
|
||||||
|
Pull_Up = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
void mmio_write(long reg, unsigned int val) { *(volatile unsigned int *)reg = val; }
|
||||||
|
unsigned int mmio_read(long reg) { return *(volatile unsigned int *)reg; }
|
||||||
|
|
||||||
|
unsigned int gpio_call(unsigned int pin_number, unsigned int value, unsigned int base, unsigned int field_size, unsigned int field_max) {
|
||||||
|
unsigned int field_mask = (1 << field_size) - 1;
|
||||||
|
|
||||||
|
if (pin_number > field_max) return 0;
|
||||||
|
if (value > field_mask) return 0;
|
||||||
|
|
||||||
|
unsigned int num_fields = 32 / field_size;
|
||||||
|
unsigned int reg = base + ((pin_number / num_fields) * 4);
|
||||||
|
unsigned int shift = (pin_number % num_fields) * field_size;
|
||||||
|
|
||||||
|
unsigned int curval = mmio_read(reg);
|
||||||
|
curval &= ~(field_mask << shift);
|
||||||
|
curval |= value << shift;
|
||||||
|
mmio_write(reg, curval);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int gpio_set (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPSET0, 1, GPIO_MAX_PIN); }
|
||||||
|
unsigned int gpio_clear (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPCLR0, 1, GPIO_MAX_PIN); }
|
||||||
|
unsigned int gpio_pull (unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPPUPPDN0, 2, GPIO_MAX_PIN); }
|
||||||
|
unsigned int gpio_function(unsigned int pin_number, unsigned int value) { return gpio_call(pin_number, value, GPFSEL0, 3, GPIO_MAX_PIN); }
|
||||||
|
|
||||||
|
void gpio_useAsAlt3(unsigned int pin_number) {
|
||||||
|
gpio_pull(pin_number, Pull_None);
|
||||||
|
gpio_function(pin_number, GPIO_FUNCTION_ALT3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_useAsAlt5(unsigned int pin_number) {
|
||||||
|
gpio_pull(pin_number, Pull_None);
|
||||||
|
gpio_function(pin_number, GPIO_FUNCTION_ALT5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_initOutputPinWithPullNone(unsigned int pin_number) {
|
||||||
|
gpio_pull(pin_number, Pull_None);
|
||||||
|
gpio_function(pin_number, GPIO_FUNCTION_OUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpio_setPinOutputBool(unsigned int pin_number, unsigned int onOrOff) {
|
||||||
|
if (onOrOff) {
|
||||||
|
gpio_set(pin_number, 1);
|
||||||
|
} else {
|
||||||
|
gpio_clear(pin_number, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UART
|
||||||
|
|
||||||
|
enum {
|
||||||
|
AUX_BASE = PERIPHERAL_BASE + 0x215000,
|
||||||
|
AUX_IRQ = AUX_BASE,
|
||||||
|
AUX_ENABLES = AUX_BASE + 4,
|
||||||
|
AUX_MU_IO_REG = AUX_BASE + 64,
|
||||||
|
AUX_MU_IER_REG = AUX_BASE + 68,
|
||||||
|
AUX_MU_IIR_REG = AUX_BASE + 72,
|
||||||
|
AUX_MU_LCR_REG = AUX_BASE + 76,
|
||||||
|
AUX_MU_MCR_REG = AUX_BASE + 80,
|
||||||
|
AUX_MU_LSR_REG = AUX_BASE + 84,
|
||||||
|
AUX_MU_MSR_REG = AUX_BASE + 88,
|
||||||
|
AUX_MU_SCRATCH = AUX_BASE + 92,
|
||||||
|
AUX_MU_CNTL_REG = AUX_BASE + 96,
|
||||||
|
AUX_MU_STAT_REG = AUX_BASE + 100,
|
||||||
|
AUX_MU_BAUD_REG = AUX_BASE + 104,
|
||||||
|
AUX_UART_CLOCK = 500000000,
|
||||||
|
UART_MAX_QUEUE = 16 * 1024
|
||||||
|
};
|
||||||
|
|
||||||
|
#define AUX_MU_BAUD(baud) ((AUX_UART_CLOCK/(baud*8))-1)
|
||||||
|
|
||||||
|
unsigned char uart_output_queue[UART_MAX_QUEUE];
|
||||||
|
unsigned int uart_output_queue_write = 0;
|
||||||
|
unsigned int uart_output_queue_read = 0;
|
||||||
|
|
||||||
|
void uart_init() {
|
||||||
|
mmio_write(AUX_ENABLES, 1); //enable UART1
|
||||||
|
mmio_write(AUX_MU_IER_REG, 0);
|
||||||
|
mmio_write(AUX_MU_CNTL_REG, 0);
|
||||||
|
mmio_write(AUX_MU_LCR_REG, 3); //8 bits
|
||||||
|
mmio_write(AUX_MU_MCR_REG, 0);
|
||||||
|
mmio_write(AUX_MU_IER_REG, 0);
|
||||||
|
mmio_write(AUX_MU_IIR_REG, 0xC6); //disable interrupts
|
||||||
|
mmio_write(AUX_MU_BAUD_REG, AUX_MU_BAUD(115200));
|
||||||
|
gpio_useAsAlt5(14);
|
||||||
|
gpio_useAsAlt5(15);
|
||||||
|
mmio_write(AUX_MU_CNTL_REG, 3); //enable RX/TX
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int uart_isOutputQueueEmpty() {
|
||||||
|
return uart_output_queue_read == uart_output_queue_write;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int uart_isReadByteReady() { return mmio_read(AUX_MU_LSR_REG) & 0x01; }
|
||||||
|
unsigned int uart_isWriteByteReady() { return mmio_read(AUX_MU_LSR_REG) & 0x20; }
|
||||||
|
|
||||||
|
unsigned char uart_readByte() {
|
||||||
|
while (!uart_isReadByteReady());
|
||||||
|
return (unsigned char)mmio_read(AUX_MU_IO_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_writeByteBlockingActual(unsigned char ch) {
|
||||||
|
while (!uart_isWriteByteReady());
|
||||||
|
mmio_write(AUX_MU_IO_REG, (unsigned int)ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_loadOutputFifo() {
|
||||||
|
while (!uart_isOutputQueueEmpty() && uart_isWriteByteReady()) {
|
||||||
|
uart_writeByteBlockingActual(uart_output_queue[uart_output_queue_read]);
|
||||||
|
uart_output_queue_read = (uart_output_queue_read + 1) & (UART_MAX_QUEUE - 1); // Don't overrun
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_writeByteBlocking(unsigned char ch) {
|
||||||
|
unsigned int next = (uart_output_queue_write + 1) & (UART_MAX_QUEUE - 1); // Don't overrun
|
||||||
|
|
||||||
|
while (next == uart_output_queue_read) uart_loadOutputFifo();
|
||||||
|
|
||||||
|
uart_output_queue[uart_output_queue_write] = ch;
|
||||||
|
uart_output_queue_write = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_writeText(char *buffer) {
|
||||||
|
while (*buffer) {
|
||||||
|
if (*buffer == '\n') uart_writeByteBlocking('\r');
|
||||||
|
uart_writeByteBlocking(*buffer++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_drainOutputQueue() {
|
||||||
|
while (!uart_isOutputQueueEmpty()) uart_loadOutputFifo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_update() {
|
||||||
|
uart_loadOutputFifo();
|
||||||
|
|
||||||
|
if (uart_isReadByteReady()) {
|
||||||
|
unsigned char ch = uart_readByte();
|
||||||
|
if (ch == '\r') uart_writeText("\n"); else uart_writeByteBlocking(ch);
|
||||||
|
}
|
||||||
|
}
|
11
part6-breakout/io.h
Normal file
11
part6-breakout/io.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#define PERIPHERAL_BASE 0xFE000000
|
||||||
|
|
||||||
|
void uart_init();
|
||||||
|
void uart_writeText(char *buffer);
|
||||||
|
void uart_loadOutputFifo();
|
||||||
|
unsigned char uart_readByte();
|
||||||
|
unsigned int uart_isReadByteReady();
|
||||||
|
void uart_writeByteBlocking(unsigned char ch);
|
||||||
|
void uart_update();
|
||||||
|
void mmio_write(long reg, unsigned int val);
|
||||||
|
unsigned int mmio_read(long reg);
|
10
part6-breakout/kernel.c
Normal file
10
part6-breakout/kernel.c
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#include "io.h"
|
||||||
|
#include "fb.h"
|
||||||
|
#include "breakout.h"
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fb_init();
|
||||||
|
game();
|
||||||
|
while (1);
|
||||||
|
}
|
19
part6-breakout/link.ld
Normal file
19
part6-breakout/link.ld
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x80000; /* Kernel load address for AArch64 */
|
||||||
|
.text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) }
|
||||||
|
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) }
|
||||||
|
PROVIDE(_data = .);
|
||||||
|
.data : { *(.data .data.* .gnu.linkonce.d*) }
|
||||||
|
.bss (NOLOAD) : {
|
||||||
|
. = ALIGN(16);
|
||||||
|
__bss_start = .;
|
||||||
|
*(.bss .bss.*)
|
||||||
|
*(COMMON)
|
||||||
|
__bss_end = .;
|
||||||
|
}
|
||||||
|
_end = .;
|
||||||
|
|
||||||
|
/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
|
||||||
|
}
|
||||||
|
__bss_size = (__bss_end - __bss_start)>>3;
|
39
part6-breakout/mb.c
Normal file
39
part6-breakout/mb.c
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
// The buffer must be 16-byte aligned as only the upper 28 bits of the address can be passed via the mailbox
|
||||||
|
volatile unsigned int __attribute__((aligned(16))) mbox[36];
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VIDEOCORE_MBOX = (PERIPHERAL_BASE + 0x0000B880),
|
||||||
|
MBOX_READ = (VIDEOCORE_MBOX + 0x0),
|
||||||
|
MBOX_POLL = (VIDEOCORE_MBOX + 0x10),
|
||||||
|
MBOX_SENDER = (VIDEOCORE_MBOX + 0x14),
|
||||||
|
MBOX_STATUS = (VIDEOCORE_MBOX + 0x18),
|
||||||
|
MBOX_CONFIG = (VIDEOCORE_MBOX + 0x1C),
|
||||||
|
MBOX_WRITE = (VIDEOCORE_MBOX + 0x20),
|
||||||
|
MBOX_RESPONSE = 0x80000000,
|
||||||
|
MBOX_FULL = 0x80000000,
|
||||||
|
MBOX_EMPTY = 0x40000000
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int mbox_call(unsigned char ch)
|
||||||
|
{
|
||||||
|
// 28-bit address (MSB) and 4-bit value (LSB)
|
||||||
|
unsigned int r = ((unsigned int)((long) &mbox) &~ 0xF) | (ch & 0xF);
|
||||||
|
|
||||||
|
// Wait until we can write
|
||||||
|
while (mmio_read(MBOX_STATUS) & MBOX_FULL);
|
||||||
|
|
||||||
|
/* write the address of our message to the mailbox with channel identifier */
|
||||||
|
mmio_write(MBOX_WRITE, r);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// Is there a reply?
|
||||||
|
while (mmio_read(MBOX_STATUS) & MBOX_EMPTY);
|
||||||
|
|
||||||
|
// Is it a reply to our message?
|
||||||
|
if (r == mmio_read(MBOX_READ)) return mbox[1]==MBOX_RESPONSE; // Is it successful?
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
34
part6-breakout/mb.h
Normal file
34
part6-breakout/mb.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
extern volatile unsigned int mbox[36];
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MBOX_REQUEST = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MBOX_CH_POWER = 0,
|
||||||
|
MBOX_CH_FB = 1,
|
||||||
|
MBOX_CH_VUART = 2,
|
||||||
|
MBOX_CH_VCHIQ = 3,
|
||||||
|
MBOX_CH_LEDS = 4,
|
||||||
|
MBOX_CH_BTNS = 5,
|
||||||
|
MBOX_CH_TOUCH = 6,
|
||||||
|
MBOX_CH_COUNT = 7,
|
||||||
|
MBOX_CH_PROP = 8 // Request from ARM for response by VideoCore
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MBOX_TAG_SETPOWER = 0x28001,
|
||||||
|
MBOX_TAG_SETCLKRATE = 0x38002,
|
||||||
|
|
||||||
|
MBOX_TAG_SETPHYWH = 0x48003,
|
||||||
|
MBOX_TAG_SETVIRTWH = 0x48004,
|
||||||
|
MBOX_TAG_SETVIRTOFF = 0x48009,
|
||||||
|
MBOX_TAG_SETDEPTH = 0x48005,
|
||||||
|
MBOX_TAG_SETPXLORDR = 0x48006,
|
||||||
|
MBOX_TAG_GETFB = 0x40001,
|
||||||
|
MBOX_TAG_GETPITCH = 0x40008,
|
||||||
|
|
||||||
|
MBOX_TAG_LAST = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int mbox_call(unsigned char ch);
|
253
part6-breakout/terminal.h
Normal file
253
part6-breakout/terminal.h
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
unsigned int vgapal[] = {
|
||||||
|
0x000000,
|
||||||
|
0x0000AA,
|
||||||
|
0x00AA00,
|
||||||
|
0x00AAAA,
|
||||||
|
0xAA0000,
|
||||||
|
0xAA00AA,
|
||||||
|
0xAA5500,
|
||||||
|
0xAAAAAA,
|
||||||
|
0x555555,
|
||||||
|
0x5555FF,
|
||||||
|
0x55FF55,
|
||||||
|
0x55FFFF,
|
||||||
|
0xFF5555,
|
||||||
|
0xFF55FF,
|
||||||
|
0xFFFF55,
|
||||||
|
0xFFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FONT_WIDTH = 8,
|
||||||
|
FONT_HEIGHT = 8,
|
||||||
|
FONT_BPG = 8, // Bytes per glyph
|
||||||
|
FONT_BPL = 1, // Bytes per line
|
||||||
|
FONT_NUMGLYPHS = 224
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned char font[FONT_NUMGLYPHS][FONT_BPG] = {
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space)
|
||||||
|
{ 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!)
|
||||||
|
{ 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (")
|
||||||
|
{ 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#)
|
||||||
|
{ 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($)
|
||||||
|
{ 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%)
|
||||||
|
{ 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&)
|
||||||
|
{ 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (')
|
||||||
|
{ 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (()
|
||||||
|
{ 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ())
|
||||||
|
{ 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*)
|
||||||
|
{ 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.)
|
||||||
|
{ 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/)
|
||||||
|
{ 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0)
|
||||||
|
{ 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1)
|
||||||
|
{ 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2)
|
||||||
|
{ 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3)
|
||||||
|
{ 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4)
|
||||||
|
{ 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5)
|
||||||
|
{ 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6)
|
||||||
|
{ 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7)
|
||||||
|
{ 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8)
|
||||||
|
{ 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9)
|
||||||
|
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:)
|
||||||
|
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (;)
|
||||||
|
{ 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<)
|
||||||
|
{ 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=)
|
||||||
|
{ 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>)
|
||||||
|
{ 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?)
|
||||||
|
{ 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@)
|
||||||
|
{ 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A)
|
||||||
|
{ 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B)
|
||||||
|
{ 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C)
|
||||||
|
{ 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D)
|
||||||
|
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E)
|
||||||
|
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F)
|
||||||
|
{ 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G)
|
||||||
|
{ 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H)
|
||||||
|
{ 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I)
|
||||||
|
{ 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J)
|
||||||
|
{ 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K)
|
||||||
|
{ 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L)
|
||||||
|
{ 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M)
|
||||||
|
{ 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N)
|
||||||
|
{ 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O)
|
||||||
|
{ 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P)
|
||||||
|
{ 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q)
|
||||||
|
{ 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R)
|
||||||
|
{ 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S)
|
||||||
|
{ 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T)
|
||||||
|
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U)
|
||||||
|
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V)
|
||||||
|
{ 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W)
|
||||||
|
{ 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X)
|
||||||
|
{ 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y)
|
||||||
|
{ 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z)
|
||||||
|
{ 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([)
|
||||||
|
{ 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\)
|
||||||
|
{ 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (])
|
||||||
|
{ 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_)
|
||||||
|
{ 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`)
|
||||||
|
{ 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a)
|
||||||
|
{ 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b)
|
||||||
|
{ 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c)
|
||||||
|
{ 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d)
|
||||||
|
{ 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e)
|
||||||
|
{ 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f)
|
||||||
|
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g)
|
||||||
|
{ 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h)
|
||||||
|
{ 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i)
|
||||||
|
{ 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j)
|
||||||
|
{ 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k)
|
||||||
|
{ 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l)
|
||||||
|
{ 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m)
|
||||||
|
{ 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n)
|
||||||
|
{ 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o)
|
||||||
|
{ 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p)
|
||||||
|
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q)
|
||||||
|
{ 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r)
|
||||||
|
{ 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s)
|
||||||
|
{ 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t)
|
||||||
|
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u)
|
||||||
|
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v)
|
||||||
|
{ 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w)
|
||||||
|
{ 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x)
|
||||||
|
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y)
|
||||||
|
{ 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z)
|
||||||
|
{ 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({)
|
||||||
|
{ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|)
|
||||||
|
{ 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (})
|
||||||
|
{ 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007F
|
||||||
|
{ 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x18, 0x30, 0x1E}, // U+00C7 (C cedille)
|
||||||
|
{ 0x00, 0x33, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00FC (u umlaut)
|
||||||
|
{ 0x38, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // U+00E9 (e aigu)
|
||||||
|
{ 0x7E, 0xC3, 0x3C, 0x60, 0x7C, 0x66, 0xFC, 0x00}, // U+00E2 (a circumflex)
|
||||||
|
{ 0x33, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E4 (a umlaut)
|
||||||
|
{ 0x07, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E0 (a grave)
|
||||||
|
{ 0x0C, 0x0C, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E5 (a ring)
|
||||||
|
{ 0x00, 0x00, 0x1E, 0x03, 0x03, 0x1E, 0x30, 0x1C}, // U+00E7 (c cedille)
|
||||||
|
{ 0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00}, // U+00EA (e circumflex)
|
||||||
|
{ 0x33, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // U+00EB (e umlaut)
|
||||||
|
{ 0x07, 0x00, 0x1E, 0x33, 0x3F, 0x03, 0x1E, 0x00}, // U+00E8 (e grave)
|
||||||
|
{ 0x33, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00EF (i umlaut)
|
||||||
|
{ 0x3E, 0x63, 0x1C, 0x18, 0x18, 0x18, 0x3C, 0x00}, // U+00EE (i circumflex)
|
||||||
|
{ 0x07, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00EC (i grave)
|
||||||
|
{ 0x63, 0x1C, 0x36, 0x63, 0x7F, 0x63, 0x63, 0x00}, // U+00C4 (A umlaut)
|
||||||
|
{ 0x0C, 0x0C, 0x00, 0x1E, 0x33, 0x3F, 0x33, 0x00}, // U+00C5 (A ring)
|
||||||
|
{ 0x07, 0x00, 0x3F, 0x06, 0x1E, 0x06, 0x3F, 0x00}, // U+00C8 (E grave)
|
||||||
|
{ 0x00, 0x00, 0xFE, 0x30, 0xFE, 0x33, 0xFE, 0x00}, // U+00E6 (ae)
|
||||||
|
{ 0x7C, 0x36, 0x33, 0x7F, 0x33, 0x33, 0x73, 0x00}, // U+00C6 (AE)
|
||||||
|
{ 0x1E, 0x33, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F4 (o circumflex)
|
||||||
|
{ 0x00, 0x33, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F6 (o umlaut)
|
||||||
|
{ 0x00, 0x07, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F2 (o grave)
|
||||||
|
{ 0x1E, 0x33, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00FB (u circumflex)
|
||||||
|
{ 0x00, 0x07, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00F9 (u grave)
|
||||||
|
{ 0x00, 0x33, 0x00, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+00FF (y umlaut)
|
||||||
|
{ 0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00}, // U+00D6 (O umlaut)
|
||||||
|
{ 0x33, 0x00, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+00DC (U umlaut)
|
||||||
|
{ 0x18, 0x18, 0x7E, 0x03, 0x03, 0x7E, 0x18, 0x18}, // U+00A2 (dollarcents)
|
||||||
|
{ 0x1C, 0x36, 0x26, 0x0F, 0x06, 0x67, 0x3F, 0x00}, // U+00A3 (pound sterling)
|
||||||
|
{ 0x33, 0x33, 0x1E, 0x3F, 0x0C, 0x3F, 0x0C, 0x0C}, // U+00A5 (yen)
|
||||||
|
{ 0x7C, 0xC6, 0x1C, 0x36, 0x36, 0x1C, 0x33, 0x1E}, // U+00A7 (paragraph)
|
||||||
|
{ 0x70, 0xD8, 0x18, 0x3C, 0x18, 0x18, 0x1B, 0x0E}, // U+0192 (dutch florijn)
|
||||||
|
{ 0x38, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x7E, 0x00}, // U+00E1 (a aigu)
|
||||||
|
{ 0x1C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+00ED (i augu)
|
||||||
|
{ 0x00, 0x38, 0x00, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+00F3 (o aigu)
|
||||||
|
{ 0x00, 0x38, 0x00, 0x33, 0x33, 0x33, 0x7E, 0x00}, // U+00FA (u aigu)
|
||||||
|
{ 0x00, 0x1F, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x00}, // U+00F1 (n ~)
|
||||||
|
{ 0x3F, 0x00, 0x33, 0x37, 0x3F, 0x3B, 0x33, 0x00}, // U+00D1 (N ~)
|
||||||
|
{ 0x3C, 0x36, 0x36, 0x7C, 0x00, 0x00, 0x00, 0x00}, // U+00AA (superscript a)
|
||||||
|
{ 0x1C, 0x36, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00}, // U+00BA (superscript 0)
|
||||||
|
{ 0x0C, 0x00, 0x0C, 0x06, 0x03, 0x33, 0x1E, 0x00}, // U+00BF (inverted ?)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x3F, 0x03, 0x03, 0x00, 0x00}, // U+2310 (gun pointing right)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x3F, 0x30, 0x30, 0x00, 0x00}, // U+00AC (gun pointing left)
|
||||||
|
{ 0xC3, 0x63, 0x33, 0x7B, 0xCC, 0x66, 0x33, 0xF0}, // U+00BD (1/2)
|
||||||
|
{ 0xC3, 0x63, 0x33, 0xBD, 0xEC, 0xF6, 0xF3, 0x03}, // U+00BC (1/4)
|
||||||
|
{ 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00}, // U+00A1 (inverted !)
|
||||||
|
{ 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00}, // U+00AB (<<)
|
||||||
|
{ 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00}, // U+00BB (>>)
|
||||||
|
{ 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00}, // U+2591 (25% solid)
|
||||||
|
{ 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA}, // U+2592 (50% solid)
|
||||||
|
{ 0xFF, 0xAA, 0xFF, 0x55, 0xFF, 0xAA, 0xFF, 0x55}, // U+2593 (75% solid)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, // U+2502 (thin vertical)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08}, // U+2524 (down L, left L, up L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x0F, 0x08, 0x0F, 0x08, 0x08}, // U+2561 (up L, down L, left D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x14, 0x17, 0x14, 0x14, 0x14}, // U+2562 (up D, down D, left L)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x1F, 0x14, 0x14, 0x14}, // U+2556 (down D, left L)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x0F, 0x08, 0x0F, 0x08, 0x08}, // U+2555 (down L, left D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x17, 0x10, 0x17, 0x14, 0x14}, // U+2563 (up D, down D, left D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14}, // U+2551 (double vertical)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x1F, 0x10, 0x17, 0x14, 0x14}, // U+2557 (down D, left D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x17, 0x10, 0x1F, 0x00, 0x00}, // U+255D (up D, left D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x14, 0x1F, 0x00, 0x00, 0x00}, // U+255C (up D, left L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x0F, 0x08, 0x0F, 0x00, 0x00}, // U+255B (up L, left D)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x08, 0x08}, // U+2510 (down L, left L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x08, 0xf8, 0x00, 0x00, 0x00}, // U+2514 (up L, right L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x08, 0xff, 0x00, 0x00, 0x00}, // U+2534 (up L, right L, left L)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0xff, 0x08, 0x08, 0x08}, // U+252C (down L, right L, left L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x08, 0xf8, 0x08, 0x08, 0x08}, // U+251C (down L, right L, up L)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00}, // U+2500 (thin horizontal)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08}, // U+253C (up L, right L, left L, down L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0xF8, 0x08, 0xF8, 0x08, 0x08}, // U+255E (up L, down L, right D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x14, 0xF4, 0x14, 0x14, 0x14}, // U+255F (up D, down D, right L)
|
||||||
|
{ 0x14, 0x14, 0x14, 0xF4, 0x04, 0xFC, 0x00, 0x00}, // U+255A (up D, right D)
|
||||||
|
{ 0x00, 0x00, 0x00, 0xFC, 0x04, 0xF4, 0x14, 0x14}, // U+2554 (down D, right D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0xF7, 0x00, 0xFF, 0x00, 0x00}, // U+2569 (left D, right D, up D)
|
||||||
|
{ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x14, 0x14}, // U+2566 (left D, right D, down D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0xF4, 0x04, 0xF4, 0x14, 0x14}, // U+2560 (up D, down D, right D)
|
||||||
|
{ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00}, // U+2550 (double horizontal)
|
||||||
|
{ 0x14, 0x14, 0x14, 0xF7, 0x00, 0xF7, 0x14, 0x14}, // U+256C (left D, right D, down D, up D)
|
||||||
|
{ 0x08, 0x08, 0x08, 0xFF, 0x00, 0xFF, 0x00, 0x00}, // U+2567 (left D, right D, up L)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x14, 0xFF, 0x00, 0x00, 0x00}, // U+2568 (left L, right L, up D)
|
||||||
|
{ 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x08, 0x08}, // U+2564 (left D, right D, down L)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0xFF, 0x14, 0x14, 0x14}, // U+2565 (left L, right L, down D)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x14, 0xFC, 0x00, 0x00, 0x00}, // U+2559 (up D, right L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0xF8, 0x08, 0xF8, 0x00, 0x00}, // U+2558 (up L, right D)
|
||||||
|
{ 0x00, 0x00, 0x00, 0xF8, 0x08, 0xF8, 0x08, 0x08}, // U+2552 (down L, right D)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0xFC, 0x14, 0x14, 0x14}, // U+2553 (down D, right L)
|
||||||
|
{ 0x14, 0x14, 0x14, 0x14, 0xFF, 0x14, 0x14, 0x14}, // U+256B (left L, right L, down D, up D)
|
||||||
|
{ 0x08, 0x08, 0x08, 0xFF, 0x08, 0xFF, 0x08, 0x08}, // U+256A (left D, right D, down L, up L)
|
||||||
|
{ 0x08, 0x08, 0x08, 0x08, 0x0f, 0x00, 0x00, 0x00}, // U+2518 (up L, left L)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0xf8, 0x08, 0x08, 0x08}, // U+250C (down L, right L)
|
||||||
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // U+2588 (solid)
|
||||||
|
{ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}, // U+2584 (bottom half)
|
||||||
|
{ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F}, // U+258C (left half)
|
||||||
|
{ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0}, // U+2590 (right half)
|
||||||
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, // U+2580 (top half)
|
||||||
|
};
|
Loading…
Reference in a new issue