Skip to content

Instantly share code, notes, and snippets.

@cheery
Created February 11, 2019 10:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cheery/23de1a0a35ede00008bfe34ab94d4664 to your computer and use it in GitHub Desktop.
Save cheery/23de1a0a35ede00008bfe34ab94d4664 to your computer and use it in GitHub Desktop.
Easy method for drawing pixel graphics on rv8 rv-jit.
# A modified version of the linux-framebuffer program.
# It's drawing into the shared file buffer instead.
# There's no synchronizing, it's just drawing and we get screen tearing.
# This program is drawing colorful noise that flickers.
# https://content.riscv.org/wp-content/uploads/2017/05/riscv-spec-v2.2.pdf
# https://en.wikichip.org/wiki/risc-v/registers
# https://rv8.io/syscalls.html
.section .text
.globl _start # stop ld from nagging.
.org 0
load_address = 0x010000 # can also use: 0x08048000
ehdr:
.byte 0x7f, 0x45, 0x4c, 0x46, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
.half 2 # e_type
.half 0xf3 # e_machine
.word 1 # e_version
.quad load_address + _start - ehdr # e_entry
.quad phdr - ehdr # e_phoff
.quad 0 # e_shoff
.word 0 # e_flags
.half ehdrsize # e_ehsize (64)
.half phdrsize # e_phentsize (56)
.half 1 # e_phnum
.half 0 # e_shentsize (64)
.half 0 # e_shnum
.half 0 # e_shstrndx
ehdrsize = . - ehdr
phdr:
.word 1 # p_type
.word 5 # p_flags
.quad 0 # p_offset
.quad load_address # p_vaddr
.quad load_address # p_paddr
.quad filesize # p_filesz
.quad filesize # p_memsz
.quad 0x1000 # p_align
phdrsize = . - phdr
# Linux system call numbers we are using, https://rv8.io/syscalls.html
sys_ioctl = 29
sys_close = 57
sys_read = 63
sys_write = 64
sys_exit = 93
sys_brk = 214
sys_munmmap = 215
sys_mmap = 222
sys_open = 1024
# standard file numbers
stdin = 0
stdout = 1
stderr = 2
# Some file flags we need
O_RDWR = 0x0002
PROT_READ = 0x1
PROT_WRITE = 0x2
PROT_EXEC = 0x4
PROT_READ_WRITE = 0x3
MAP_SHARED = 0x1
MAP_PRIVATE = 0x2
MAP_FIXED = 0x10
MAP_ANON = 0x20
# Some framebuffer flags we need
FBIOGET_VSCREENINFO = 0x4600
FBIOGET_FSCREENINFO = 0x4602
GET_VSCREENINFO = 0x80A04600
GET_FSCREENINFO = 0x80504602
fb_var_screeninfo_size = 160
# struct fb_var_screeninfo {
# 0 __u32 xres; /* visible resolution */
# 4 __u32 yres;
# 8 __u32 xres_virtual; /* virtual resolution */
# 12 __u32 yres_virtual;
# 16 __u32 xoffset; /* offset from virtual to visible */
# 20 __u32 yoffset; /* resolution */
#
# 24 __u32 bits_per_pixel; /* guess what */
# 28 __u32 grayscale; /* 0 = color, 1 = grayscale, */
# /* >1 = FOURCC */
# 32 struct fb_bitfield red; /* bitfield in fb mem if true color, */
# 44 struct fb_bitfield green; /* else only length is significant */
# 56 struct fb_bitfield blue;
# 68 struct fb_bitfield transp; /* transparency */
#
# 80 __u32 nonstd; /* != 0 Non standard pixel format */
#
# 84 __u32 activate; /* see FB_ACTIVATE_* */
#
# 88 __u32 height; /* height of picture in mm */
# 92 __u32 width; /* width of picture in mm */
#
# 96 __u32 accel_flags; /* (OBSOLETE) see fb_info.flags */
#
# /* Timing: All values in pixclocks, except pixclock (of course) */
# 100 __u32 pixclock; /* pixel clock in ps (pico seconds) */
# 104 __u32 left_margin; /* time from sync to picture */
# 108 __u32 right_margin; /* time from picture to sync */
# 112 __u32 upper_margin; /* time from sync to picture */
# 116 __u32 lower_margin;
# 120 __u32 hsync_len; /* length of horizontal sync */
# 124 __u32 vsync_len; /* length of vertical sync */
# 128 __u32 sync; /* see FB_SYNC_* */
# 132 __u32 vmode; /* see FB_VMODE_* */
# 136 __u32 rotate; /* angle we rotate counter clockwise */
# 140 __u32 colorspace; /* colorspace for FOURCC-based modes */
# __u32 reserved[4]; /* Reserved for future compatibility */
fb_bitfield_size = 12
# struct fb_bitfield {
# 0 __u32 offset; /* beginning of bitfield */
# 4 __u32 length; /* length of bitfield */
# 8 __u32 msb_right; /* != 0 : Most significant bit is */
# /* right */
# };
fb_fix_screeninfo_size = 80
# struct fb_fix_screeninfo {
# 0 char id[16]; /* identification string eg "TT Builtin" */
# 16 unsigned long smem_start; /* Start of frame buffer mem */
# /* (physical address) */
# 24 __u32 smem_len; /* Length of frame buffer mem */
# 28 __u32 type; /* see FB_TYPE_* */
# 32 __u32 type_aux; /* Interleave for interleaved Planes */
# 36 __u32 visual; /* see FB_VISUAL_* */
# 40 __u16 xpanstep; /* zero if no hardware panning */
# 42 __u16 ypanstep; /* zero if no hardware panning */
# 44 __u16 ywrapstep; /* zero if no hardware ywrap */
# 48 __u32 line_length; /* length of a line in bytes */
# 56 unsigned long mmio_start; /* Start of Memory Mapped I/O */
# /* (physical address) */
# 64 __u32 mmio_len; /* Length of Memory Mapped I/O */
# 68 __u32 accel; /* Indicate to driver which */
# /* specific chip/card we have */
# 72 __u16 capabilities; /* see FB_CAP_* */
# __u16 reserved[2]; /* Reserved for future compatibility */
# };
_start:
lla a0, fb0_path
li a1, O_RDWR
li a2, 0
li a7, sys_open
ecall
blt a0, zero, fail # Fail if cannot open the file.
mv gp, a0 # gp = fbfd
# addi sp, sp, -fb_fix_screeninfo_size
# mv a0, gp # fbfd
# li a1, FBIOGET_VSCREENINFO
# mv a2, sp # The screeninfo size pointer.
# li a7, sys_ioctl
# ecall
# blt a0, zero, fail
li a0, stdout
lla a1, greeting
li a2, 6
li a7, sys_write
ecall
# addi sp, sp, -fb_var_screeninfo_size
# mv a0, gp # fbfd
# li a1, FBIOGET_VSCREENINFO
# mv a2, sp # The screeninfo size pointer.
# li a7, sys_ioctl
# ecall
# blt a0, zero, fail
# screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8
# lw a0, 0(sp) # xres
# lw a1, 4(sp) # yres
# lw a2, 24(sp) # bits_per_pixel
# mul a0, a0, a1 # t = xres * yres
# mul a0, a0, a2 # t = t * bits_per_pixel
# srl t0, a0, 3 # >> 8
# t0 = screen size
screen_buffer_size = 1280*1024*3
lui t0, %hi(screen_buffer_size)
addi t0, t0, %lo(screen_buffer_size)
li a0, 0
mv a1, t0 # The screen size.
li a2, PROT_READ_WRITE
li a3, MAP_SHARED
mv a4, gp # fbfd
li a5, 0 # offset
li a7, sys_mmap
ecall
blt a0, zero, fail # Fail if mapping failed.
mv tp, a0 # tp = screenbuffer
# seed for the random number generator.
rdtime a0
lcg_multiplier = 1664525
lui a1, %hi(lcg_multiplier)
addi a1, a1, %lo(lcg_multiplier)
lcg_increment = 1013904223
lui a2, %hi(lcg_increment)
addi a2, a2, %lo(lcg_increment)
li a7, 100 # do 100 times.
repeat_fill:
blt a7, zero, repeat_done
# the current pointer.
li a3, 0
fill_screen_with_garbage:
bge a3, t0, fill_screen_with_garbage_done
mul a4, a0, a1 # seed = (a * seed + c) % m
add a0, a4, a2
srl a6, a0, 24
add a5, tp, a3 # screenbuffer + index
sb a6, 0(a5)
mul a4, a0, a1 # seed = (a * seed + c) % m
add a0, a4, a2
srl a6, a0, 24
add a5, tp, a3 # screenbuffer + index
sb a6, 1(a5)
mul a4, a0, a1 # seed = (a * seed + c) % m
add a0, a4, a2
srl a6, a0, 24
add a5, tp, a3 # screenbuffer + index
sb a6, 2(a5)
# location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
# (y+vinfo.yoffset) * finfo.line_length;
addi a3, a3, 3
j fill_screen_with_garbage
fill_screen_with_garbage_done:
addi a7, a7, -1
j repeat_fill
repeat_done:
# li a0, stdout
# lla a1, greeting
# li a2, 6
# li a7, sys_write
# ecall
li a0, 0
li a7, sys_exit
ecall
fail:
li a0, 1
li a7, sys_exit
ecall
loop: j loop
greeting:
.string "Hello\n"
fb0_path:
.string "window"
.byte 0
filesize = . - ehdr
/* This program generates a small window and a shared file buffer that is mirrored into it.
*/
#include <assert.h> /* assert() */
#include <SDL.h>
#include <stdlib.h> /* exit() */
#include <math.h>
#include <unistd.h> /* truncate(), open() */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h> /* perror */
#include <sys/mman.h> /* mmap */
void check_sdl_error(int);
int main() {
int result;
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *screen;
SDL_Event event;
int done = 0;
int line = 0;
int p = 1;
char *input_pixels;
char *output_pixels;
int pitch;
int screen_width = 1280;
int screen_height = 1024;
int buffer_size = screen_width*screen_height*3;
int fbfd;
result = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
check_sdl_error(result == 0);
window = SDL_CreateWindow("main", 0, 0, screen_width, screen_height, 0);
check_sdl_error(window != NULL);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
screen = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_RGB888,
SDL_TEXTUREACCESS_STREAMING,
screen_width, screen_height);
fbfd = open("window", O_RDWR | O_CREAT, 0660);
if (fbfd == -1) {
perror("cannot open 'window'");
exit(1);
}
if (ftruncate(fbfd, buffer_size) == -1) {
perror("cannot resize the file to correct size");
exit(1);
}
input_pixels = mmap(NULL, buffer_size, PROT_READ|PROT_WRITE, MAP_SHARED, fbfd, 0);
if (input_pixels == MAP_FAILED) {
perror("mmap failed");
exit(1);
}
while (!done) {
unsigned int currentTime;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
done = 1;
}
}
// SDL_UpdateTexture(screen, NULL, (void*)input_pixels, screen_width*4);
SDL_LockTexture(screen, NULL, (void**)&output_pixels, &pitch);
int i = 0;
for (int y = 0; y < screen_height*pitch; y += pitch) {
for (int x = 0; x < screen_width*4; x += 4) {
output_pixels[y+x+0] = input_pixels[i+2];
output_pixels[y+x+1] = input_pixels[i+1];
output_pixels[y+x+2] = input_pixels[i+0];
output_pixels[y+x+3] = 0;
i += 3;
}
}
SDL_UnlockTexture(screen);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, screen, NULL, NULL);
SDL_RenderPresent(renderer);
}
SDL_ShowWindow(window);
SDL_DestroyTexture(screen);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
void check_sdl_error(int success) {
if (!success) {
SDL_LogError(SDL_LOG_CATEGORY_ERROR,
"%s\n", SDL_GetError());
exit(1);
}
}
SDL2_CFLAGS = $(shell pkg-config sdl2 --cflags)
SDL2_LIBS = $(shell pkg-config sdl2 --libs)
CFLAGS = $(SDL2_CFLAGS)
LIBS = $(SDL2_LIBS) -lm
.PHONY: all
all: main maze
run: all
./main& rv-jit maze
main: main.c
gcc $(CFLAGS) -O2 $^ -o $@ $(LIBS)
# There was a bug in the riscv toolchain preventing use of --oformat binary.
# Use of objcopy is a workaround for it.
maze: maze.elf
riscv64-unknown-elf-objcopy -O binary $^ $@
chmod +x $@
maze.elf: listing.s
riscv64-unknown-elf-gcc -nostartfiles $^ -o $@
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment