-
Notifications
You must be signed in to change notification settings - Fork 0
Adding a Verilog example using PicoSoC #39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ __pycache__/ | |
/build | ||
/mcu_soc/build | ||
/minimal/build | ||
/picosoc_verilog/build | ||
|
||
# testbenches | ||
*.vcd | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "picosoc_verilog/design/picorv32"] | ||
path = picosoc_verilog/design/picorv32 | ||
url = https://github.com/YosysHQ/picorv32 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# PicoSoC (Verilog) | ||
|
||
This example design shows how an existing Verilog design (picosoc) can be wrapped in a minimal layer of Amaranth and submitted to the ChipFlow platform. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[chipflow] | ||
project_name = "chipflow-examples-picosoc" | ||
|
||
[chipflow.top] | ||
soc = "design.design:MySoC" | ||
|
||
[chipflow.steps] | ||
software = "design.steps.software:MySoftwareStep" | ||
|
||
[chipflow.silicon] | ||
process = "sky130" | ||
package = "openframe" | ||
|
||
[chipflow.test] | ||
event_reference = "design/tests/events_reference.json" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import os | ||
|
||
from chipflow_lib.platforms.sim import SimPlatform | ||
|
||
from amaranth import Module, Instance, ClockSignal, ResetSignal | ||
from amaranth.lib import wiring | ||
from amaranth.lib.wiring import In, Out, flipped, connect | ||
|
||
from chipflow_lib.platforms import ( | ||
GPIOSignature, UARTSignature, QSPIFlashSignature, | ||
BinaryData, attach_data | ||
) | ||
|
||
__all__ = ["MySoC"] | ||
|
||
|
||
class MySoC(wiring.Component): | ||
def __init__(self): | ||
# Top level interfaces | ||
|
||
super().__init__({ | ||
"flash": Out(QSPIFlashSignature()), | ||
"uart_0": Out(UARTSignature()), | ||
"gpio_0": Out(GPIOSignature(pin_count=8)), | ||
}) | ||
|
||
def elaborate(self, platform): | ||
m = Module() | ||
|
||
base = os.path.dirname(__file__) | ||
|
||
verilog_sources = [ | ||
f"{base}/picosoc_asic_top.v", | ||
f"{base}/picorv32/picosoc/spimemio.v", | ||
f"{base}/picorv32/picosoc/simpleuart.v", | ||
f"{base}/picorv32/picosoc/picosoc.v", | ||
f"{base}/picorv32/picorv32.v", | ||
] | ||
|
||
if platform is not None: | ||
for verilog_file in verilog_sources: | ||
with open(verilog_file, 'r') as f: | ||
platform.add_file(verilog_file, f) | ||
|
||
m.submodules.soc = soc = Instance("picosoc_asic_top", | ||
# Clock and reset | ||
i_clk=ClockSignal(), | ||
i_resetn=~ResetSignal(), | ||
|
||
# UART | ||
o_ser_tx=self.uart_0.tx.o, | ||
i_ser_rx=self.uart_0.rx.i, | ||
|
||
# SPI flash | ||
o_flash_csb=self.flash.csn.o, | ||
o_flash_clk=self.flash.clk.o, | ||
|
||
o_flash_io0_oe=self.flash.d.oe[0], | ||
o_flash_io1_oe=self.flash.d.oe[1], | ||
o_flash_io2_oe=self.flash.d.oe[2], | ||
o_flash_io3_oe=self.flash.d.oe[3], | ||
|
||
o_flash_io0_do=self.flash.d.o[0], | ||
o_flash_io1_do=self.flash.d.o[1], | ||
o_flash_io2_do=self.flash.d.o[2], | ||
o_flash_io3_do=self.flash.d.o[3], | ||
|
||
i_flash_io0_di=self.flash.d.i[0], | ||
i_flash_io1_di=self.flash.d.i[1], | ||
i_flash_io2_di=self.flash.d.i[2], | ||
i_flash_io3_di=self.flash.d.i[3], | ||
|
||
# LEDs | ||
o_leds=self.gpio_0.gpio.o | ||
) | ||
|
||
# Hardwire GPIO to output enabled | ||
m.d.comb += self.gpio_0.gpio.oe.eq(0xFF) | ||
|
||
attach_data(self.flash, None, BinaryData(filename="software.bin", offset=0x00100000)) | ||
|
||
return m |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
/* | ||
* PicoSoC - A simple example SoC using PicoRV32 | ||
* | ||
* Copyright (C) 2017 Claire Xenia Wolf <[email protected]> | ||
* Copyright (C) 2025 Myrtle Shah <[email protected]> | ||
* | ||
* Permission to use, copy, modify, and/or distribute this software for any | ||
* purpose with or without fee is hereby granted, provided that the above | ||
* copyright notice and this permission notice appear in all copies. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
* | ||
*/ | ||
|
||
`define PICOSOC_MEM picosoc_asic_mem | ||
|
||
module picosoc_asic_top ( | ||
input clk, | ||
input resetn, | ||
|
||
output ser_tx, | ||
input ser_rx, | ||
|
||
output [7:0] leds, | ||
|
||
output flash_csb, | ||
output flash_clk, | ||
|
||
output flash_io0_oe, | ||
output flash_io1_oe, | ||
output flash_io2_oe, | ||
output flash_io3_oe, | ||
|
||
output flash_io0_do, | ||
output flash_io1_do, | ||
output flash_io2_do, | ||
output flash_io3_do, | ||
|
||
input flash_io0_di, | ||
input flash_io1_di, | ||
input flash_io2_di, | ||
input flash_io3_di | ||
); | ||
|
||
wire iomem_valid; | ||
reg iomem_ready; | ||
wire [3:0] iomem_wstrb; | ||
wire [31:0] iomem_addr; | ||
wire [31:0] iomem_wdata; | ||
reg [31:0] iomem_rdata; | ||
|
||
reg [31:0] gpio; | ||
assign leds = gpio; | ||
|
||
always @(posedge clk) begin | ||
if (!resetn) begin | ||
gpio <= 0; | ||
end else begin | ||
iomem_ready <= 0; | ||
if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 03) begin | ||
iomem_ready <= 1; | ||
iomem_rdata <= gpio; | ||
if (iomem_wstrb[0]) gpio[ 7: 0] <= iomem_wdata[ 7: 0]; | ||
if (iomem_wstrb[1]) gpio[15: 8] <= iomem_wdata[15: 8]; | ||
if (iomem_wstrb[2]) gpio[23:16] <= iomem_wdata[23:16]; | ||
if (iomem_wstrb[3]) gpio[31:24] <= iomem_wdata[31:24]; | ||
end | ||
end | ||
end | ||
|
||
picosoc soc ( | ||
.clk (clk ), | ||
.resetn (resetn ), | ||
|
||
.ser_tx (ser_tx ), | ||
.ser_rx (ser_rx ), | ||
|
||
.flash_csb (flash_csb ), | ||
.flash_clk (flash_clk ), | ||
|
||
.flash_io0_oe (flash_io0_oe), | ||
.flash_io1_oe (flash_io1_oe), | ||
.flash_io2_oe (flash_io2_oe), | ||
.flash_io3_oe (flash_io3_oe), | ||
|
||
.flash_io0_do (flash_io0_do), | ||
.flash_io1_do (flash_io1_do), | ||
.flash_io2_do (flash_io2_do), | ||
.flash_io3_do (flash_io3_do), | ||
|
||
.flash_io0_di (flash_io0_di), | ||
.flash_io1_di (flash_io1_di), | ||
.flash_io2_di (flash_io2_di), | ||
.flash_io3_di (flash_io3_di), | ||
|
||
.irq_5 (1'b0 ), | ||
.irq_6 (1'b0 ), | ||
.irq_7 (1'b0 ), | ||
|
||
.iomem_valid (iomem_valid ), | ||
.iomem_ready (iomem_ready ), | ||
.iomem_wstrb (iomem_wstrb ), | ||
.iomem_addr (iomem_addr ), | ||
.iomem_wdata (iomem_wdata ), | ||
.iomem_rdata (iomem_rdata ) | ||
); | ||
endmodule | ||
|
||
module picosoc_asic_mem #( | ||
parameter integer WORDS = 256 | ||
) ( | ||
input clk, | ||
input [3:0] wen, | ||
input [21:0] addr, | ||
input [31:0] wdata, | ||
output reg [31:0] rdata | ||
); | ||
reg [31:0] mem [0:WORDS-1]; | ||
|
||
always @(posedge clk) begin | ||
if (wen == 4'b0) | ||
rdata <= mem[addr]; | ||
if (wen[0]) mem[addr][ 7: 0] <= wdata[ 7: 0]; | ||
if (wen[1]) mem[addr][15: 8] <= wdata[15: 8]; | ||
if (wen[2]) mem[addr][23:16] <= wdata[23:16]; | ||
if (wen[3]) mem[addr][31:24] <= wdata[31:24]; | ||
end | ||
endmodule | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
*.o | ||
*.elf | ||
*.bin | ||
generated/ |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't think this should be necessary now? if the chipflow-lib impl doesnt do something you need, lets fix that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be a ton of work to get software building working with Verilog, and I don't think everyone is even going to want this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fair enough, see other comment.. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import os | ||
import sys | ||
from pathlib import Path | ||
import shutil | ||
|
||
from doit import create_after | ||
from doit.action import CmdAction | ||
import chipflow_lib.config | ||
|
||
|
||
BUILD_DIR = "./build/software" | ||
DESIGN_DIR = os.path.dirname(__file__) + "/.." | ||
RISCVCC = f"{sys.executable} -m ziglang cc -target riscv32-freestanding-musl" | ||
CINCLUDES = f"-I. -I{BUILD_DIR} -I{DESIGN_DIR}/software" | ||
LINKER_SCR = f"{DESIGN_DIR}/software/sections.lds" | ||
SOFTWARE_START = f"{DESIGN_DIR}/software/start.s" | ||
CFLAGS = f"-g -mcpu=baseline_rv32-a-c-d -mabi=ilp32 -Wl,--build-id=none,-Bstatic,-T," | ||
CFLAGS += f"{LINKER_SCR},--strip-debug -static -ffreestanding -nostdlib {CINCLUDES}" | ||
|
||
|
||
def task_gather_depencencies(): | ||
src_files = [] | ||
target_files = [] | ||
|
||
# Project dependencies | ||
rel_paths = _get_source_rel_paths(f"{DESIGN_DIR}/software", ["*.c", "*.h"]) | ||
for rel_path in rel_paths: | ||
src_files.append(f"{DESIGN_DIR}/software{rel_path}") | ||
target_files.append(f"{BUILD_DIR}/{rel_path}") | ||
|
||
def copy_files(): | ||
_create_build_dir() | ||
for i in range(len(src_files)): | ||
shutil.copyfile(src_files[i - 1], target_files[i - 1]) | ||
|
||
return { | ||
"actions": [(copy_files)], | ||
"file_dep": src_files, | ||
"targets": target_files, | ||
"verbosity": 2 | ||
} | ||
|
||
|
||
@create_after(executed="gather_depencencies", target_regex=".*/software\\.elf") | ||
def task_build_software_elf(): | ||
sources = [SOFTWARE_START] | ||
sources += _gather_source_paths(f"{BUILD_DIR}", ["*.c"]) | ||
|
||
sources_str = " ".join(sources) | ||
|
||
return { | ||
"actions": [f"{RISCVCC} {CFLAGS} -o {BUILD_DIR}/software.elf {sources_str}"], | ||
"file_dep": sources + [LINKER_SCR], | ||
"targets": [f"{BUILD_DIR}/software.elf"], | ||
"verbosity": 2 | ||
} | ||
|
||
|
||
@create_after(executed="build_software_elf", target_regex=".*/software\\.bin") | ||
def task_build_software(): | ||
return { | ||
"actions": [f"{sys.executable} -m ziglang objcopy -O binary " | ||
f"{BUILD_DIR}/software.elf {BUILD_DIR}/software.bin"], | ||
"file_dep": [f"{BUILD_DIR}/software.elf"], | ||
"targets": [f"{BUILD_DIR}/software.bin"], | ||
} | ||
|
||
|
||
def _create_build_dir(): | ||
Path(f"{BUILD_DIR}").mkdir(parents=True, exist_ok=True) | ||
|
||
|
||
def _get_source_rel_paths(source_dir, globs): | ||
abs_source_dir = str(Path(source_dir).absolute()) | ||
rel_paths = [] | ||
for glob in globs: | ||
source_paths = list(Path(abs_source_dir).glob(glob)) | ||
for source_path in source_paths: | ||
dst = str(source_path).replace(abs_source_dir, "") | ||
rel_paths.append(dst) | ||
|
||
return rel_paths | ||
|
||
|
||
def _gather_source_paths(source_dir, globs): | ||
sources = [] | ||
for glob in globs: | ||
source_paths = list(Path(source_dir).glob(glob)) | ||
for source_path in source_paths: | ||
sources.append(f"{source_dir}/" + str(source_path.name)) | ||
|
||
return sources |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, might be something worth putting in a toml description?