Skip to content

Instantly share code, notes, and snippets.

@cheery
Created February 9, 2019 14:37
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/5b2466edc4007a4f932a16d7a1c0b1df to your computer and use it in GitHub Desktop.
Save cheery/5b2466edc4007a4f932a16d7a1c0b1df to your computer and use it in GitHub Desktop.
# This program draws 100 frames of noise to the screen and then stops.
# Using linux framebuffers.
# 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
#li t0, 16588800
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)
# location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
# (y+vinfo.yoffset) * finfo.line_length;
addi a3, a3, 1
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 "/dev/fb0"
.byte 0
filesize = . - ehdr
# There was a bug in the riscv toolchain preventing use of --oformat binary.
# Use of objcopy is a workaround for it.
noise: noise.elf
riscv64-unknown-elf-objcopy -O binary $^ $@
chmod +x $@
noise.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