Skip to content

Commit

Permalink
Add zig example
Browse files Browse the repository at this point in the history
  • Loading branch information
daurnimator committed Jan 22, 2020
1 parent 53cffe1 commit 1ee0ab1
Show file tree
Hide file tree
Showing 10 changed files with 322 additions and 0 deletions.
2 changes: 2 additions & 0 deletions riscv-zig-blink/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
zig-cache/
riscv-zig-blink.bin
39 changes: 39 additions & 0 deletions riscv-zig-blink/build.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const std = @import("std");
const Builder = std.build.Builder;

pub fn build(b: *Builder) void {
b.setPreferredReleaseMode(.ReleaseSmall);
const mode = b.standardReleaseOptions();

const elf = b.addExecutable("riscv-zig-blink", "src/main.zig");
elf.setTheTarget(.{
.Cross = .{
.arch = .riscv32,
.os = .freestanding,
.abi = .gnu,
.cpu_features = .{ .features = std.Target.Cpu.Feature.Set.empty },
},
});
elf.setLinkerScriptPath("ld/linker.ld");
elf.setBuildMode(mode);

const binary = b.addSystemCommand(&[_][]const u8{
"llvm-objcopy",
"-I",
"elf32-littleriscv",
"-O",
"binary",
});
binary.addArtifactArg(elf);
binary.addArg("riscv-zig-blink.bin");
b.default_step.dependOn(&binary.step);

const run_cmd = b.addSystemCommand(&[_][]const u8{
"dfu-util",
"-D",
"riscv-zig-blink.bin",
});
run_cmd.step.dependOn(&binary.step);
const run_step = b.step("run", "Upload and run the app on your FOMU");
run_step.dependOn(&run_cmd.step);
}
59 changes: 59 additions & 0 deletions riscv-zig-blink/ld/linker.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
ENTRY(_start)

__DYNAMIC = 0;

MEMORY {
sram : ORIGIN = 0x10000000, LENGTH = 0x00020000
rom : ORIGIN = 0x20040000, LENGTH = 0x100000 /* 1 MBit */
}

SECTIONS
{
.text :
{
_ftext = .;
*(.text.start)
*(.text .stub .text.* .gnu.linkonce.t.*)
_etext = .;
} > rom

.rodata :
{
. = ALIGN(4);
_frodata = .;
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.rodata1)
*(.srodata)
. = ALIGN(4);
_erodata = .;
} > rom

.data : AT (ADDR(.rodata) + SIZEOF (.rodata))
{
. = ALIGN(4);
_fdata = .;
*(.data .data.* .gnu.linkonce.d.*)
*(.data1)
*(.ramtext .ramtext.*)
_gp = ALIGN(16);
*(.sdata .sdata.* .gnu.linkonce.s.* .sdata2 .sdata2.*)
_edata = ALIGN(16); /* Make sure _edata is >= _gp. */
} > sram

.bss :
{
. = ALIGN(4);
_fbss = .;
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
_end = .;
} > sram
}

PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram) - 4);
6 changes: 6 additions & 0 deletions riscv-zig-blink/src/fomu.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pub const MESSIBLE = @import("./fomu/messible.zig").MESSIBLE;
pub const REBOOT = @import("./fomu/reboot.zig").REBOOT;
pub const RGB = @import("./fomu/rgb.zig").RGB;
pub const TOUCH = @import("./fomu/touch.zig").TOUCH;

pub const start = @import("./fomu/start.zig");
52 changes: 52 additions & 0 deletions riscv-zig-blink/src/fomu/messible.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/// Messible: An Ansible for Messages
/// https://rm.fomu.im/messible.html
///
/// An Ansible is a system for instant communication across vast distances,
/// from a small portable device to a huge terminal far away. A Messible is
/// a message- passing system from embedded devices to a host system. You can
/// use it to get very simple printf()-style support over a debug channel.
///
/// The Messible assumes the host has a way to peek into the device’s memory
/// space. This is the case with the Wishbone bridge, which allows both the
/// device and the host to access the same memory.
///
/// At its core, a Messible is a FIFO. As long as the STATUS.FULL bit is 0,
/// the device can write data into the Messible by writing into the IN.
/// However, if this value is 1, you need to decide if you want to wait for it
/// to empty (if the other side is just slow), or if you want to drop the
/// message. From the host side, you need to read STATUS.HAVE to see if there
/// is data in the FIFO. If there is, read OUT to get the most recent byte,
/// which automatically advances the READ pointer.
pub const MESSIBLE = struct {
const base = 0xe0008000;

/// Write half of the FIFO to send data out the Messible. Writing to this register advances the write pointer automatically.
pub const IN = @intToPtr(*volatile u8, base + 0x0);

/// Read half of the FIFO to receive data on the Messible. Reading from this register advances the read pointer automatically.
pub const OUT = @intToPtr(*volatile u8, base + 0x4);

pub const STATUS = @intToPtr(*volatile packed struct {
/// if more data can fit into the IN FIFO.
FULL: bool,

/// if data can be read from the OUT FIFO.
HAVE: bool,
}, base + 0x8);

pub fn write(data: []const u8) usize {
for (data) |c, i| {
if (STATUS.*.FULL) return i;
OUT.* = c;
}
return data.len;
}

pub fn read(dst: []u8) usize {
for (dst) |*c, i| {
if (!STATUS.*.HAVE) return i;
c.* = IN.*;
}
return dst.len;
}
};
22 changes: 22 additions & 0 deletions riscv-zig-blink/src/fomu/reboot.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/// https://rm.fomu.im/reboot.html
pub const REBOOT = struct {
const base = 0xe0006000;

/// Provides support for rebooting the FPGA.
/// You can select which of the four images to reboot to.
pub const CTRL = @intToPtr(*volatile packed struct {
/// Which image to reboot to. SB_WARMBOOT supports four images that are configured at FPGA startup.
/// The bootloader is image 0, so set these bits to 0 to reboot back into the bootloader.
image: u2,

/// A reboot key used to prevent accidental reboots when writing to random areas of memory.
/// To initiate a reboot, set this to 0b101011.
key: u6,
}, base + 0x0);

/// This sets the reset vector for the VexRiscv.
/// This address will be used whenever the CPU is reset, for example
/// through a debug bridge. You should update this address whenever
/// you load a new program, to enable the debugger to run `mon reset`
pub const ADDR = @intToPtr(*volatile u32, base + 0x4);
};
55 changes: 55 additions & 0 deletions riscv-zig-blink/src/fomu/rgb.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/// https://rm.fomu.im/rgb.html
pub const RGB = struct {
const base = 0xe0006800;

/// This is the value for the SB_LEDDA_IP.DAT register.
/// It is directly written into the SB_LEDDA_IP hardware block, so you
/// should refer to http://www.latticesemi.com/view_document?document_id=50668.
/// The contents of this register are written to the address specified
/// in ADDR immediately upon writing this register.
pub const DAT = @intToPtr(*volatile u8, base + 0x0);

/// This register is directly connected to SB_LEDDA_IP.ADDR.
/// This register controls the address that is updated whenever DAT is written.
/// Writing to this register has no immediate effect – data isn’t written until the DAT register is written.
pub const ADDR = @intToPtr(*volatile u4, base + 0x4);

/// Control logic for the RGB LED and LEDDA hardware PWM LED block.
pub const CTRL = @intToPtr(*volatile packed struct {
/// Enable the fading pattern?
/// Connected to `SB_LEDDA_IP.LEDDEXE`.
EXE: bool,

/// Enable the current source?
/// Connected to `SB_RGBA_DRV.CURREN`.
CURREN: bool,

/// Enable the RGB PWM control logic?
/// Connected to `SB_RGBA_DRV.RGBLEDEN`.
RGBLEDEN: bool,

/// Enable raw control of the red LED via the RAW.R register.
RRAW: bool,

/// Enable raw control of the green LED via the RAW.G register.
GRAW: bool,

/// Enable raw control of the blue LED via the RAW.B register.
BRAW: bool,
}, base + 0x8);

/// Normally the hardware SB_LEDDA_IP block controls the brightness of the
/// LED, creating a gentle fading pattern.
/// However, by setting the appropriate bit in CTRL, it is possible to
/// manually control the three individual LEDs.
pub const RAW = @intToPtr(*volatile packed struct {
/// Red
R: bool,

/// Green
G: bool,

/// Blue
B: bool,
}, base + 0xc);
};
42 changes: 42 additions & 0 deletions riscv-zig-blink/src/fomu/start.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const root = @import("root");
const std = @import("std");

extern var _ftext: u8;
extern var _etext: u8;
extern var _frodata: u8 align(4);
extern var _erodata: u8 align(4);
extern var _fdata: u8 align(4);
extern var _gp: u8 align(16);
extern var _edata: u8 align(16);
extern var _fbss: u8 align(4);
extern var _ebss: u8 align(4);
extern var _end: u8;
extern var _fstack: u8;

pub fn _start() linksection(".text.start") callconv(.Naked) noreturn {
asm volatile (
\\ j over_magic
\\ .word 0xb469075a // Magic value for config flags
\\ .word 0x00000020 // USB_NO_RESET flag so we can attach the debugger
\\ over_magic:
);

// set the stack pointer to `&_fstack`
asm volatile (
\\la sp, _fstack + 4
);

const text = @ptrCast([*]u8, &_ftext)[0..(@ptrToInt(&_etext) - @ptrToInt(&_ftext))];
const rodata = @ptrCast([*]align(4) const u8, &_erodata)[0..(@ptrToInt(&_erodata) - @ptrToInt(&_frodata))];
const bss = @ptrCast([*]align(4) u8, &_fbss)[0..(@ptrToInt(&_ebss) - @ptrToInt(&_fbss))];
const data = @ptrCast([*]align(4) u8, &_fdata)[0..(@ptrToInt(&_edata) - @ptrToInt(&_fdata))];

// zero out bss
std.mem.set(u8, bss, 0);

// copy data from rodata to data
std.mem.copy(u8, data, rodata);

// call user's main
root.main();
}
13 changes: 13 additions & 0 deletions riscv-zig-blink/src/fomu/touch.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/// https://rm.fomu.im/touch.html
pub const TOUCH = struct {
const base = 0xe0005800;

/// Output values for pads 1-4
pub const TOUCH_O = @intToPtr(*volatile u4, base + 0x0);

/// Output enable control for pads 1-4
pub const TOUCH_OE = @intToPtr(*volatile u4, base + 0x4);

/// Input value for pads 1-4
pub const TOUCH_1 = @intToPtr(*volatile u4, base + 0x8);
};
32 changes: 32 additions & 0 deletions riscv-zig-blink/src/main.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const builtin = @import("builtin");
const std = @import("std");
const fomu = @import("./fomu.zig");

// export our _start symbol
comptime {
@export(fomu.start._start, .{ .name = "_start" });
}

pub fn panic(message: []const u8, stack_trace: ?*builtin.StackTrace) noreturn {
@setCold(true);
while (true) {}
}

pub fn main() noreturn {
// Turn on the green LED
fomu.RGB.CTRL.* = .{
.EXE = false,
.CURREN = true,
.RGBLEDEN = true,
.RRAW = true,
.GRAW = true,
.BRAW = true,
};
fomu.RGB.RAW.* = .{
.R = false,
.G = true,
.B = false,
};
while (true) {}
}

0 comments on commit 1ee0ab1

Please sign in to comment.