Compare commits

..

10 Commits

Author SHA1 Message Date
84695d44b4 Added base GOWIN eda script 2023-10-14 20:30:45 +02:00
da27f38f0f Added all subtle changes
Signed-off-by: Joppe Blondel <joppe@blondel.nl>
2022-10-14 21:39:56 +02:00
646440493f Return value acquisition from rmbuild fixed
Signed-off-by: Jojojoppe <joppe@blondel.nl>
2022-09-14 21:55:54 +02:00
78205b90f2 Some small bug fixes in toolchains
Signed-off-by: Joppe Blondel <joppe@blondel.nl>
2022-09-14 21:40:52 +02:00
1e8986f8a7 Fixed small bug in cosim.c
Signed-off-by: Joppe Blondel <joppe@blondel.nl>
2022-09-09 17:59:31 +02:00
346de9cdd4 Added new stuff to readme
Signed-off-by: Joppe Blondel <joppe@blondel.nl>
2022-09-09 17:55:07 +02:00
8f03d29894 First version of zynq cosimulation added
Signed-off-by: Joppe Blondel <joppe@blondel.nl>
2022-09-09 17:53:03 +02:00
e18a0c1762 Added qemu toolchain and created zynq ps targets
Signed-off-by: Joppe Blondel <joppe@blondel.nl>
2022-09-09 13:54:55 +02:00
15d7e8b801 Added gcc make toolchain for remote compilation
Signed-off-by: Joppe Blondel <joppe@blondel.nl>
2022-09-08 13:58:03 +02:00
7c5351b9c3 Added test firmware for zynq
Signed-off-by: Joppe Blondel <joppe@blondel.nl>
2022-09-08 13:29:11 +02:00
53 changed files with 4264 additions and 71 deletions

View File

@ -8,6 +8,9 @@ Remotesyn is a tool which proves a general abstraction for HDL/FPGA toolchains s
+ Xilinx VIVADO synthesis and bitstream generation [`VIVADO`]
+ Xilinx Vivado IP core generation [`VIVADO-IP`]
+ Xilinx xsim (Vivado) simulation (pre and post synthesis) [`xsim`]
+ Makefile build [`make`]
+ QEMU simulation (nographic mode) [`qemu`]
+ QuestaSim simulation [`questa`]
The HDL project is configured with a config file (in ini format) and should provide execution targets specified by a `[target.<target_name>]` tag with a toolchain setting (see the example directory for examples).

2
examples/GW1NSR-4C/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
OUT
BUILD

View File

@ -0,0 +1,8 @@
IO_LOC "led_o" 10;
IO_PORT "led_o" PULL_MODE=NONE DRIVE=8;
IO_LOC "reset_n_i" 15;
IO_PORT "reset_n_i" PULL_MODE=UP;
IO_LOC "clk_i" 45;
IO_PORT "clk_i" PULL_MODE=UP;

View File

@ -0,0 +1 @@
create_clock -name CLK_IN -period 37.037 -waveform {0 18.52} [get_ports {clk_i}]

View File

@ -0,0 +1,23 @@
module led_blink
(
input clk_i,
input reset_n_i,
output led_o
);
reg [23:0] counter;
reg polarity;
always@(posedge clk_i) begin
if (!reset_n_i)
counter <= 24'h00000;
else
counter <= counter + 1'b1;
if (counter == 24'hFFFFF)
polarity <= ~polarity;
end
assign led_o = polarity;
endmodule

View File

@ -0,0 +1,28 @@
[project]
name = gowin_project
version = 0.1
out_dir = OUT
build_dir = BUILD
[server]
hostname = localhost
port = 2020
privkey = /home/joppe/.ssh/id_rsa
pubkey = /home/joppe/.ssh/id_rsa.pub
# ######################################
# Basic synthesis
[target.synth]
toolchain = gowin
# Toolchain settings
family = GW1NSR-4C
device = GW1NSR-LV4CQN48PC6/I5
toplevel = led_blink
# Fileset
# files_vhdl =
files_verilog = RTL/toplevel.v
files_con = CON/io.cst
CON/io.sdc
# ######################################

View File

@ -0,0 +1,19 @@
# ZYNQ 7 series project
### Basic FPGA workflow
+ target `ip`: Generate IP blocks defined in the tcl files in the IP directory
+ target `synth`: Synthesize design
+ target `sim`: Behavioural simulation of part of the design
+ target `psim`: Post synthesis simulation of mentioned part of the design
### ZYNQ SoC workflos
+ target `firmware`: Compile the firmware running on the ARM core(s) with the `make` toolchain
+ target `firmsim`: Simulate the firmware with QEMU without PS/PL cosimulation with the `qemu` toolchain
+ target `devtree`: Compile the device tree for a PS/PL cosimulation with QEMU
+ target `cosim_ps`: PS part of the cosimulation. Must be ran first
+ target `cosim_pl`: PL part of the cosimulation. Must be ran in a separate terminal while the PS part is still running
### Notes:
Compilation with Xilinx provided gcc and binutils done with `xsc` can be problematic... This is the reason
Questasim is used for the cosimulation. If one would use the free Intel variant of Questasim post synthesis
simulation will not be possible. The attempt to get DPI-C working with xsim is not stopped!

View File

@ -0,0 +1,186 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/select.h>
#include <errno.h>
#include "remote-port-proto.h"
#define UNIX_PREFIX "unix:"
int fd;
uint8_t buf[4096];
struct rp_pkt_hdr * hdr = (struct rp_pkt_hdr*)buf;
struct rp_pkt * payload = (struct rp_pkt*)(buf);
int rp_pkt_id = 0;
struct rp_peer_state state;
size_t pkt_size;
FILE * log;
int still_to_write, still_to_read, datpointer;
uint32_t write_addr, read_addr;
int start_cosim(char * descr){
// Open socket
fd = socket(AF_UNIX, SOCK_STREAM, 0);
// Try to connect
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, descr + strlen(UNIX_PREFIX), sizeof addr.sun_path);
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) >= 0){
// log = fopen("cosim_log.txt", "w");
return 0;
}else{
close(fd);
return 1;
}
}
void end_cosim(){
close(fd);
// fclose(log);
}
int wait_cosim(uint32_t * retaddr, uint32_t * time){
// fprintf(log, "-->");
if(still_to_write){
*retaddr = write_addr;
// fprintf(log, "\r\nwrite [%08x] @ %d\r\n", *retaddr, *time);
return 1;
}else if(still_to_read){
*retaddr = read_addr;
// fprintf(log, "\r\nread [%08x] @ %d\r\n", *retaddr, *time);
return 2;
}else{
int n;
int retval = 0;
// Receive header
do{
n = recv(fd, hdr, sizeof(struct rp_pkt_hdr), 0);
} while(n<=0);
rp_decode_hdr(hdr);
// fprintf(log, " . ");
// Receive payload
if(hdr->len){
do{
n = recv(fd, hdr+1, hdr->len, 0);
} while(n<=0);
}
rp_decode_payload(payload);
// fprintf(log, "%d\r\n", hdr->cmd);
switch(hdr->cmd){
case RP_CMD_hello:{
rp_process_caps(&state, buf+payload->hello.caps.offset, payload->hello.caps.len);
// Send HELO packet
uint32_t caps[] = {
CAP_BUSACCESS_EXT_BASE
};
size_t s = rp_encode_hello_caps(rp_pkt_id++, 0, buf, 4, 3, caps, caps, sizeof(caps)/sizeof(uint32_t));
send(fd, buf, s, 0);
send(fd, caps, sizeof(caps), 0);
// fprintf(log, "hello\r\n");
} break;
case RP_CMD_interrupt:{
*time = (uint32_t) payload->interrupt.timestamp;
// fprintf(log, "interrupt @ %ld\r\n", payload->interrupt.timestamp);
} break;
case RP_CMD_write:{
int addr = payload->busaccess_ext_base.addr;
int len = payload->busaccess_ext_base.len;
uint64_t t = payload->busaccess_ext_base.timestamp;
if(len/4>1){
// Must be more than one write cycle
still_to_write = len/4-1;
write_addr = addr+4;
datpointer = 0;
}else{
still_to_write = 0;
}
retval = 1;
*retaddr = addr;
*time = (uint32_t)t;
// fprintf(log, "write [%08x] @ %d\r\n", *retaddr, *time);
// Respond to write
struct rp_encode_busaccess_in in = {0};
rp_encode_busaccess_in_rsp_init(&in, payload);
pkt_size = rp_encode_busaccess(&state, buf, &in);
} break;
case RP_CMD_read:{
int len = payload->busaccess_ext_base.len;
int addr = payload->busaccess_ext_base.addr;
uint64_t t = payload->busaccess_ext_base.timestamp;
if(len/4>1){
// Must be more than one write cycle
still_to_read = len/4-1;
read_addr = addr+4;
datpointer = 0;
}else{
still_to_read = 0;
}
retval = 2;
*retaddr = addr;
*time = (uint32_t)t;
// fprintf(log, "read [%08x] @ %d\r\n", *retaddr, *time);
// Respond to read
struct rp_encode_busaccess_in in = {0};
rp_encode_busaccess_in_rsp_init(&in, payload);
pkt_size = rp_encode_busaccess(&state, buf, &in);
} break;
case RP_CMD_sync:{
// Respond to sync
struct rp_pkt resp = {0};
size_t s = rp_encode_sync_resp(rp_pkt_id++, 0, &resp, payload->sync.timestamp);
uint64_t t = payload->sync.timestamp;
*time = (uint32_t)t;
send(fd, &resp, s, 0);
// fprintf(log, "SYNC @ %ld\r\n", payload->sync.timestamp);
} break;
}
return retval;
}
}
void read_cosim(unsigned int value){
unsigned int * dat = (unsigned int*)((void*)payload + sizeof(payload->busaccess_ext_base));
dat[datpointer] = value;
// fprintf(log, " -> %08x\r\n", value);
}
int write_cosim(){
unsigned int * dat = (unsigned int*)((void*)payload + sizeof(payload->busaccess_ext_base));
fprintf(log, " -> %08x\r\n", dat[datpointer]);
// return dat[datpointer];
}
void finalize_cosim(uint32_t timestamp){
if(still_to_write){
still_to_write--;
write_addr += 4;
datpointer++;
}else if(still_to_read){
still_to_read--;
read_addr += 4;
datpointer++;
}else{
payload->busaccess_ext_base.timestamp = (uint64_t) timestamp;
send(fd, buf, pkt_size, 0);
}
// fprintf(log, "finalize @ %d\r\n<--\r\n", timestamp);
}

View File

@ -0,0 +1,513 @@
/*
* Remote-port protocol
*
* Copyright (c) 2013 Xilinx Inc
* Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _DEFAULT_SOURCE
# define _DEFAULT_SOURCE
#endif
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <assert.h>
#include "remote-port-proto.h"
#undef MIN
#define MIN(x, y) (x < y ? x : y)
#if defined(__linux__)
# include <endian.h>
#elif defined(__FreeBSD__) || defined(__NetBSD__)
# include <sys/endian.h>
#elif defined(__OpenBSD__)
# include <sys/types.h>
# define be16toh(x) betoh16(x)
# define be32toh(x) betoh32(x)
# define be64toh(x) betoh64(x)
#elif defined(__WIN32)
/* We assume little endian. */
# define htobe64(x) _byteswap_uint64(x)
# define htobe32(x) _byteswap_ulong(x)
# define htobe16(x) _byteswap_ushort(x)
# define be64toh(x) _byteswap_uint64(x)
# define be32toh(x) _byteswap_ulong(x)
# define be16toh(x) _byteswap_ushort(x)
#endif
/* Fallback for ancient Linux systems. */
#ifndef htobe64
# include <byteswap.h>
# if __BYTE_ORDER == __LITTLE_ENDIAN
# define htobe64(x) bswap_64(x)
# define htobe32(x) bswap_32(x)
# define htobe16(x) bswap_16(x)
# define be64toh(x) bswap_64(x)
# define be32toh(x) bswap_32(x)
# define be16toh(x) bswap_16(x)
# else
# define htobe64(x) x
# define htobe32(x) x
# define htobe16(x) x
# define be64toh(x) x
# define be32toh(x) x
# define be16toh(x) x
# endif
#endif
static const char *rp_cmd_names[RP_CMD_max + 1] = {
[RP_CMD_nop] = "nop",
[RP_CMD_hello] = "hello",
[RP_CMD_cfg] = "cfg",
[RP_CMD_read] = "read",
[RP_CMD_write] = "write",
[RP_CMD_interrupt] = "interrupt",
[RP_CMD_sync] = "sync",
[RP_CMD_ats_req] = "ats_request",
[RP_CMD_ats_inv] = "ats_invalidation",
};
const char *rp_cmd_to_string(enum rp_cmd cmd)
{
assert(cmd <= RP_CMD_max);
return rp_cmd_names[cmd];
}
int rp_decode_hdr(struct rp_pkt *pkt)
{
int used = 0;
pkt->hdr.cmd = be32toh(pkt->hdr.cmd);
pkt->hdr.len = be32toh(pkt->hdr.len);
pkt->hdr.id = be32toh(pkt->hdr.id);
pkt->hdr.flags = be32toh(pkt->hdr.flags);
pkt->hdr.dev = be32toh(pkt->hdr.dev);
used += sizeof pkt->hdr;
return used;
}
int rp_decode_payload(struct rp_pkt *pkt)
{
int used = 0;
/* Master_id has an odd decoding due to historical reasons. */
uint64_t master_id;
switch (pkt->hdr.cmd) {
case RP_CMD_hello:
assert(pkt->hdr.len >= sizeof pkt->hello.version);
pkt->hello.version.major = be16toh(pkt->hello.version.major);
pkt->hello.version.minor = be16toh(pkt->hello.version.minor);
used += sizeof pkt->hello.version;
if ((pkt->hdr.len - used) >= sizeof pkt->hello.caps) {
void *offset;
int i;
pkt->hello.caps.offset = be32toh(pkt->hello.caps.offset);
pkt->hello.caps.len = be16toh(pkt->hello.caps.len);
offset = (char *)pkt + pkt->hello.caps.offset;
for (i = 0; i < pkt->hello.caps.len; i++) {
uint32_t cap;
/* We don't know if offset is 32bit aligned so use
* memcpy to do the endian conversion. */
memcpy(&cap, offset + i * sizeof cap, sizeof cap);
cap = be32toh(cap);
memcpy(offset + i * sizeof cap, &cap, sizeof cap);
}
used += sizeof pkt->hello.caps;
} else {
pkt->hello.caps.offset = 0;
pkt->hello.caps.len = 0;
}
/* Consume everything ignoring additional headers we do not yet
* know about. */
used = pkt->hdr.len;
break;
case RP_CMD_write:
case RP_CMD_read:
assert(pkt->hdr.len >= sizeof pkt->busaccess - sizeof pkt->hdr);
pkt->busaccess.timestamp = be64toh(pkt->busaccess.timestamp);
pkt->busaccess.addr = be64toh(pkt->busaccess.addr);
pkt->busaccess.master_id = be16toh(pkt->busaccess.master_id);
pkt->busaccess.attributes = be64toh(pkt->busaccess.attributes);
pkt->busaccess.len = be32toh(pkt->busaccess.len);
pkt->busaccess.width = be32toh(pkt->busaccess.width);
pkt->busaccess.stream_width = be32toh(pkt->busaccess.stream_width);
master_id = be16toh(pkt->busaccess.master_id);
used += sizeof pkt->busaccess - sizeof pkt->hdr;
if (pkt->busaccess.attributes & RP_BUS_ATTR_EXT_BASE) {
struct rp_pkt_busaccess_ext_base *pext = &pkt->busaccess_ext_base;
assert(pkt->hdr.len >= sizeof *pext - sizeof pkt->hdr);
master_id |= (uint64_t)be16toh(pext->master_id_31_16) << 16;
master_id |= (uint64_t)be32toh(pext->master_id_63_32) << 32;
pext->data_offset = be32toh(pext->data_offset);
pext->next_offset = be32toh(pext->next_offset);
pext->byte_enable_offset = be32toh(pext->byte_enable_offset);
pext->byte_enable_len = be32toh(pext->byte_enable_len);
used += sizeof *pext - sizeof pkt->busaccess;
}
pkt->busaccess.master_id = master_id;
break;
case RP_CMD_interrupt:
pkt->interrupt.timestamp = be64toh(pkt->interrupt.timestamp);
pkt->interrupt.vector = be64toh(pkt->interrupt.vector);
pkt->interrupt.line = be32toh(pkt->interrupt.line);
pkt->interrupt.val = pkt->interrupt.val;
used += pkt->hdr.len;
break;
case RP_CMD_sync:
pkt->sync.timestamp = be64toh(pkt->interrupt.timestamp);
used += pkt->hdr.len;
break;
case RP_CMD_ats_req:
case RP_CMD_ats_inv:
pkt->ats.attributes = be64toh(pkt->ats.attributes);
pkt->ats.addr = be64toh(pkt->ats.addr);
pkt->ats.len = be64toh(pkt->ats.len);
pkt->ats.result = be32toh(pkt->ats.result);
break;
default:
break;
}
return used;
}
void rp_encode_hdr(struct rp_pkt_hdr *hdr, uint32_t cmd, uint32_t id,
uint32_t dev, uint32_t len, uint32_t flags)
{
hdr->cmd = htobe32(cmd);
hdr->len = htobe32(len);
hdr->id = htobe32(id);
hdr->dev = htobe32(dev);
hdr->flags = htobe32(flags);
}
size_t rp_encode_hello_caps(uint32_t id, uint32_t dev, struct rp_pkt_hello *pkt,
uint16_t version_major, uint16_t version_minor,
uint32_t *caps, uint32_t *caps_out,
uint32_t caps_len)
{
size_t psize = sizeof *pkt + sizeof caps[0] * caps_len;
unsigned int i;
rp_encode_hdr(&pkt->hdr, RP_CMD_hello, id, dev,
psize - sizeof pkt->hdr, 0);
pkt->version.major = htobe16(version_major);
pkt->version.minor = htobe16(version_minor);
/* Feature list is appeneded right after the hello packet. */
pkt->caps.offset = htobe32(sizeof *pkt);
pkt->caps.len = htobe16(caps_len);
for (i = 0; i < caps_len; i++) {
uint32_t cap;
cap = caps[i];
caps_out[i] = htobe32(cap);
}
return sizeof *pkt;
}
static void rp_encode_busaccess_common(struct rp_pkt_busaccess *pkt,
int64_t clk, uint16_t master_id,
uint64_t addr, uint64_t attr, uint32_t size,
uint32_t width, uint32_t stream_width)
{
pkt->timestamp = htobe64(clk);
pkt->master_id = htobe16(master_id);
pkt->addr = htobe64(addr);
pkt->attributes = htobe64(attr);
pkt->len = htobe32(size);
pkt->width = htobe32(width);
pkt->stream_width = htobe32(stream_width);
}
size_t rp_encode_read(uint32_t id, uint32_t dev,
struct rp_pkt_busaccess *pkt,
int64_t clk, uint16_t master_id,
uint64_t addr, uint64_t attr, uint32_t size,
uint32_t width, uint32_t stream_width)
{
rp_encode_hdr(&pkt->hdr, RP_CMD_read, id, dev,
sizeof *pkt - sizeof pkt->hdr, 0);
rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
size, width, stream_width);
return sizeof *pkt;
}
size_t rp_encode_read_resp(uint32_t id, uint32_t dev,
struct rp_pkt_busaccess *pkt,
int64_t clk, uint16_t master_id,
uint64_t addr, uint64_t attr, uint32_t size,
uint32_t width, uint32_t stream_width)
{
rp_encode_hdr(&pkt->hdr, RP_CMD_read, id, dev,
sizeof *pkt - sizeof pkt->hdr + size, RP_PKT_FLAGS_response);
rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
size, width, stream_width);
return sizeof *pkt + size;
}
size_t rp_encode_write(uint32_t id, uint32_t dev,
struct rp_pkt_busaccess *pkt,
int64_t clk, uint16_t master_id,
uint64_t addr, uint64_t attr, uint32_t size,
uint32_t width, uint32_t stream_width)
{
rp_encode_hdr(&pkt->hdr, RP_CMD_write, id, dev,
sizeof *pkt - sizeof pkt->hdr + size, 0);
rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
size, width, stream_width);
return sizeof *pkt;
}
size_t rp_encode_write_resp(uint32_t id, uint32_t dev,
struct rp_pkt_busaccess *pkt,
int64_t clk, uint16_t master_id,
uint64_t addr, uint64_t attr, uint32_t size,
uint32_t width, uint32_t stream_width)
{
rp_encode_hdr(&pkt->hdr, RP_CMD_write, id, dev,
sizeof *pkt - sizeof pkt->hdr, RP_PKT_FLAGS_response);
rp_encode_busaccess_common(pkt, clk, master_id, addr, attr,
size, width, stream_width);
return sizeof *pkt;
}
/* New API for extended header. */
size_t rp_encode_busaccess(struct rp_peer_state *peer,
struct rp_pkt_busaccess_ext_base *pkt,
struct rp_encode_busaccess_in *in) {
struct rp_pkt_busaccess *pkt_v4_0 = (void *) pkt;
uint32_t hsize = 0;
uint32_t ret_size = 0;
/* Allocate packet space. */
if (in->cmd == RP_CMD_write && !(in->flags & RP_PKT_FLAGS_response)) {
hsize = in->size;
}
if (in->cmd == RP_CMD_read && (in->flags & RP_PKT_FLAGS_response)) {
hsize = in->size;
ret_size = in->size;
}
/* If peer does not support the busaccess base extensions, use the
* old layout. For responses, what matters is if we're responding
* to a packet with the extensions.
*/
if (!peer->caps.busaccess_ext_base && !(in->attr & RP_BUS_ATTR_EXT_BASE)) {
/* Old layout. */
assert(in->master_id < UINT16_MAX);
rp_encode_hdr(&pkt->hdr, in->cmd, in->id, in->dev,
sizeof *pkt_v4_0 - sizeof pkt->hdr + hsize, in->flags);
rp_encode_busaccess_common(pkt_v4_0, in->clk, in->master_id,
in->addr, in->attr,
in->size, in->width, in->stream_width);
return sizeof *pkt_v4_0 + ret_size;
}
/* Encode the extended fields. */
pkt->master_id_31_16 = htobe16(in->master_id >> 16);
pkt->master_id_63_32 = htobe32(in->master_id >> 32);
/* We always put data right after the header. */
pkt->data_offset = htobe32(sizeof *pkt);
pkt->next_offset = 0;
pkt->byte_enable_offset = htobe32(sizeof *pkt + hsize);
pkt->byte_enable_len = htobe32(in->byte_enable_len);
hsize += in->byte_enable_len;
rp_encode_hdr(&pkt->hdr, in->cmd, in->id, in->dev,
sizeof *pkt - sizeof pkt->hdr + hsize, in->flags);
rp_encode_busaccess_common(pkt_v4_0, in->clk, in->master_id, in->addr,
in->attr | RP_BUS_ATTR_EXT_BASE,
in->size, in->width, in->stream_width);
return sizeof *pkt + ret_size;
}
size_t rp_encode_interrupt_f(uint32_t id, uint32_t dev,
struct rp_pkt_interrupt *pkt,
int64_t clk,
uint32_t line, uint64_t vector, uint8_t val,
uint32_t flags)
{
rp_encode_hdr(&pkt->hdr, RP_CMD_interrupt, id, dev,
sizeof *pkt - sizeof pkt->hdr, flags);
pkt->timestamp = htobe64(clk);
pkt->vector = htobe64(vector);
pkt->line = htobe32(line);
pkt->val = val;
return sizeof *pkt;
}
size_t rp_encode_interrupt(uint32_t id, uint32_t dev,
struct rp_pkt_interrupt *pkt,
int64_t clk,
uint32_t line, uint64_t vector, uint8_t val)
{
return rp_encode_interrupt_f(id, dev, pkt, clk, line, vector, val, 0);
}
static size_t rp_encode_ats_common(uint32_t cmd, uint32_t id, uint32_t dev,
struct rp_pkt_ats *pkt,
int64_t clk, uint64_t attr, uint64_t addr,
uint64_t len, uint64_t result, uint32_t flags)
{
rp_encode_hdr(&pkt->hdr, cmd, id, dev,
sizeof *pkt - sizeof pkt->hdr, flags);
pkt->timestamp = htobe64(clk);
pkt->attributes = htobe64(attr);
pkt->addr = htobe64(addr);
pkt->len = htobe64(len);
pkt->result = htobe32(result);
return sizeof *pkt;
}
size_t rp_encode_ats_req(uint32_t id, uint32_t dev,
struct rp_pkt_ats *pkt,
int64_t clk, uint64_t attr, uint64_t addr,
uint64_t len, uint64_t result, uint32_t flags)
{
return rp_encode_ats_common(RP_CMD_ats_req, id, dev,
pkt, clk, attr,
addr, len, result, flags);
}
size_t rp_encode_ats_inv(uint32_t id, uint32_t dev,
struct rp_pkt_ats *pkt,
int64_t clk, uint64_t attr, uint64_t addr,
uint64_t len, uint64_t result, uint32_t flags)
{
return rp_encode_ats_common(RP_CMD_ats_inv, id, dev,
pkt, clk, attr,
addr, len, result, flags);
}
static size_t rp_encode_sync_common(uint32_t id, uint32_t dev,
struct rp_pkt_sync *pkt,
int64_t clk, uint32_t flags)
{
rp_encode_hdr(&pkt->hdr, RP_CMD_sync, id, dev,
sizeof *pkt - sizeof pkt->hdr, flags);
pkt->timestamp = htobe64(clk);
return sizeof *pkt;
}
size_t rp_encode_sync(uint32_t id, uint32_t dev,
struct rp_pkt_sync *pkt,
int64_t clk)
{
return rp_encode_sync_common(id, dev, pkt, clk, 0);
}
size_t rp_encode_sync_resp(uint32_t id, uint32_t dev,
struct rp_pkt_sync *pkt,
int64_t clk)
{
return rp_encode_sync_common(id, dev, pkt, clk, RP_PKT_FLAGS_response);
}
void rp_process_caps(struct rp_peer_state *peer,
void *caps, size_t caps_len)
{
int i;
assert(peer->caps.busaccess_ext_base == false);
for (i = 0; i < caps_len; i++) {
uint32_t cap;
memcpy(&cap, caps + i * sizeof cap, sizeof cap);
switch (cap) {
case CAP_BUSACCESS_EXT_BASE:
peer->caps.busaccess_ext_base = true;
break;
case CAP_BUSACCESS_EXT_BYTE_EN:
peer->caps.busaccess_ext_byte_en = true;
break;
case CAP_WIRE_POSTED_UPDATES:
peer->caps.wire_posted_updates = true;
break;
case CAP_ATS:
peer->caps.ats = true;
break;
}
}
}
void rp_dpkt_alloc(RemotePortDynPkt *dpkt, size_t size)
{
if (dpkt->size < size) {
char *u8;
dpkt->pkt = realloc(dpkt->pkt, size);
u8 = (void *) dpkt->pkt;
memset(u8 + dpkt->size, 0, size - dpkt->size);
dpkt->size = size;
}
}
void rp_dpkt_swap(RemotePortDynPkt *a, RemotePortDynPkt *b)
{
struct rp_pkt *tmp_pkt;
size_t tmp_size;
tmp_pkt = a->pkt;
tmp_size = a->size;
a->pkt = b->pkt;
a->size = b->size;
b->pkt = tmp_pkt;
b->size = tmp_size;
}
bool rp_dpkt_is_valid(RemotePortDynPkt *dpkt)
{
return dpkt->size > 0 && dpkt->pkt->hdr.len;
}
void rp_dpkt_invalidate(RemotePortDynPkt *dpkt)
{
assert(rp_dpkt_is_valid(dpkt));
dpkt->pkt->hdr.len = 0;
}
inline void rp_dpkt_free(RemotePortDynPkt *dpkt)
{
dpkt->size = 0;
free(dpkt->pkt);
}

View File

@ -0,0 +1,534 @@
/*
* QEMU remote port protocol parts.
*
* Copyright (c) 2013 Xilinx Inc
* Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef REMOTE_PORT_PROTO_H__
#define REMOTE_PORT_PROTO_H__
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>
/*
* Remote-Port (RP) is an inter-simulator protocol. It assumes a reliable
* point to point communcation with the remote simulation environment.
*
* Setup
* In the SETUP phase a mandatory HELLO packet is exchanged with optional
* CFG packets following. HELLO packets are useful to ensure that both
* sides are speaking the same protocol and using compatible versions.
*
* CFG packets are used to negotiate configuration options. At the moment
* these remain unimplemented.
*
* Once the session is up, communication can start through various other
* commands. The list can be found further down this document.
* Commands are carried over RP packets. Every RP packet contains a header
* with length, flags and an ID to track potential responses.
* The header is followed by a packet specific payload. You'll find the
* details of the various commands packet layouts here. Some commands can
* carry data/blobs in their payload.
*/
#define RP_VERSION_MAJOR 4
#define RP_VERSION_MINOR 3
#if defined(_WIN32) && defined(__MINGW32__)
/* mingw GCC has a bug with packed attributes. */
#define PACKED __attribute__ ((gcc_struct, packed))
#else
#define PACKED __attribute__ ((packed))
#endif
/* Could be auto generated. */
enum rp_cmd {
RP_CMD_nop = 0,
RP_CMD_hello = 1,
RP_CMD_cfg = 2,
RP_CMD_read = 3,
RP_CMD_write = 4,
RP_CMD_interrupt = 5,
RP_CMD_sync = 6,
RP_CMD_ats_req = 7,
RP_CMD_ats_inv = 8,
RP_CMD_max = 8
};
enum {
RP_OPT_quantum = 0,
};
struct rp_cfg_state {
uint64_t quantum;
};
enum {
RP_PKT_FLAGS_optional = 1 << 0,
RP_PKT_FLAGS_response = 1 << 1,
/* Posted hint.
* When set this means that the receiver is not required to respond to
* the message. Since it's just a hint, the sender must be prepared to
* drop responses. Note that since flags are echoed back in responses
* a response to a posted packet will be easy to identify early in the
* protocol stack.
*/
RP_PKT_FLAGS_posted = 1 << 2,
};
struct rp_pkt_hdr {
uint32_t cmd;
uint32_t len;
uint32_t id;
uint32_t flags;
uint32_t dev;
} PACKED;
struct rp_pkt_cfg {
struct rp_pkt_hdr hdr;
uint32_t opt;
uint8_t set;
} PACKED;
struct rp_version {
uint16_t major;
uint16_t minor;
} PACKED;
struct rp_capabilities {
/* Offset from start of packet. */
uint32_t offset;
uint16_t len;
uint16_t reserved0;
} PACKED;
enum {
CAP_BUSACCESS_EXT_BASE = 1, /* New header layout. */
CAP_BUSACCESS_EXT_BYTE_EN = 2, /* Support for Byte Enables. */
/*
* Originally, all interrupt/wire updates over remote-port were posted.
* This turned out to be a bad idea. To fix it without breaking backwards
* compatibility, we add the WIRE Posted updates capability.
*
* If the peer supportes this, it will respect the RP_PKT_FLAGS_posted
* flag. If the peer doesn't support this capability, senders need to
* be aware that the peer will not respond to wire updates regardless
* of the posted header-flag.
*/
CAP_WIRE_POSTED_UPDATES = 3,
CAP_ATS = 4, /* Address translation services */
};
struct rp_pkt_hello {
struct rp_pkt_hdr hdr;
struct rp_version version;
struct rp_capabilities caps;
} PACKED;
enum {
/* Remote port responses. */
RP_RESP_OK = 0x0,
RP_RESP_BUS_GENERIC_ERROR = 0x1,
RP_RESP_ADDR_ERROR = 0x2,
RP_RESP_MAX = 0xF,
};
enum {
RP_BUS_ATTR_EOP = (1 << 0),
RP_BUS_ATTR_SECURE = (1 << 1),
RP_BUS_ATTR_EXT_BASE = (1 << 2),
RP_BUS_ATTR_PHYS_ADDR = (1 << 3),
/*
* Bits [11:8] are allocated for storing transaction response codes.
* These new response codes are backward compatible as existing
* implementations will not set/read these bits.
* For existing implementations, these bits will be zero which is RESP_OKAY.
*/
RP_BUS_RESP_SHIFT = 8,
RP_BUS_RESP_MASK = (RP_RESP_MAX << RP_BUS_RESP_SHIFT),
};
struct rp_pkt_busaccess {
struct rp_pkt_hdr hdr;
uint64_t timestamp;
uint64_t attributes;
uint64_t addr;
/* Length in bytes. */
uint32_t len;
/* Width of each beat in bytes. Set to zero for unknown (let the remote
side choose). */
uint32_t width;
/* Width of streaming, must be a multiple of width.
addr should repeat itself around this width. Set to same as len
for incremental (normal) accesses. In bytes. */
uint32_t stream_width;
/* Implementation specific source or master-id. */
uint16_t master_id;
} PACKED;
/* This is the new extended busaccess packet layout. */
struct rp_pkt_busaccess_ext_base {
struct rp_pkt_hdr hdr;
uint64_t timestamp;
uint64_t attributes;
uint64_t addr;
/* Length in bytes. */
uint32_t len;
/* Width of each beat in bytes. Set to zero for unknown (let the remote
side choose). */
uint32_t width;
/* Width of streaming, must be a multiple of width.
addr should repeat itself around this width. Set to same as len
for incremental (normal) accesses. In bytes. */
uint32_t stream_width;
/* Implementation specific source or master-id. */
uint16_t master_id;
/* ---- End of 4.0 base busaccess. ---- */
uint16_t master_id_31_16; /* MasterID bits [31:16]. */
uint32_t master_id_63_32; /* MasterID bits [63:32]. */
/* ---------------------------------------------------
* Since hdr is 5 x 32bit, we are now 64bit aligned. */
uint32_t data_offset; /* Offset to data from start of pkt. */
uint32_t next_offset; /* Offset to next extension. 0 if none. */
uint32_t byte_enable_offset;
uint32_t byte_enable_len;
/* ---- End of CAP_BUSACCESS_EXT_BASE. ---- */
/* If new features are needed that may always occupy space
* in the header, then add a new capability and extend the
* this area with new fields.
* Will help receivers find data_offset and next offset,
* even those that don't know about extended fields.
*/
} PACKED;
struct rp_pkt_interrupt {
struct rp_pkt_hdr hdr;
uint64_t timestamp;
uint64_t vector;
uint32_t line;
uint8_t val;
} PACKED;
struct rp_pkt_sync {
struct rp_pkt_hdr hdr;
uint64_t timestamp;
} PACKED;
enum {
RP_ATS_ATTR_exec = 1 << 0,
RP_ATS_ATTR_read = 1 << 1,
RP_ATS_ATTR_write = 1 << 2,
};
enum {
RP_ATS_RESULT_ok = 0,
RP_ATS_RESULT_error = 1,
};
struct rp_pkt_ats {
struct rp_pkt_hdr hdr;
uint64_t timestamp;
uint64_t attributes;
uint64_t addr;
uint64_t len;
uint32_t result;
uint64_t reserved0;
uint64_t reserved1;
uint64_t reserved2;
uint64_t reserved3;
} PACKED;
struct rp_pkt {
union {
struct rp_pkt_hdr hdr;
struct rp_pkt_hello hello;
struct rp_pkt_busaccess busaccess;
struct rp_pkt_busaccess_ext_base busaccess_ext_base;
struct rp_pkt_interrupt interrupt;
struct rp_pkt_sync sync;
struct rp_pkt_ats ats;
};
};
struct rp_peer_state {
void *opaque;
struct rp_pkt pkt;
bool hdr_used;
struct rp_version version;
struct {
bool busaccess_ext_base;
bool busaccess_ext_byte_en;
bool wire_posted_updates;
bool ats;
} caps;
/* Used to normalize our clk. */
int64_t clk_base;
struct rp_cfg_state local_cfg;
struct rp_cfg_state peer_cfg;
};
const char *rp_cmd_to_string(enum rp_cmd cmd);
int rp_decode_hdr(struct rp_pkt *pkt);
int rp_decode_payload(struct rp_pkt *pkt);
void rp_encode_hdr(struct rp_pkt_hdr *hdr,
uint32_t cmd, uint32_t id, uint32_t dev, uint32_t len,
uint32_t flags);
/*
* caps is a an array of supported capabilities by the implementor.
* caps_out is the encoded (network byte order) version of the
* same array. It should be sent to the peer after the hello packet.
*/
size_t rp_encode_hello_caps(uint32_t id, uint32_t dev, struct rp_pkt_hello *pkt,
uint16_t version_major, uint16_t version_minor,
uint32_t *caps, uint32_t *features_out,
uint32_t features_len);
/* rp_encode_hello is deprecated in favor of hello_caps. */
static inline size_t __attribute__ ((deprecated))
rp_encode_hello(uint32_t id, uint32_t dev, struct rp_pkt_hello *pkt,
uint16_t version_major, uint16_t version_minor) {
return rp_encode_hello_caps(id, dev, pkt, version_major, version_minor,
NULL, NULL, 0);
}
static inline void *__attribute__ ((deprecated))
rp_busaccess_dataptr(struct rp_pkt_busaccess *pkt)
{
/* Right after the packet. */
return pkt + 1;
}
/*
* rp_busaccess_rx_dataptr
*
* Predicts the dataptr for a packet to be transmitted.
* This should only be used if you are trying to keep
* the entire packet in a linear buffer.
*/
static inline unsigned char *
rp_busaccess_tx_dataptr(struct rp_peer_state *peer,
struct rp_pkt_busaccess_ext_base *pkt)
{
unsigned char *p = (unsigned char *) pkt;
if (peer->caps.busaccess_ext_base) {
/* We always put our data right after the header. */
return p + sizeof *pkt;
} else {
/* Right after the old packet layout. */
return p + sizeof(struct rp_pkt_busaccess);
}
}
/*
* rp_busaccess_rx_dataptr
*
* Extracts the dataptr from a received packet.
*/
static inline unsigned char *
rp_busaccess_rx_dataptr(struct rp_peer_state *peer,
struct rp_pkt_busaccess_ext_base *pkt)
{
unsigned char *p = (unsigned char *) pkt;
if (pkt->attributes & RP_BUS_ATTR_EXT_BASE) {
return p + pkt->data_offset;
} else {
/* Right after the old packet layout. */
return p + sizeof(struct rp_pkt_busaccess);
}
}
static inline unsigned char *
rp_busaccess_byte_en_ptr(struct rp_peer_state *peer,
struct rp_pkt_busaccess_ext_base *pkt)
{
unsigned char *p = (unsigned char *) pkt;
if ((pkt->attributes & RP_BUS_ATTR_EXT_BASE)
&& pkt->byte_enable_len) {
assert(pkt->byte_enable_offset >= sizeof *pkt);
assert(pkt->byte_enable_offset + pkt->byte_enable_len
<= pkt->hdr.len + sizeof pkt->hdr);
return p + pkt->byte_enable_offset;
}
return NULL;
}
size_t __attribute__ ((deprecated))
rp_encode_read(uint32_t id, uint32_t dev,
struct rp_pkt_busaccess *pkt,
int64_t clk, uint16_t master_id,
uint64_t addr, uint64_t attr, uint32_t size,
uint32_t width, uint32_t stream_width);
size_t __attribute__ ((deprecated))
rp_encode_read_resp(uint32_t id, uint32_t dev,
struct rp_pkt_busaccess *pkt,
int64_t clk, uint16_t master_id,
uint64_t addr, uint64_t attr, uint32_t size,
uint32_t width, uint32_t stream_width);
size_t __attribute__ ((deprecated))
rp_encode_write(uint32_t id, uint32_t dev,
struct rp_pkt_busaccess *pkt,
int64_t clk, uint16_t master_id,
uint64_t addr, uint64_t attr, uint32_t size,
uint32_t width, uint32_t stream_width);
size_t __attribute__ ((deprecated))
rp_encode_write_resp(uint32_t id, uint32_t dev,
struct rp_pkt_busaccess *pkt,
int64_t clk, uint16_t master_id,
uint64_t addr, uint64_t attr, uint32_t size,
uint32_t width, uint32_t stream_width);
struct rp_encode_busaccess_in {
uint32_t cmd;
uint32_t id;
uint32_t flags;
uint32_t dev;
int64_t clk;
uint64_t master_id;
uint64_t addr;
uint64_t attr;
uint32_t size;
uint32_t width;
uint32_t stream_width;
uint32_t byte_enable_len;
};
/* Prepare encode_busaccess input parameters for a packet response. */
static inline void
rp_encode_busaccess_in_rsp_init(struct rp_encode_busaccess_in *in,
struct rp_pkt *pkt) {
memset(in, 0, sizeof *in);
in->cmd = pkt->hdr.cmd;
in->id = pkt->hdr.id;
in->flags = pkt->hdr.flags | RP_PKT_FLAGS_response;
in->dev = pkt->hdr.dev;
/* FIXME: Propagate all master_id fields? */
in->master_id = pkt->busaccess.master_id;
in->addr = pkt->busaccess.addr;
in->size = pkt->busaccess.len;
in->width = pkt->busaccess.width;
in->stream_width = pkt->busaccess.stream_width;
in->byte_enable_len = 0;
}
size_t rp_encode_busaccess(struct rp_peer_state *peer,
struct rp_pkt_busaccess_ext_base *pkt,
struct rp_encode_busaccess_in *in);
size_t rp_encode_interrupt_f(uint32_t id, uint32_t dev,
struct rp_pkt_interrupt *pkt,
int64_t clk,
uint32_t line, uint64_t vector, uint8_t val,
uint32_t flags);
size_t rp_encode_interrupt(uint32_t id, uint32_t dev,
struct rp_pkt_interrupt *pkt,
int64_t clk,
uint32_t line, uint64_t vector, uint8_t val);
size_t rp_encode_sync(uint32_t id, uint32_t dev,
struct rp_pkt_sync *pkt,
int64_t clk);
size_t rp_encode_sync_resp(uint32_t id, uint32_t dev,
struct rp_pkt_sync *pkt,
int64_t clk);
size_t rp_encode_ats_req(uint32_t id, uint32_t dev,
struct rp_pkt_ats *pkt,
int64_t clk, uint64_t attr, uint64_t addr,
uint64_t size, uint64_t result, uint32_t flags);
size_t rp_encode_ats_inv(uint32_t id, uint32_t dev,
struct rp_pkt_ats *pkt,
int64_t clk, uint64_t attr, uint64_t addr,
uint64_t size, uint64_t result, uint32_t flags);
void rp_process_caps(struct rp_peer_state *peer,
void *caps, size_t caps_len);
/* Dynamically resizable remote port pkt. */
typedef struct RemotePortDynPkt {
struct rp_pkt *pkt;
size_t size;
} RemotePortDynPkt;
/*
* Make sure dpkt is allocated and has enough room.
*/
void rp_dpkt_alloc(RemotePortDynPkt *dpkt, size_t size);
void rp_dpkt_swap(RemotePortDynPkt *a, RemotePortDynPkt *b);
/*
* Check if the dpkt is valid. Used for debugging purposes.
*/
bool rp_dpkt_is_valid(RemotePortDynPkt *dpkt);
/*
* Invalidate the dpkt. Used for debugging purposes.
*/
void rp_dpkt_invalidate(RemotePortDynPkt *dpkt);
void rp_dpkt_free(RemotePortDynPkt *dpkt);
static inline int rp_get_busaccess_response(struct rp_pkt *pkt)
{
return (pkt->busaccess_ext_base.attributes & RP_BUS_RESP_MASK) >>
RP_BUS_RESP_SHIFT;
}
#endif

View File

@ -0,0 +1,115 @@
`timescale 1ns / 1ps
module tb_cosim;
import "DPI-C" function int start_cosim(string path);
import "DPI-C" function void end_cosim();
import "DPI-C" function int wait_cosim(output int addr, output int t);
import "DPI-C" function void finalize_cosim(int t);
import "DPI-C" function void read_cosim(input int value);
import "DPI-C" function int write_cosim();
// Cosimulation variables
integer cosim_ret;
reg unsigned [31:0] cosim_address;
reg unsigned [31:0] cosim_data;
integer timestamp;
integer curtime;
integer started;
reg ACLK;
reg ARESETN;
wire [1:0] LED;
initial begin
ACLK = 1'b0;
ARESETN = 0'b0;
end
always #5 ACLK = !ACLK;
initial begin
$display("Starting testbench");
// Start co-simulation
if (start_cosim("unix:/tmp/qemu-rport-_cosim@0")>0) begin
$display("ERROR: Could not start co-simulation. Stop simulation");
$stop;
end
$display("Co-simulation started");
ARESETN = 1'b0;
repeat(2)@(posedge ACLK);
ARESETN = 1'b1;
repeat(2)@(posedge ACLK);
// Main loop
cosim_ret = 0;
while (cosim_ret>=0) begin
cosim_ret = wait_cosim(cosim_address, timestamp);
// Check for end of simulation
if (cosim_address=='h7ffffffc) begin
break;
end
// Check for start of simulation
if (cosim_address=='h7ffffff8) begin
curtime = timestamp;
cosim_ret = 0;
started = 1;
end
// Check for pause of simulation
if (cosim_address=='h7ffffff4) begin
started = 0;
finalize_cosim(curtime);
end
if (started==0) begin
continue;
end
while(curtime<timestamp) begin
@(posedge ACLK);
end
if (cosim_ret==1) begin
// WRITE
cosim_data = write_cosim();
// ADDR = cosim_address;
// WRDAT = cosim_data;
// WR = 1'b1;
@(posedge ACLK);
// WR = 1'b0;
// while (WRREADY==1'b0) begin
// @(posedge ACLK);
// end
end
if (cosim_ret==2) begin
// READ
// ADDR = cosim_address;
// RD = 1'b1;
@(posedge ACLK);
// RD = 1'b0;
// while (RDREADY==1'b0) begin
// @(posedge ACLK);
// end
@(negedge ACLK);
cosim_data = 'hdeadbeef;
read_cosim(cosim_data);
end
finalize_cosim(curtime);
end
$display("Reached end of simulation. Stop Co-simulation");
end_cosim();
$stop;
end
heartbeat #(100000000, 10000000) i_heartbeat(
ACLK, ARESETN, LED
);
endmodule

2
examples/zynq7000/SW/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
build
DISASS

View File

@ -0,0 +1,68 @@
.SILENT:
TARGET := app.elf
BUILDROOT ?= $(shell pwd)
BUILDDIR := build
SRCDIRS := $(BUILDROOT)/src
SRCFILESC := $(shell find $(SRCDIRS) -type f -name "*.c")
OBJFILESC := $(SRCFILESC:%.c=$(BUILDDIR)/%.c.o) $(BUILDDIR)/src/ps7_init.o
DEPFILESC := $(SRCFILESC:%.c=$(BUILDDIR)/%.c.d)
SRCFILESA := $(shell find $(SRCDIRS) -type f -name "*.S")
OBJFILESA := $(SRCFILESA:%.S=$(BUILDDIR)/%.S.o)
DEPFILESA := $(SRCFILESA:%.S=$(BUILDDIR)/%.S.d)
SRCFILES := $(SRCFILESC) $(SRCFILESA)
OBJFILES := $(OBJFILESA) $(OBJFILESC)
DEPFILES := $(DEPFILESC) $(DEPFILESA)
FILESTOCLEAN := $(OBJFILES) $(DEPFILES) $(BUILDDIR)/$(TARGET)
CROSS_COMPILE ?= arm-none-eabi-
CC := $(CROSS_COMPILE)gcc
AS := $(CROSS_COMPILE)as
LD := $(CROSS_COMPILE)gcc
CC_WARNING := -Wall -Wextra
CC_LIBS := -lgcc
CC_FLAGS := -nostdlib -fno-builtin -g -mcpu=cortex-a9
CC_INCLUDES := -I $(BUILDROOT)/src -I $(BUILDROOT)/../OUT/ip/zynqps
LD_FLAGS := -Wl,-T$(BUILDROOT)/linker.ld
.PHONY: $(TARGET) all clean
all: $(TARGET)
# PHONY RULES
# -----------
$(TARGET): $(BUILDDIR)/$(TARGET)
clean:
echo CLEAN FILES FOR $(TARGET)
-rm -r $(FILESTOCLEAN)
# SPECIFIC BUILD RULES
# --------------------
$(BUILDDIR)/$(TARGET): $(OBJFILES)
echo 'LD ' $@
$(LD) $(CC_FLAGS) $(LD_FLAGS) -o $(BUILDDIR)/$(TARGET) $(OBJFILES) $(CC_LIBS)
$(XILINX_BASE)/bin/$(CROSS_COMPILE)objdump -D $(BUILDDIR)/$(TARGET) > DISASS
$(BUILDDIR)/src/ps7_init.o : $(BUILDROOT)/../OUT/ip/zynqps/ps7_init.c $(BUILDROOT)/../OUT/ip/zynqps/ps7_init.h
echo 'CC ' $@
-mkdir -p $(shell dirname $@)
$(CC) $(CC_FLAGS) $(CC_WARNING) $(CC_INCLUDES) -MD -o $(BUILDDIR)/src/ps7_init.o -c $(BUILDROOT)/../OUT/ip/zynqps/ps7_init.c
$(OBJFILES): $(BUILDDIR)/%.c.o: %.c
echo 'CC ' $@
-mkdir -p $(shell dirname $@)
$(CC) $(CC_FLAGS) $(CC_WARNING) $(CC_INCLUDES) -MD -o $@ -c $<
$(OBJFILESA): $(BUILDDIR)/%.S.o: %.S
echo 'AS ' $@
-mkdir -p $(shell dirname $@)
$(CC) $(CC_FLAGS) $(CC_WARNING) $(CC_INCLUDES) -MD -o $@ -c $<
# Add DEPFILE dependencies
-include $(DEPFILES)

View File

@ -0,0 +1,13 @@
.SILENT:
TARGET := system.dtb
BUILDROOT ?= $(shell pwd)
BUILDDIR := build
.PHONY: $(TARGET) all clean
all: $(TARGET)
$(TARGET):
gcc -I $(BUILDROOT) -I $(BUILDROOT)/include -E -nostdinc -undef -D__DTS__ -x assembler-with-cpp -o system.dts $(BUILDROOT)/system-top.dts
dtc -I dts -O dtb -o system.dtb system.dts

View File

@ -0,0 +1,123 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2019 Xilinx Inc.
*
*/
#ifndef _DT_BINDINGS_CLK_VERSAL_H
#define _DT_BINDINGS_CLK_VERSAL_H
#define PMC_PLL 1
#define APU_PLL 2
#define RPU_PLL 3
#define CPM_PLL 4
#define NOC_PLL 5
#define PLL_MAX 6
#define PMC_PRESRC 7
#define PMC_POSTCLK 8
#define PMC_PLL_OUT 9
#define PPLL 10
#define NOC_PRESRC 11
#define NOC_POSTCLK 12
#define NOC_PLL_OUT 13
#define NPLL 14
#define APU_PRESRC 15
#define APU_POSTCLK 16
#define APU_PLL_OUT 17
#define APLL 18
#define RPU_PRESRC 19
#define RPU_POSTCLK 20
#define RPU_PLL_OUT 21
#define RPLL 22
#define CPM_PRESRC 23
#define CPM_POSTCLK 24
#define CPM_PLL_OUT 25
#define CPLL 26
#define PPLL_TO_XPD 27
#define NPLL_TO_XPD 28
#define APLL_TO_XPD 29
#define RPLL_TO_XPD 30
#define EFUSE_REF 31
#define SYSMON_REF 32
#define IRO_SUSPEND_REF 33
#define USB_SUSPEND 34
#define SWITCH_TIMEOUT 35
#define RCLK_PMC 36
#define RCLK_LPD 37
#define WDT 38
#define TTC0 39
#define TTC1 40
#define TTC2 41
#define TTC3 42
#define GEM_TSU 43
#define GEM_TSU_LB 44
#define MUXED_IRO_DIV2 45
#define MUXED_IRO_DIV4 46
#define PSM_REF 47
#define GEM0_RX 48
#define GEM0_TX 49
#define GEM1_RX 50
#define GEM1_TX 51
#define CPM_CORE_REF 52
#define CPM_LSBUS_REF 53
#define CPM_DBG_REF 54
#define CPM_AUX0_REF 55
#define CPM_AUX1_REF 56
#define QSPI_REF 57
#define OSPI_REF 58
#define SDIO0_REF 59
#define SDIO1_REF 60
#define PMC_LSBUS_REF 61
#define I2C_REF 62
#define TEST_PATTERN_REF 63
#define DFT_OSC_REF 64
#define PMC_PL0_REF 65
#define PMC_PL1_REF 66
#define PMC_PL2_REF 67
#define PMC_PL3_REF 68
#define CFU_REF 69
#define SPARE_REF 70
#define NPI_REF 71
#define HSM0_REF 72
#define HSM1_REF 73
#define SD_DLL_REF 74
#define FPD_TOP_SWITCH 75
#define FPD_LSBUS 76
#define ACPU 77
#define DBG_TRACE 78
#define DBG_FPD 79
#define LPD_TOP_SWITCH 80
#define ADMA 81
#define LPD_LSBUS 82
#define CPU_R5 83
#define CPU_R5_CORE 84
#define CPU_R5_OCM 85
#define CPU_R5_OCM2 86
#define IOU_SWITCH 87
#define GEM0_REF 88
#define GEM1_REF 89
#define GEM_TSU_REF 90
#define USB0_BUS_REF 91
#define UART0_REF 92
#define UART1_REF 93
#define SPI0_REF 94
#define SPI1_REF 95
#define CAN0_REF 96
#define CAN1_REF 97
#define I2C0_REF 98
#define I2C1_REF 99
#define DBG_LPD 100
#define TIMESTAMP_REF 101
#define DBG_TSTMP 102
#define CPM_TOPSW_REF 103
#define USB3_DUAL_REF 104
#define OUTCLK_MAX 105
#define REF_CLK 106
#define PL_ALT_REF_CLK 107
#define MUXED_IRO 108
#define PL_EXT 109
#define PL_LB 110
#define MIO_50_OR_51 111
#define MIO_24_OR_25 112
#endif

View File

@ -0,0 +1,42 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2019 Xilinx, Inc.
*/
#ifndef _DT_BINDINGS_VERSAL_POWER_H
#define _DT_BINDINGS_VERSAL_POWER_H
#define PM_DEV_USB_0 (0x18224018U)
#define PM_DEV_GEM_0 (0x18224019U)
#define PM_DEV_GEM_1 (0x1822401aU)
#define PM_DEV_SPI_0 (0x1822401bU)
#define PM_DEV_SPI_1 (0x1822401cU)
#define PM_DEV_I2C_0 (0x1822401dU)
#define PM_DEV_I2C_1 (0x1822401eU)
#define PM_DEV_CAN_FD_0 (0x1822401fU)
#define PM_DEV_CAN_FD_1 (0x18224020U)
#define PM_DEV_UART_0 (0x18224021U)
#define PM_DEV_UART_1 (0x18224022U)
#define PM_DEV_GPIO (0x18224023U)
#define PM_DEV_TTC_0 (0x18224024U)
#define PM_DEV_TTC_1 (0x18224025U)
#define PM_DEV_TTC_2 (0x18224026U)
#define PM_DEV_TTC_3 (0x18224027U)
#define PM_DEV_SWDT_FPD (0x18224029U)
#define PM_DEV_OSPI (0x1822402aU)
#define PM_DEV_QSPI (0x1822402bU)
#define PM_DEV_GPIO_PMC (0x1822402cU)
#define PM_DEV_SDIO_0 (0x1822402eU)
#define PM_DEV_SDIO_1 (0x1822402fU)
#define PM_DEV_RTC (0x18224034U)
#define PM_DEV_ADMA_0 (0x18224035U)
#define PM_DEV_ADMA_1 (0x18224036U)
#define PM_DEV_ADMA_2 (0x18224037U)
#define PM_DEV_ADMA_3 (0x18224038U)
#define PM_DEV_ADMA_4 (0x18224039U)
#define PM_DEV_ADMA_5 (0x1822403aU)
#define PM_DEV_ADMA_6 (0x1822403bU)
#define PM_DEV_ADMA_7 (0x1822403cU)
#define PM_DEV_AI (0x18224072U)
#endif

View File

@ -0,0 +1,130 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2018 Xilinx, Inc.
*/
#ifndef _DT_BINDINGS_ZYNQMP_RESETS_H
#define _DT_BINDINGS_ZYNQMP_RESETS_H
#define ZYNQMP_RESET_PCIE_CFG 0
#define ZYNQMP_RESET_PCIE_BRIDGE 1
#define ZYNQMP_RESET_PCIE_CTRL 2
#define ZYNQMP_RESET_DP 3
#define ZYNQMP_RESET_SWDT_CRF 4
#define ZYNQMP_RESET_AFI_FM5 5
#define ZYNQMP_RESET_AFI_FM4 6
#define ZYNQMP_RESET_AFI_FM3 7
#define ZYNQMP_RESET_AFI_FM2 8
#define ZYNQMP_RESET_AFI_FM1 9
#define ZYNQMP_RESET_AFI_FM0 10
#define ZYNQMP_RESET_GDMA 11
#define ZYNQMP_RESET_GPU_PP1 12
#define ZYNQMP_RESET_GPU_PP0 13
#define ZYNQMP_RESET_GPU 14
#define ZYNQMP_RESET_GT 15
#define ZYNQMP_RESET_SATA 16
#define ZYNQMP_RESET_ACPU3_PWRON 17
#define ZYNQMP_RESET_ACPU2_PWRON 18
#define ZYNQMP_RESET_ACPU1_PWRON 19
#define ZYNQMP_RESET_ACPU0_PWRON 20
#define ZYNQMP_RESET_APU_L2 21
#define ZYNQMP_RESET_ACPU3 22
#define ZYNQMP_RESET_ACPU2 23
#define ZYNQMP_RESET_ACPU1 24
#define ZYNQMP_RESET_ACPU0 25
#define ZYNQMP_RESET_DDR 26
#define ZYNQMP_RESET_APM_FPD 27
#define ZYNQMP_RESET_SOFT 28
#define ZYNQMP_RESET_GEM0 29
#define ZYNQMP_RESET_GEM1 30
#define ZYNQMP_RESET_GEM2 31
#define ZYNQMP_RESET_GEM3 32
#define ZYNQMP_RESET_QSPI 33
#define ZYNQMP_RESET_UART0 34
#define ZYNQMP_RESET_UART1 35
#define ZYNQMP_RESET_SPI0 36
#define ZYNQMP_RESET_SPI1 37
#define ZYNQMP_RESET_SDIO0 38
#define ZYNQMP_RESET_SDIO1 39
#define ZYNQMP_RESET_CAN0 40
#define ZYNQMP_RESET_CAN1 41
#define ZYNQMP_RESET_I2C0 42
#define ZYNQMP_RESET_I2C1 43
#define ZYNQMP_RESET_TTC0 44
#define ZYNQMP_RESET_TTC1 45
#define ZYNQMP_RESET_TTC2 46
#define ZYNQMP_RESET_TTC3 47
#define ZYNQMP_RESET_SWDT_CRL 48
#define ZYNQMP_RESET_NAND 49
#define ZYNQMP_RESET_ADMA 50
#define ZYNQMP_RESET_GPIO 51
#define ZYNQMP_RESET_IOU_CC 52
#define ZYNQMP_RESET_TIMESTAMP 53
#define ZYNQMP_RESET_RPU_R50 54
#define ZYNQMP_RESET_RPU_R51 55
#define ZYNQMP_RESET_RPU_AMBA 56
#define ZYNQMP_RESET_OCM 57
#define ZYNQMP_RESET_RPU_PGE 58
#define ZYNQMP_RESET_USB0_CORERESET 59
#define ZYNQMP_RESET_USB1_CORERESET 60
#define ZYNQMP_RESET_USB0_HIBERRESET 61
#define ZYNQMP_RESET_USB1_HIBERRESET 62
#define ZYNQMP_RESET_USB0_APB 63
#define ZYNQMP_RESET_USB1_APB 64
#define ZYNQMP_RESET_IPI 65
#define ZYNQMP_RESET_APM_LPD 66
#define ZYNQMP_RESET_RTC 67
#define ZYNQMP_RESET_SYSMON 68
#define ZYNQMP_RESET_AFI_FM6 69
#define ZYNQMP_RESET_LPD_SWDT 70
#define ZYNQMP_RESET_FPD 71
#define ZYNQMP_RESET_RPU_DBG1 72
#define ZYNQMP_RESET_RPU_DBG0 73
#define ZYNQMP_RESET_DBG_LPD 74
#define ZYNQMP_RESET_DBG_FPD 75
#define ZYNQMP_RESET_APLL 76
#define ZYNQMP_RESET_DPLL 77
#define ZYNQMP_RESET_VPLL 78
#define ZYNQMP_RESET_IOPLL 79
#define ZYNQMP_RESET_RPLL 80
#define ZYNQMP_RESET_GPO3_PL_0 81
#define ZYNQMP_RESET_GPO3_PL_1 82
#define ZYNQMP_RESET_GPO3_PL_2 83
#define ZYNQMP_RESET_GPO3_PL_3 84
#define ZYNQMP_RESET_GPO3_PL_4 85
#define ZYNQMP_RESET_GPO3_PL_5 86
#define ZYNQMP_RESET_GPO3_PL_6 87
#define ZYNQMP_RESET_GPO3_PL_7 88
#define ZYNQMP_RESET_GPO3_PL_8 89
#define ZYNQMP_RESET_GPO3_PL_9 90
#define ZYNQMP_RESET_GPO3_PL_10 91
#define ZYNQMP_RESET_GPO3_PL_11 92
#define ZYNQMP_RESET_GPO3_PL_12 93
#define ZYNQMP_RESET_GPO3_PL_13 94
#define ZYNQMP_RESET_GPO3_PL_14 95
#define ZYNQMP_RESET_GPO3_PL_15 96
#define ZYNQMP_RESET_GPO3_PL_16 97
#define ZYNQMP_RESET_GPO3_PL_17 98
#define ZYNQMP_RESET_GPO3_PL_18 99
#define ZYNQMP_RESET_GPO3_PL_19 100
#define ZYNQMP_RESET_GPO3_PL_20 101
#define ZYNQMP_RESET_GPO3_PL_21 102
#define ZYNQMP_RESET_GPO3_PL_22 103
#define ZYNQMP_RESET_GPO3_PL_23 104
#define ZYNQMP_RESET_GPO3_PL_24 105
#define ZYNQMP_RESET_GPO3_PL_25 106
#define ZYNQMP_RESET_GPO3_PL_26 107
#define ZYNQMP_RESET_GPO3_PL_27 108
#define ZYNQMP_RESET_GPO3_PL_28 109
#define ZYNQMP_RESET_GPO3_PL_29 110
#define ZYNQMP_RESET_GPO3_PL_30 111
#define ZYNQMP_RESET_GPO3_PL_31 112
#define ZYNQMP_RESET_RPU_LS 113
#define ZYNQMP_RESET_PS_ONLY 114
#define ZYNQMP_RESET_PL 115
#define ZYNQMP_RESET_PS_PL0 116
#define ZYNQMP_RESET_PS_PL1 117
#define ZYNQMP_RESET_PS_PL2 118
#define ZYNQMP_RESET_PS_PL3 119
#endif

View File

@ -0,0 +1,28 @@
/*
* CAUTION: This file is automatically generated by Xilinx.
* Version: XSCT 2020.2
* Today is: Wed Oct 13 14:26:41 2021
*/
/ {
cpus {
cpu@0 {
operating-points = <666666 1000000 333333 1000000>;
};
};
};
&intc {
num_cpus = <2>;
num_interrupts = <96>;
};
&uart1 {
cts-override ;
device_type = "serial";
port-number = <0>;
status = "okay";
};
&clkc {
fclk-enable = <0x1>;
ps-clk-frequency = <33333333>;
};

View File

@ -0,0 +1,35 @@
/*
* CAUTION: This file is automatically generated by Xilinx.
* Version: XSCT 2020.2
* Today is: Wed Oct 13 14:26:41 2021
*/
/ {
amba_pl: amba_pl {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges ;
axi_gpio_0: gpio@41200000 {
#gpio-cells = <3>;
clock-names = "s_axi_aclk";
clocks = <&clkc 15>;
compatible = "xlnx,axi-gpio-2.0", "xlnx,xps-gpio-1.00.a";
gpio-controller ;
reg = <0x41200000 0x10000>;
xlnx,all-inputs = <0x0>;
xlnx,all-inputs-2 = <0x0>;
xlnx,all-outputs = <0x0>;
xlnx,all-outputs-2 = <0x0>;
xlnx,dout-default = <0x00000000>;
xlnx,dout-default-2 = <0x00000000>;
xlnx,gpio-width = <0x20>;
xlnx,gpio2-width = <0x20>;
xlnx,interrupt-present = <0x0>;
xlnx,is-dual = <0x0>;
xlnx,tri-default = <0xFFFFFFFF>;
xlnx,tri-default-2 = <0xFFFFFFFF>;
};
};
};

View File

@ -0,0 +1,13 @@
/*
* Skeleton device tree; the bare minimum needed to boot; just include and
* add a compatible value. The bootloader will typically populate the memory
* node.
*/
/ {
#address-cells = <1>;
#size-cells = <1>;
chosen { };
aliases { };
memory { device_type = "memory"; reg = <0 0>; };
};

View File

@ -0,0 +1,25 @@
/*
* CAUTION: This file is automatically generated by Xilinx.
* Version: XSCT 2020.2
* Today is: Wed Oct 13 14:26:41 2021
*/
/dts-v1/;
#include "zynq-7000.dtsi"
#include "zynq-pl-remoteport.dtsi"
//#include "pl.dtsi"
#include "pcw.dtsi"
/ {
chosen {
bootargs = "earlycon";
stdout-path = "serial0:115200n8";
};
aliases {
serial0 = &uart1;
};
memory {
device_type = "memory";
reg = <0x0 0x20000000>;
};
};

View File

@ -0,0 +1,566 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011 - 2015 Xilinx
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/ {
#address-cells = <1>;
#size-cells = <1>;
compatible = "xlnx,zynq-7000";
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu0: cpu@0 {
compatible = "arm,cortex-a9";
device_type = "cpu";
reg = <0>;
clocks = <&clkc 3>;
clock-latency = <1000>;
cpu0-supply = <&regulator_vccpint>;
operating-points = <
/* kHz uV */
666667 1000000
333334 1000000
>;
};
cpu1: cpu@1 {
compatible = "arm,cortex-a9";
device_type = "cpu";
reg = <1>;
clocks = <&clkc 3>;
};
};
fpga_full: fpga-full {
compatible = "fpga-region";
fpga-mgr = <&devcfg>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
};
pmu@f8891000 {
compatible = "arm,cortex-a9-pmu";
interrupts = <0 5 4>, <0 6 4>;
interrupt-parent = <&intc>;
reg = < 0xf8891000 0x1000 0xf8893000 0x1000 >;
};
regulator_vccpint: fixedregulator {
compatible = "regulator-fixed";
regulator-name = "VCCPINT";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
regulator-boot-on;
regulator-always-on;
};
replicator {
compatible = "arm,coresight-static-replicator";
clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
out-ports {
#address-cells = <1>;
#size-cells = <0>;
/* replicator output ports */
port@0 {
reg = <0>;
replicator_out_port0: endpoint {
remote-endpoint = <&tpiu_in_port>;
};
};
port@1 {
reg = <1>;
replicator_out_port1: endpoint {
remote-endpoint = <&etb_in_port>;
};
};
};
in-ports {
/* replicator input port */
port {
replicator_in_port0: endpoint {
remote-endpoint = <&funnel_out_port>;
};
};
};
};
amba: amba {
u-boot,dm-pre-reloc;
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;
ranges;
adc: adc@f8007100 {
compatible = "xlnx,zynq-xadc-1.00.a";
reg = <0xf8007100 0x20>;
interrupts = <0 7 4>;
interrupt-parent = <&intc>;
clocks = <&clkc 12>;
};
can0: can@e0008000 {
compatible = "xlnx,zynq-can-1.0";
status = "disabled";
clocks = <&clkc 19>, <&clkc 36>;
clock-names = "can_clk", "pclk";
reg = <0xe0008000 0x1000>;
interrupts = <0 28 4>;
interrupt-parent = <&intc>;
tx-fifo-depth = <0x40>;
rx-fifo-depth = <0x40>;
};
can1: can@e0009000 {
compatible = "xlnx,zynq-can-1.0";
status = "disabled";
clocks = <&clkc 20>, <&clkc 37>;
clock-names = "can_clk", "pclk";
reg = <0xe0009000 0x1000>;
interrupts = <0 51 4>;
interrupt-parent = <&intc>;
tx-fifo-depth = <0x40>;
rx-fifo-depth = <0x40>;
};
gpio0: gpio@e000a000 {
compatible = "xlnx,zynq-gpio-1.0";
#gpio-cells = <2>;
clocks = <&clkc 42>;
gpio-controller;
interrupt-controller;
#interrupt-cells = <2>;
interrupt-parent = <&intc>;
interrupts = <0 20 4>;
reg = <0xe000a000 0x1000>;
};
i2c0: i2c@e0004000 {
compatible = "cdns,i2c-r1p10";
status = "disabled";
clocks = <&clkc 38>;
interrupt-parent = <&intc>;
interrupts = <0 25 4>;
reg = <0xe0004000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
};
i2c1: i2c@e0005000 {
compatible = "cdns,i2c-r1p10";
status = "disabled";
clocks = <&clkc 39>;
interrupt-parent = <&intc>;
interrupts = <0 48 4>;
reg = <0xe0005000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
};
intc: interrupt-controller@f8f01000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0xF8F01000 0x1000>,
<0xF8F00100 0x100>;
};
L2: cache-controller@f8f02000 {
compatible = "arm,pl310-cache";
reg = <0xF8F02000 0x1000>;
interrupts = <0 2 4>;
arm,data-latency = <3 2 2>;
arm,tag-latency = <2 2 2>;
cache-unified;
cache-level = <2>;
};
mc: memory-controller@f8006000 {
compatible = "xlnx,zynq-ddrc-a05";
reg = <0xf8006000 0x1000>;
};
ocmc: ocmc@f800c000 {
compatible = "xlnx,zynq-ocmc-1.0";
interrupt-parent = <&intc>;
interrupts = <0 3 4>;
reg = <0xf800c000 0x1000>;
};
uart0: serial@e0000000 {
compatible = "xlnx,xuartps", "cdns,uart-r1p8";
status = "disabled";
clocks = <&clkc 23>, <&clkc 40>;
clock-names = "uart_clk", "pclk";
reg = <0xE0000000 0x1000>;
interrupts = <0 27 4>;
};
uart1: serial@e0001000 {
compatible = "xlnx,xuartps", "cdns,uart-r1p8";
status = "disabled";
clocks = <&clkc 24>, <&clkc 41>;
clock-names = "uart_clk", "pclk";
reg = <0xE0001000 0x1000>;
interrupts = <0 50 4>;
};
spi0: spi@e0006000 {
compatible = "xlnx,zynq-spi-r1p6";
reg = <0xe0006000 0x1000>;
status = "disabled";
interrupt-parent = <&intc>;
interrupts = <0 26 4>;
clocks = <&clkc 25>, <&clkc 34>;
clock-names = "ref_clk", "pclk";
#address-cells = <1>;
#size-cells = <0>;
};
spi1: spi@e0007000 {
compatible = "xlnx,zynq-spi-r1p6";
reg = <0xe0007000 0x1000>;
status = "disabled";
interrupt-parent = <&intc>;
interrupts = <0 49 4>;
clocks = <&clkc 26>, <&clkc 35>;
clock-names = "ref_clk", "pclk";
#address-cells = <1>;
#size-cells = <0>;
};
qspi: spi@e000d000 {
clock-names = "ref_clk", "pclk";
clocks = <&clkc 10>, <&clkc 43>;
compatible = "xlnx,zynq-qspi-1.0";
status = "disabled";
interrupt-parent = <&intc>;
interrupts = <0 19 4>;
reg = <0xe000d000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
};
smcc: memory-controller@e000e000 {
#address-cells = <1>;
#size-cells = <1>;
status = "disabled";
clock-names = "memclk", "apb_pclk";
clocks = <&clkc 11>, <&clkc 44>;
compatible = "arm,pl353-smc-r2p1", "arm,primecell";
interrupt-parent = <&intc>;
interrupts = <0 18 4>;
ranges ;
reg = <0xe000e000 0x1000>;
nand0: flash@e1000000 {
status = "disabled";
compatible = "arm,pl353-nand-r2p1";
reg = <0xe1000000 0x1000000>;
#address-cells = <0x1>;
#size-cells = <0x1>;
};
nor0: flash@e2000000 {
status = "disabled";
compatible = "cfi-flash";
reg = <0xe2000000 0x2000000>;
#address-cells = <1>;
#size-cells = <1>;
};
};
gem0: ethernet@e000b000 {
compatible = "cdns,zynq-gem", "cdns,gem";
reg = <0xe000b000 0x1000>;
status = "disabled";
interrupts = <0 22 4>;
clocks = <&clkc 30>, <&clkc 30>, <&clkc 13>;
clock-names = "pclk", "hclk", "tx_clk";
#address-cells = <1>;
#size-cells = <0>;
};
gem1: ethernet@e000c000 {
compatible = "cdns,zynq-gem", "cdns,gem";
reg = <0xe000c000 0x1000>;
status = "disabled";
interrupts = <0 45 4>;
clocks = <&clkc 31>, <&clkc 31>, <&clkc 14>;
clock-names = "pclk", "hclk", "tx_clk";
#address-cells = <1>;
#size-cells = <0>;
};
sdhci0: mmc@e0100000 {
compatible = "arasan,sdhci-8.9a";
status = "disabled";
clock-names = "clk_xin", "clk_ahb";
clocks = <&clkc 21>, <&clkc 32>;
interrupt-parent = <&intc>;
interrupts = <0 24 4>;
reg = <0xe0100000 0x1000>;
};
sdhci1: mmc@e0101000 {
compatible = "arasan,sdhci-8.9a";
status = "disabled";
clock-names = "clk_xin", "clk_ahb";
clocks = <&clkc 22>, <&clkc 33>;
interrupt-parent = <&intc>;
interrupts = <0 47 4>;
reg = <0xe0101000 0x1000>;
};
slcr: slcr@f8000000 {
u-boot,dm-pre-reloc;
#address-cells = <1>;
#size-cells = <1>;
compatible = "xlnx,zynq-slcr", "syscon", "simple-mfd";
reg = <0xF8000000 0x1000>;
ranges;
clkc: clkc@100 {
u-boot,dm-pre-reloc;
#clock-cells = <1>;
compatible = "xlnx,ps7-clkc";
fclk-enable = <0xf>;
clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x",
"cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x",
"dci", "lqspi", "smc", "pcap", "gem0", "gem1",
"fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1",
"sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1",
"dma", "usb0_aper", "usb1_aper", "gem0_aper",
"gem1_aper", "sdio0_aper", "sdio1_aper",
"spi0_aper", "spi1_aper", "can0_aper", "can1_aper",
"i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper",
"gpio_aper", "lqspi_aper", "smc_aper", "swdt",
"dbg_trc", "dbg_apb";
reg = <0x100 0x100>;
};
rstc: rstc@200 {
compatible = "xlnx,zynq-reset";
reg = <0x200 0x48>;
#reset-cells = <1>;
syscon = <&slcr>;
};
pinctrl0: pinctrl@700 {
compatible = "xlnx,pinctrl-zynq";
reg = <0x700 0x200>;
syscon = <&slcr>;
};
};
dmac_s: dmac@f8003000 {
compatible = "arm,pl330", "arm,primecell";
reg = <0xf8003000 0x1000>;
interrupt-parent = <&intc>;
interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3",
"dma4", "dma5", "dma6", "dma7";
interrupts = <0 13 4>,
<0 14 4>, <0 15 4>,
<0 16 4>, <0 17 4>,
<0 40 4>, <0 41 4>,
<0 42 4>, <0 43 4>;
#dma-cells = <1>;
#dma-channels = <8>;
#dma-requests = <4>;
clocks = <&clkc 27>;
clock-names = "apb_pclk";
};
devcfg: devcfg@f8007000 {
compatible = "xlnx,zynq-devcfg-1.0";
interrupt-parent = <&intc>;
interrupts = <0 8 4>;
reg = <0xf8007000 0x100>;
clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>;
clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3";
syscon = <&slcr>;
};
efuse: efuse@f800d000 {
compatible = "xlnx,zynq-efuse";
reg = <0xf800d000 0x20>;
};
global_timer: timer@f8f00200 {
compatible = "arm,cortex-a9-global-timer";
reg = <0xf8f00200 0x20>;
interrupts = <1 11 0x301>;
interrupt-parent = <&intc>;
clocks = <&clkc 4>;
};
ttc0: timer@f8001000 {
interrupt-parent = <&intc>;
interrupts = <0 10 4>, <0 11 4>, <0 12 4>;
compatible = "cdns,ttc";
clocks = <&clkc 6>;
reg = <0xF8001000 0x1000>;
};
ttc1: timer@f8002000 {
interrupt-parent = <&intc>;
interrupts = <0 37 4>, <0 38 4>, <0 39 4>;
compatible = "cdns,ttc";
clocks = <&clkc 6>;
reg = <0xF8002000 0x1000>;
};
scutimer: timer@f8f00600 {
interrupt-parent = <&intc>;
interrupts = <1 13 0x301>;
compatible = "arm,cortex-a9-twd-timer";
reg = <0xf8f00600 0x20>;
clocks = <&clkc 4>;
};
usb0: usb@e0002000 {
compatible = "xlnx,zynq-usb-2.20a", "chipidea,usb2";
status = "disabled";
clocks = <&clkc 28>;
interrupt-parent = <&intc>;
interrupts = <0 21 4>;
reg = <0xe0002000 0x1000>;
phy_type = "ulpi";
};
usb1: usb@e0003000 {
compatible = "xlnx,zynq-usb-2.20a", "chipidea,usb2";
status = "disabled";
clocks = <&clkc 29>;
interrupt-parent = <&intc>;
interrupts = <0 44 4>;
reg = <0xe0003000 0x1000>;
phy_type = "ulpi";
};
watchdog0: watchdog@f8005000 {
clocks = <&clkc 45>;
compatible = "cdns,wdt-r1p2";
interrupt-parent = <&intc>;
interrupts = <0 9 1>;
reg = <0xf8005000 0x1000>;
timeout-sec = <10>;
};
etb@f8801000 {
compatible = "arm,coresight-etb10", "arm,primecell";
reg = <0xf8801000 0x1000>;
clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
in-ports {
port {
etb_in_port: endpoint {
remote-endpoint = <&replicator_out_port1>;
};
};
};
};
tpiu@f8803000 {
compatible = "arm,coresight-tpiu", "arm,primecell";
reg = <0xf8803000 0x1000>;
clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
in-ports {
port {
tpiu_in_port: endpoint {
remote-endpoint = <&replicator_out_port0>;
};
};
};
};
funnel@f8804000 {
compatible = "arm,coresight-static-funnel", "arm,primecell";
reg = <0xf8804000 0x1000>;
clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
/* funnel output ports */
out-ports {
port {
funnel_out_port: endpoint {
remote-endpoint =
<&replicator_in_port0>;
};
};
};
in-ports {
#address-cells = <1>;
#size-cells = <0>;
/* funnel input ports */
port@0 {
reg = <0>;
funnel0_in_port0: endpoint {
remote-endpoint = <&ptm0_out_port>;
};
};
port@1 {
reg = <1>;
funnel0_in_port1: endpoint {
remote-endpoint = <&ptm1_out_port>;
};
};
port@2 {
reg = <2>;
funnel0_in_port2: endpoint {
};
};
/* The other input ports are not connect to anything */
};
};
ptm@f889c000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0xf889c000 0x1000>;
clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
cpu = <&cpu0>;
out-ports {
port {
ptm0_out_port: endpoint {
remote-endpoint = <&funnel0_in_port0>;
};
};
};
};
ptm@f889d000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0xf889d000 0x1000>;
clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
cpu = <&cpu1>;
out-ports {
port {
ptm1_out_port: endpoint {
remote-endpoint = <&funnel0_in_port1>;
};
};
};
};
};
};

View File

@ -0,0 +1,263 @@
/*
* Zynq 7000 PL Interface over Remote-port.
*
* Copyright (c) 2016, Xilinx Inc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
&slcr {
/* In QEMU, the SLCR exports GPIOS (e.g the FPGA Resets). */
#gpio-cells = <1>;
gpio-controller;
};
/* Append stuff to the PS nodes. */
/ {
/* This version of the AMBA PL describes the PS/PL interface
* and not the devices that are available on the PL side.
*
* This is what QEMU will use to instantiate the RemotePort
* connections allowing for cosimulation.
*/
amba_pl {
cosim_rp_0: cosim@0 {
compatible = "remote-port";
sync = <1>;
chrdev-id = "pl-rp";
};
m_axi_gp0: rp_m_axi_gp0@40000000 {
compatible = "remote-port-memory-master";
remote-ports = < &cosim_rp_0 7 >;
reg = < 0x40000000 0x40000000 >;
};
m_axi_gp1: rp_m_axi_gp1@80000000 {
compatible = "remote-port-memory-master";
remote-ports = < &cosim_rp_0 8 >;
reg = < 0x80000000 0x40000000 >;
};
s_axi_gp0: rp_s_axi_gp0@0 {
compatible = "remote-port-memory-slave";
remote-ports = < &cosim_rp_0 0 >;
};
s_axi_gp1: rp_s_axi_gp1@0 {
compatible = "remote-port-memory-slave";
remote-ports = < &cosim_rp_0 1 >;
};
afi_0: rp_afi0@0 {
compatible = "remote-port-memory-slave";
remote-ports = < &cosim_rp_0 2 >;
};
afi_1: rp_afi1@0 {
compatible = "remote-port-memory-slave";
remote-ports = < &cosim_rp_0 3 >;
};
afi_2: rp_afi2@0 {
compatible = "remote-port-memory-slave";
remote-ports = < &cosim_rp_0 4 >;
};
afi_3: rp_afi3@0 {
compatible = "remote-port-memory-slave";
remote-ports = < &cosim_rp_0 5 >;
};
acp: rp_acp0@0 {
compatible = "remote-port-memory-slave";
remote-ports = < &cosim_rp_0 6 >;
};
wires_in: rp_wires_in@0 {
compatible = "remote-port-gpio";
remote-ports = < &cosim_rp_0 9 >;
num-gpios = < 16 >;
/* QEMU has a bug in the interrupts-extended parsing,
* so we need to use interrupt-parent for the moment.
*/
interrupt-parent = < &intc >;
interrupts = <
0x0 29 0x4
0x0 30 0x4
0x0 31 0x4
0x0 32 0x4
0x0 33 0x4
0x0 34 0x4
0x0 35 0x4
0x0 36 0x4
0x0 52 0x4
0x0 53 0x4
0x0 54 0x4
0x0 55 0x4
0x0 56 0x4
0x0 57 0x4
0x0 58 0x4
0x0 59 0x4
>;
};
wires_out: rp_wires_out@0 {
compatible = "remote-port-gpio";
remote-ports = < &cosim_rp_0 10 >;
num-gpios = <17>;
gpios = <
/* 17 FPGA_OUT_RESETS. */
&slcr 2 &slcr 3 &slcr 4 &slcr 5
&slcr 6 &slcr 7 &slcr 8 &slcr 9
&slcr 10 &slcr 11 &slcr 12 &slcr 13
&slcr 14 &slcr 15 &slcr 16 &slcr 17
&slcr 18
>;
};
rp_cosim_intr_pstopl: rp_cosim_intr_pstopl@0 {
#interrupt-cells = <3>;
interrupt-controller;
compatible = "remote-port-gpio";
remote-ports = <&cosim_rp_0 11>;
/* There are only 28 connections but due to the offset we need
* a higher number here.
*/
num-gpios = <96>;
cell-offset-irq-num = <1>;
};
/* This area can be used for implentation specific emulation*/
rp_cosim_reserved: rp_cosim_reserved@0{
compatible = "remote-port-memory-master";
remote-ports = <&cosim_rp_0 12>;
reg = <0xFE000000 0x100000>;
};
};
};
&can1 {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 0 4>, <0 0 0 &intc 0 51 4>;
};
&uart1 {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 1 4>, <0 0 0 &intc 0 50 4>;
};
&spi1 {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 2 4>, <0 0 0 &intc 0 49 4>;
};
&i2c1 {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 3 4>, <0 0 0 &intc 0 48 4>;
};
&sdhci1 {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 4 4>, <0 0 0 &intc 0 47 4>;
};
&gem1 {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 6 4>, <0 0 0 &intc 0 45 4>;
};
&usb1 {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 7 4>, <0 0 0 &intc 0 44 4>;
};
&can0 {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 8 4>, <0 0 0 &intc 0 28 4>;
};
&spi0 {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 10 4>, <0 0 0 &intc 0 26 4>;
};
&i2c0 {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 11 4>, <0 0 0 &intc 0 25 4>;
};
&sdhci0 {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 12 4>, <0 0 0 &intc 0 24 4>;
};
&gem0 {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 14 4>, <0 0 0 &intc 0 22 4>;
};
&usb0 {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 15 4>, <0 0 0 &intc 0 21 4>;
};
&gpio0 {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 16 4>, <0 0 0 &intc 0 20 4>;
};
&qspi {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 18 4>, <0 0 0 &intc 0 19 4>;
};
&smcc {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 19 4>, <0 0 0 &intc 0 18 4>;
};
&dmac_s {
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 &rp_cosim_intr_pstopl 0 28 4>, <0 0 0 &intc 0 13 4>,
<0 0 0 &rp_cosim_intr_pstopl 0 20 4>, <0 0 0 &intc 0 14 4>,
<0 0 0 &rp_cosim_intr_pstopl 0 21 4>, <0 0 0 &intc 0 15 4>,
<0 0 0 &rp_cosim_intr_pstopl 0 22 4>, <0 0 0 &intc 0 16 4>,
<0 0 0 &rp_cosim_intr_pstopl 0 23 4>, <0 0 0 &intc 0 17 4>,
<0 0 0 &rp_cosim_intr_pstopl 0 24 4>, <0 0 0 &intc 0 40 4>,
<0 0 0 &rp_cosim_intr_pstopl 0 25 4>, <0 0 0 &intc 0 41 4>,
<0 0 0 &rp_cosim_intr_pstopl 0 26 4>, <0 0 0 &intc 0 42 4>,
<0 0 0 &rp_cosim_intr_pstopl 0 27 4>, <0 0 0 &intc 0 43 4>;
};

View File

@ -0,0 +1,89 @@
OUTPUT_FORMAT ("elf32-littlearm")
MEMORY
{
SRAM_0 : ORIGIN = 0x00000000, LENGTH = 0x00030000 /* 192k */
SRAM_1 : ORIGIN = 0xFFFF0000, LENGTH = 0x00010000 /* 64k */
DDR_PS : ORIGIN = 0x00100000, LENGTH = 0x0FF00000 /* 256M */
}
EXTERN(__stack_size);
ASSERT(__stack_size, "Must provide a non-zero stack size");
EXTERN(_start);
SECTIONS
{
.text :
{
__stext = .;
*(.vectortable) /* Vector table */
*(.text .text.*) /* Standard Code */
*(.rodata .rodata.*) /* Constants, strings, ... */
*(.glue_7) /* Glue ARM to thumb code */
*(.glue_7t) /* Glue thumb to ARM code */
__etext = .;
} >DDR_PS
.data :
{
. = ALIGN(4);
__sdata = .;
*(.data .data.*)
__edata = .;
} >DDR_PS
.bss (NOLOAD) :
{
. = ALIGN(4);
__bss_start__ = .; /* Used for zeroing bss on startup */
*(.bss .bss.*)
__bss_end__ = .;
} >DDR_PS
. = ALIGN(4);
end = .;
/* Place all stacks in SRAM_1 - need to avoid filling addresses */
/* 0xfffffe00 to 0xfffffff0 - proc1 is halted running code in this range */
/* TODO: assert stacks do not step on proc1's code out of reset */
.stack (NOLOAD) :
{
. += __stack_size;
__proc0_irq_stack = .;
. += __stack_size;
__proc0_fiq_stack = .;
. += __stack_size;
__proc0_svc_stack = .;
. += __stack_size;
__proc0_abt_stack = .;
. += __stack_size;
__proc0_und_stack = .;
. += __stack_size;
__proc0_sys_stack = .;
. += __stack_size;
__proc1_irq_stack = .;
. += __stack_size;
__proc1_fiq_stack = .;
. += __stack_size;
__proc1_svc_stack = .;
. += __stack_size;
__proc1_abt_stack = .;
. += __stack_size;
__proc1_und_stack = .;
. += __stack_size;
__proc1_sys_stack = .;
. += __stack_size;
} >SRAM_1
.data.ddr :
{
*(.data_in_ddr)
} >DDR_PS
.note.gnu.build-id : {
KEEP (*(.note.gnu.build-id))
} >DDR_PS
}

View File

@ -0,0 +1,96 @@
.syntax unified /* Use the unified instruction syntax */
.arm /* Assemble ARM instruction set, not thumb */
.equ PROC1_RESET_VECTOR_TABLE, 0xFFFFFFF0
.equ CPSR_MODE_USER, 0x10
.equ CPSR_MODE_FIQ, 0x11
.equ CPSR_MODE_IRQ, 0x12
.equ CPSR_MODE_SVC, 0x13
.equ CPSR_MODE_ABORT, 0x17
.equ CPSR_MODE_UNDEFINED, 0x8B
.equ CPSR_MODE_SYSTEM, 0x1F
.equ CPSR_IRQ, 0x80 /* disable IRQ interrupts */
.equ CPSR_FIQ, 0x40 /* disable FIQ interrupts */
.global __stack_size
.equ __stack_size, 0x1000
// ------------------
.section .vectortable
// ------------------
.global vectortable
vectortable:
/* Exception Processor Mode Event Return Sequence */
b reset_handler /* MODE_SVC System Reset n/a */
b undef_handler /* MODE_UNDEFINED Undefined Instruction MOVS PC, LR (if emulating) */
b SVC_handler /* MODE_SVC SVC instruction MOVS PC, LR */
b prefetch_abort_handler /* MODE_ABORT Invalid inst. address SUBS PC, LR, #4 */
b data_abort_handler /* MODE_ABORT R/W to invalid address SUBS PC, LR, #8 (to retry) */
b hypervisor_handler /* MODE_HYP Hypervisor entry ERET */
b IRQ_handler /* MODE_IRQ IRQ Input Asserted SUBS PC, LR, #4 */
b FIQ_handler /* MODE_FIQ FIQ Input Asserted SUBS PC, LR, #4 */
reset_handler:
b _start
undef_handler:
b .
SVC_handler:
b .
prefetch_abort_handler:
b .
data_abort_handler:
b .
hypervisor_handler:
b .
IRQ_handler:
b .
FIQ_handler:
b .
// -----------
.section .text
// -----------
.global _start
_start:
msr CPSR, #(CPSR_IRQ | CPSR_FIQ | CPSR_MODE_IRQ) /* switch to MODE_IRQ */
ldr sp, =__proc0_irq_stack /* load IRQ mode stack pointer */
msr CPSR, #(CPSR_IRQ | CPSR_FIQ | CPSR_MODE_FIQ) /* switch to MODE_FIQ */
ldr sp, =__proc0_fiq_stack /* load FIQ mode stack pointer */
msr CPSR, #(CPSR_IRQ | CPSR_FIQ | CPSR_MODE_ABORT) /* switch to MODE_ABT */
ldr sp, =__proc0_abt_stack /* load ABT mode stack pointer */
msr CPSR, #(CPSR_IRQ | CPSR_FIQ | CPSR_MODE_UNDEFINED) /* switch to MODE_UND */
ldr sp, =__proc0_und_stack /* load UND mode stack pointer */
msr CPSR, #(CPSR_IRQ | CPSR_FIQ | CPSR_MODE_SYSTEM) /* switch to MODE_SYS */
ldr sp, =__proc0_sys_stack /* load SYS mode stack pointer */
msr CPSR, #(CPSR_IRQ | CPSR_FIQ | CPSR_MODE_SVC) /* switch to MODE_SVC */
ldr sp, =__proc0_svc_stack /* load SVC mode stack pointer */
/* We are now in SVC mode */
// Disable L1 cache
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 // Invalidate cache
mcr p15, 0, r0, c8, c7, 0 // Invalidate tlb
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x1000
bic r0, r0, #0x0004
mcr p15, 0, r0, c1, c0, 0
/* Set vector table base address */
ldr r0, =vectortable
mcr p15, #0, r0, c12, c0, #0
b main
_hang:
b _hang
.end

View File

@ -0,0 +1,30 @@
#include "ps7_init.h"
#include "zynq.h"
#include "uart.h"
#include "printf.h"
// COSIM control
volatile unsigned int * PAUSE = (unsigned int*) 0x7ffffff4; // Pause the cosimulation
volatile unsigned int * SOS = (unsigned int*) 0x7ffffff8; // (Re)start the cosimulation
volatile unsigned int * EOS = (unsigned int*) 0x7ffffffc; // Stop the cosimulation
void main(){
cpu_disable_interrups();
// Initialize ZYNQ Processing System
// ps7_init();
// Start UART
uart_setup();
*SOS = 1;
printf("Hello World!\n");
for(int i=0; i<32; i++){
printf("i=%d\n", i);
}
*EOS = 1;
for(;;);
}

View File

@ -0,0 +1,452 @@
#include "printf.h"
#include "uart.h"
#define NULL 0
extern int putchar(int c);
static void print_double_float(double val, unsigned int precision);
static void simple_outputchar(char **str, char c)
{
if (str) {
**str = c;
++(*str);
} else {
uart_send(c);
}
}
enum flags {
PAD_ZERO = 1,
PAD_RIGHT = 2,
};
static int prints(char **out, const char *string, int width, int flags)
{
int pc = 0, padchar = ' ';
if (width > 0) {
int len = 0;
const char *ptr;
for (ptr = string; *ptr; ++ptr) ++len;
if (len >= width) width = 0;
else width -= len;
if (flags & PAD_ZERO)
padchar = '0';
}
if (!(flags & PAD_RIGHT)) {
for ( ; width > 0; --width) {
simple_outputchar(out, padchar);
++pc;
}
}
for ( ; *string ; ++string) {
simple_outputchar(out, *string);
++pc;
}
for ( ; width > 0; --width) {
simple_outputchar(out, padchar);
++pc;
}
return pc;
}
#define PRINT_BUF_LEN 64
static int simple_outputi(char **out, long long i, int base, int sign, int width, int flags, int letbase)
{
char print_buf[PRINT_BUF_LEN];
char *s;
int t, neg = 0, pc = 0;
unsigned long long u = i;
if (i == 0) {
print_buf[0] = '0';
print_buf[1] = '\0';
return prints(out, print_buf, width, flags);
}
if (sign && base == 10 && i < 0) {
neg = 1;
u = -i;
}
s = print_buf + PRINT_BUF_LEN-1;
*s = '\0';
while (u) {
t = u % base;
if( t >= 10 )
t += letbase - '0' - 10;
*--s = t + '0';
u /= base;
}
if (neg) {
if( width && (flags & PAD_ZERO) ) {
simple_outputchar (out, '-');
++pc;
--width;
}
else {
*--s = '-';
}
}
return pc + prints (out, s, width, flags);
}
static int simple_vsprintf(char **out, char *format, va_list ap)
{
int width, flags;
int pc = 0;
char scr[2];
union {
char c;
char *s;
int i;
unsigned int u;
long li;
unsigned long lu;
long long lli;
unsigned long long llu;
short hi;
unsigned short hu;
signed char hhi;
unsigned char hhu;
void *p;
double d;
} u;
for (; *format != 0; ++format) {
if (*format == '%') {
++format;
width = flags = 0;
if (*format == '\0')
break;
if (*format == '%')
goto out;
if (*format == '-') {
++format;
flags = PAD_RIGHT;
}
while (*format == '0') {
++format;
flags |= PAD_ZERO;
}
if (*format == '*') {
width = va_arg(ap, int);
format++;
} else {
for ( ; *format >= '0' && *format <= '9'; ++format) {
width *= 10;
width += *format - '0';
}
}
switch (*format) {
case('d'):
u.i = va_arg(ap, int);
pc += simple_outputi(out, u.i, 10, 1, width, flags, 'a');
break;
case('u'):
u.u = va_arg(ap, unsigned int);
pc += simple_outputi(out, u.u, 10, 0, width, flags, 'a');
break;
case('x'):
u.u = va_arg(ap, unsigned int);
pc += simple_outputi(out, u.u, 16, 0, width, flags, 'a');
break;
case('X'):
u.u = va_arg(ap, unsigned int);
pc += simple_outputi(out, u.u, 16, 0, width, flags, 'A');
break;
case('c'):
u.c = va_arg(ap, int);
scr[0] = u.c;
scr[1] = '\0';
pc += prints(out, scr, width, flags);
break;
case('f'):
u.d = va_arg(ap, double);
print_double_float(u.d, width);
break;
case('s'):
u.s = va_arg(ap, char *);
pc += prints(out, u.s ? u.s : "(null)", width, flags);
break;
case('l'):
++format;
switch (*format) {
case('d'):
u.li = va_arg(ap, long);
pc += simple_outputi(out, u.li, 10, 1, width, flags, 'a');
break;
case('u'):
u.lu = va_arg(ap, unsigned long);
pc += simple_outputi(out, u.lu, 10, 0, width, flags, 'a');
break;
case('x'):
u.lu = va_arg(ap, unsigned long);
pc += simple_outputi(out, u.lu, 16, 0, width, flags, 'a');
break;
case('X'):
u.lu = va_arg(ap, unsigned long);
pc += simple_outputi(out, u.lu, 16, 0, width, flags, 'A');
break;
case('l'):
++format;
switch (*format) {
case('d'):
u.lli = va_arg(ap, long long);
pc += simple_outputi(out, u.lli, 10, 1, width, flags, 'a');
break;
case('u'):
u.llu = va_arg(ap, unsigned long long);
pc += simple_outputi(out, u.llu, 10, 0, width, flags, 'a');
break;
case('x'):
u.llu = va_arg(ap, unsigned long long);
pc += simple_outputi(out, u.llu, 16, 0, width, flags, 'a');
break;
case('X'):
u.llu = va_arg(ap, unsigned long long);
pc += simple_outputi(out, u.llu, 16, 0, width, flags, 'A');
break;
default:
break;
}
break;
default:
break;
}
break;
case('h'):
++format;
switch (*format) {
case('d'):
u.hi = va_arg(ap, int);
pc += simple_outputi(out, u.hi, 10, 1, width, flags, 'a');
break;
case('u'):
u.hu = va_arg(ap, unsigned int);
pc += simple_outputi(out, u.lli, 10, 0, width, flags, 'a');
break;
case('x'):
u.hu = va_arg(ap, unsigned int);
pc += simple_outputi(out, u.lli, 16, 0, width, flags, 'a');
break;
case('X'):
u.hu = va_arg(ap, unsigned int);
pc += simple_outputi(out, u.lli, 16, 0, width, flags, 'A');
break;
case('h'):
++format;
switch (*format) {
case('d'):
u.hhi = va_arg(ap, int);
pc += simple_outputi(out, u.hhi, 10, 1, width, flags, 'a');
break;
case('u'):
u.hhu = va_arg(ap, unsigned int);
pc += simple_outputi(out, u.lli, 10, 0, width, flags, 'a');
break;
case('x'):
u.hhu = va_arg(ap, unsigned int);
pc += simple_outputi(out, u.lli, 16, 0, width, flags, 'a');
break;
case('X'):
u.hhu = va_arg(ap, unsigned int);
pc += simple_outputi(out, u.lli, 16, 0, width, flags, 'A');
break;
default:
break;
}
break;
default:
break;
}
break;
default:
break;
}
}
else {
out:
simple_outputchar (out, *format);
++pc;
}
}
if (out) **out = '\0';
return pc;
}
int printf(char *fmt, ...)
{
va_list ap;
int r;
va_start(ap, fmt);
r = simple_vsprintf(NULL, fmt, ap);
va_end(ap);
return r;
}
int sprintf(char *buf, char *fmt, ...)
{
va_list ap;
int r;
va_start(ap, fmt);
r = simple_vsprintf(&buf, fmt, ap);
va_end(ap);
return r;
}
void hexDump (const char * desc, const void * addr, const int len) {
int i;
unsigned char buff[17];
const unsigned char * pc = (const unsigned char *)addr;
// Output description if given.
if (desc != NULL)
printf ("%s:\n", desc);
// Length checks.
if (len == 0) {
printf(" ZERO LENGTH\n");
return;
}
else if (len < 0) {
printf(" NEGATIVE LENGTH: %d\n", len);
return;
}
// Process every byte in the data.
for (i = 0; i < len; i++) {
// Multiple of 16 means new line (with line offset).
if ((i % 16) == 0) {
// Don't print ASCII buffer for the "zeroth" line.
if (i != 0)
printf (" %s\n", buff);
// Output the offset.
printf (" %04x ", i);
}
// Now the hex code for the specific character.
printf (" %02x", pc[i]);
// And buffer a printable ASCII character for later.
if ((pc[i] < 0x20) || (pc[i] > 0x7e)) // isprint() may be better.
buff[i % 16] = '.';
else
buff[i % 16] = pc[i];
buff[(i % 16) + 1] = '\0';
}
// Pad out last line if not exactly 16 characters.
while ((i % 16) != 0) {
printf (" ");
i++;
}
// And print the final ASCII buffer.
printf (" %s\n", buff);
}
#define MAX_PRECISION 50
#define IsNaN(n) (n != n)
// %f: double/single precision support (double or promoted float, 64-bits)
static void print_double_float(double val, unsigned int precision)
{
unsigned int cur_prec = 1;
if(precision==0)
precision = MAX_PRECISION;
// if the user-defined precision is out-of-bounds, normalize it
if(precision > MAX_PRECISION)
precision = MAX_PRECISION;
// if it's negative, show it!
if(val < 0)
{
printf("-");
// change to a positive value
val = -val;
}
// check to see if it is Not-a-Number
if(IsNaN(val))
{
printf("NaN");
return;
}
// print the integer part of the floating point
printf("%d", (int)val);
// if precision == 0, only print the integer part
if(!precision)
return;
// now on to the decimal potion
printf(".");
// remove the integer part
val -= (double)((int)val);
/* on every iteration, make sure there are still decimal places left that are non-zero,
and make sure we're still within the user-defined precision range. */
while(val > (double)((int)val) && cur_prec++ < precision+1)
{
// move the next decimal into the integer portion and print it
val *= 10;
printf("%d", (int)val);
/* if the value is == the floored value (integer portion),
then there are no more decimal places that are non-zero. */
if(val == (double)((int)val))
return;
// subtract the integer portion
val -= (double)((int)val);
}
}

View File

@ -0,0 +1,11 @@
#ifndef __H_KPRINTF
#define __H_KPRINTF 1
#include <stdarg.h>
int printf(char * fmt, ...);
int sprintf(char * buf, char * fmt, ...);
void hexDump (const char * desc, const void * addr, const int len);
#endif

View File

@ -0,0 +1,105 @@
#include "uart.h"
#include "stdint.h"
#define XUARTPS_CR_TXRST 0x00000002U /**< TX logic reset */
#define XUARTPS_CR_RXRST 0x00000001U /**< RX logic reset */
#define XUARTPS_CR_OFFSET 0x0000U /**< Control Register [8:0] */
#define XUARTPS_MR_OFFSET 0x0004U /**< Mode Register [9:0] */
#define XUARTPS_BAUDGEN_OFFSET 0x0018U /**< Baud Rate Generator [15:0] */
#define XUARTPS_BAUDDIV_OFFSET 0x0034U /**< Baud Rate Divider [7:0] */
#define XUARTPS_FIFO_OFFSET 0x0030U /**< FIFO [7:0] */
#define XUARTPS_SR_OFFSET 0x002CU /**< Channel Status [14:0] */
#define XPS_UART1_BASEADDR 0xE0001000U
#define XUARTPS_MR_CHMODE_NORM 0x00000000U /**< Normal mode */
#define XUARTPS_MR_STOPMODE_1_BIT 0x00000000U /**< 1 stop bit */
#define XUARTPS_MR_PARITY_NONE 0x00000020U /**< No parity mode */
#define XUARTPS_MR_CHARLEN_8_BIT 0x00000000U /**< 8 bits data */
#define XUARTPS_MR_CLKSEL 0x00000001U /**< Input clock selection */
#define XUARTPS_SR_TNFUL 0x00004000U /**< TX FIFO Nearly Full Status */
#define XUARTPS_SR_TACTIVE 0x00000800U /**< TX active */
#define XUARTPS_SR_RXEMPTY 0x00000002U /**< RX FIFO empty */
#define XUARTPS_CR_TX_DIS 0x00000020U /**< TX disabled. */
#define XUARTPS_CR_TX_EN 0x00000010U /**< TX enabled */
#define XUARTPS_CR_RX_DIS 0x00000008U /**< RX disabled. */
#define XUARTPS_CR_RX_EN 0x00000004U /**< RX enabled */
#define POINTER_TO_REGISTER(REG) ( *((volatile uint32_t*)(REG)))
#define UART_BASE XPS_UART1_BASEADDR
#define UART_CTRL POINTER_TO_REGISTER(UART_BASE + XUARTPS_CR_OFFSET) // Control Register
#define UART_MODE POINTER_TO_REGISTER(UART_BASE + XUARTPS_MR_OFFSET) // Mode Register
#define UART_BAUD_GEN POINTER_TO_REGISTER(UART_BASE + XUARTPS_BAUDGEN_OFFSET) // Baud Rate Generator "CD"
#define UART_BAUD_DIV POINTER_TO_REGISTER(UART_BASE + XUARTPS_BAUDDIV_OFFSET) // Baud Rate Divider "BDIV"
#define UART_FIFO POINTER_TO_REGISTER(UART_BASE + XUARTPS_FIFO_OFFSET) // FIFO
#define UART_STATUS POINTER_TO_REGISTER(UART_BASE + XUARTPS_SR_OFFSET) // Channel Status
#define BUFLEN 127
static uint16_t end_ndx;
static char buf[BUFLEN+1];
#define buf_len ((end_ndx - start_ndx) % BUFLEN)
static inline int inc_ndx(int n) { return ((n + 1) % BUFLEN); }
static inline int dec_ndx(int n) { return (((n + BUFLEN) - 1) % BUFLEN); }
void uart_send(char c) {
while (UART_STATUS & XUARTPS_SR_TNFUL);
UART_FIFO = c;
while (UART_STATUS & XUARTPS_SR_TACTIVE);
}
char uart_recv() {
if ((UART_STATUS & XUARTPS_SR_RXEMPTY) == XUARTPS_SR_RXEMPTY)
return 0;
return UART_FIFO;
}
char uart_recv_blocking() {
while ((UART_STATUS & XUARTPS_SR_RXEMPTY) == XUARTPS_SR_RXEMPTY);
return UART_FIFO;
}
void uart_setup(void) {
uint32_t r = 0; // Temporary value variable
r = UART_CTRL;
r &= ~(XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN); // Clear Tx & Rx Enable
r |= XUARTPS_CR_RX_DIS | XUARTPS_CR_TX_DIS; // Tx & Rx Disable
UART_CTRL = r;
UART_MODE = 0;
UART_MODE &= ~XUARTPS_MR_CLKSEL; // Clear "Input clock selection" - 0: clock source is uart_ref_clk
UART_MODE |= XUARTPS_MR_CHARLEN_8_BIT; // Set "8 bits data"
UART_MODE |= XUARTPS_MR_PARITY_NONE; // Set "No parity mode"
UART_MODE |= XUARTPS_MR_STOPMODE_1_BIT; // Set "1 stop bit"
UART_MODE |= XUARTPS_MR_CHMODE_NORM; // Set "Normal mode"
// baud_rate = sel_clk / (CD * (BDIV + 1) (ref: UG585 - TRM - Ch. 19 UART)
UART_BAUD_DIV = 6; // ("BDIV")
UART_BAUD_GEN = 124; // ("CD")
// Baud Rate = 100Mhz / (124 * (6 + 1)) = 115200 bps
UART_CTRL |= (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST); // TX & RX logic reset
r = UART_CTRL;
r |= XUARTPS_CR_RX_EN | XUARTPS_CR_TX_EN; // Set TX & RX enabled
r &= ~(XUARTPS_CR_RX_DIS | XUARTPS_CR_TX_DIS); // Clear TX & RX disabled
UART_CTRL = r;
}
void uart_back_up(void){
end_ndx = dec_ndx(end_ndx);
uart_send('\010');
uart_send(' ');
uart_send('\010');
}
void uart_puts(char * s){
while(*s){
uart_send(*(s++));
}
}

View File

@ -0,0 +1,11 @@
#ifndef __H_UART
#define __H_UART 1
void uart_send(char c);
char uart_recv();
char uart_recv_blocking();
void uart_setup(void);
void uart_back_up(void);
void uart_puts(char * s);
#endif

View File

View File

@ -0,0 +1,33 @@
#ifndef __H_ZYNQ
#define __H_ZYNQ 1
#define ZYNQ_PERIPH_PHY_BASE 0xF8000000
#define ZYNQ_PERIPH_TTC0_BASE (ZYNQ_PERIPH_PHY_BASE + 0x1000)
#define ZYNQ_PRI_PERIPH_PHYS_BASE 0xF8F00000
#define ZYNQ_PERIPH_SIZE 0x2000
#define ZYNQ_SCU_PHYS_BASE (ZYNQ_PRI_PERIPH_PHYS_BASE + 0)
#define ZYNQ_SCU_SIZE 0x0100
#define ZYNQ_GIC_CPU_PHYS_BASE (ZYNQ_PRI_PERIPH_PHYS_BASE + 0x100)
#define ZYNQ_GIC_CPU_SIZE 0x0100
#define ZYNQ_GTIMER_PHYS_BASE (ZYNQ_PRI_PERIPH_PHYS_BASE + 0x200)
#define ZYNQ_GTIMER_SIZE 0x0100
#define ZYNQ_PTIMER_WDT_PHYS_BASE (ZYNQ_PRI_PERIPH_PHYS_BASE + 0x600)
#define ZYNQ_PTIMER_WDT_SIZE 0x0100
#define ZYNQ_GIC_DIST_PHYS_BASE (ZYNQ_PRI_PERIPH_PHYS_BASE + 0x1000)
#define ZYNQ_GIC_DIST_SIZE 0x1000
#define WRITE32(_reg, _val) (*(volatile uint32_t*)&_reg = _val)
#define WRITE16(_reg, _val) (*(volatile uint16_t*)&_reg = _val)
#define WRITE8(_reg, _val) (*(volatile uint8_t*)&_reg = _val)
#define cpu_disable_interrups() asm ("cpsid if")
#define cpu_enable_interrups() asm ("cpsie if")
#endif

View File

@ -10,6 +10,10 @@ port = 2020
privkey = /home/joppe/.ssh/id_rsa
pubkey = /home/joppe/.ssh/id_rsa.pub
# ======================================
# BASIC FPGA WORKFLOW
# ======================================
# ######################################
# ISE IP block generation
[target.ip]
@ -91,3 +95,108 @@ files_verilog = OUT/synth/impl_netlist.v
#files_xci =
files_other = OUT/synth/impl_netlist.sdf
# ######################################
# ======================================
# PS/PL workflow
# ======================================
# ######################################
# Firmware compilation
[target.firmware]
toolchain = make
# Toolchain settings
output_files = build/app.elf DISASS
buildroot = SW
# Fileset
files_makefile = SW/Makefile
files_other = SW/linker.ld
SW/src/boot.S
SW/src/main.c
SW/src/printf.c
SW/src/printf.h
SW/src/uart.c
SW/src/uart.h
SW/src/xil_io.h
SW/src/zynq.h
OUT/ip/zynqps/ps7_init.c
OUT/ip/zynqps/ps7_init.h
# ######################################
# ######################################
# Firmware simulation
[target.firmsim]
toolchain = qemu
# Toolchain settings
arch = arm
machine = xilinx-zynq-a9
ram = 256M
extra_opts = -serial /dev/null -serial mon:stdio
# Fileset
files_executable = OUT/firmware/app.elf
# ######################################
# ######################################
# Device tree compilation
[target.devtree]
toolchain = make
# Toolchain settings
output_files = system.dtb system.dts
buildroot = SW/devicetree
# Fileset
files_makefile = SW/devicetree/Makefile
files_other = SW/devicetree/pcw.dtsi
SW/devicetree/pl.dtsi
SW/devicetree/skeleton.dtsi
SW/devicetree/system-top.dts
SW/devicetree/zynq-7000.dtsi
SW/devicetree/zynq-pl-remoteport.dtsi
SW/devicetree/include/dt-bindings/clock/xlnx-versal-clk.h
SW/devicetree/include/dt-bindings/power/xlnx-versal-power.h
SW/devicetree/include/dt-bindings/reset/xlnx-versal-resets.h
# ######################################
# ######################################
# Hardware-firmware cosimulation PS part
[target.cosim_ps]
toolchain = qemu
# Toolchain settings
arch = xilinxarm
machine = arm-generic-fdt-7series
ram = 256M
extra_opts = -serial /dev/null -serial mon:stdio -dtb ../OUT/devtree/system.dtb \
-machine-path /tmp \
-icount 1 -sync-quantum 100000 \
-device loader,addr=0xfd1a0104,data=0x8000000e,data-len=4
# Fileset
files_executable = OUT/firmware/app.elf
files_other = OUT/devtree/system.dtb
# ######################################
# ######################################
# Hardware-firmware cosimulation PL part
# Note: currently not using xsim since compilation with xilinx
# provided tools are horrible on linux
[target.cosim_pl]
toolchain = questa
# Toolchain settings
toplevel = tb_cosim
vcdlevels = 20
runtime = all
# Fileset
files_vhdl = RTL/heartbeat.vhd
# files_verilog =
files_sysverilog = SIM/tb_cosim.sv
files_c = SIM/c/remote-port-proto.c SIM/c/cosim.c
files_other = SIM/c/remote-port-proto.h
# ######################################

View File

@ -11,12 +11,16 @@ import shutil
def do(config, target, log, subprocesses, prefix='.'):
shutil.rmtree(config.get('project', 'build_dir', fallback='build'), True)
stopafter = config.get(f'target.{target}', 'stopafter', fallback='')
log("Syntesize:")
res = xst(config, target, log, subprocesses, prefix)
if res != 0:
log("ERROR: xst returned with", res)
return res
if stopafter=='synth':
return res
log("Implement")
@ -34,6 +38,8 @@ def do(config, target, log, subprocesses, prefix='.'):
if res != 0:
log("ERROR: par returned with", res)
return res
if stopafter=='impl':
return res
log("Generate output files")

View File

@ -0,0 +1,83 @@
from distutils.command.build import build
import shutil
import os
import time
import subprocess
def do(config, target, log, subprocesses, prefix='.'):
shutil.rmtree(config.get('project', 'build_dir', fallback='build'), True)
log("Starting cocotb")
log(" - parsing options")
toplevels = config.get(f'target.{target}', 'toplevels', fallback='').split()
simulator = config.get(f'target.{target}', 'simulator', fallback='ghdl')
files_vhdl = config.get(f'target.{target}', 'files_vhdl', fallback='').split()
files_verilog = config.get(f'target.{target}', 'files_verilog', fallback='').split()
files_python = config.get(f'target.{target}', 'files_python', fallback='').split()
files_python_other = config.get(f'target.{target}', 'files_python_other', fallback='').split()
files_other = config.get(f'target.{target}', 'files_other', fallback='').split()
toplevel_langs = config.get(f'target.{target}', 'toplevel_langs', fallback='').split()
build_dir = config.get(f'project', 'build_dir', fallback='build')
out_dir = config.get(f'project', 'out_dir', fallback='out')
prefix = f'{os.getcwd()}/{prefix}%%'.replace('/.%%', '').replace('%%', '')
build_dir = f'{prefix}/{build_dir}'
out_dir = f'{prefix}/{out_dir}/{target}'
log(" - creating output directories")
os.makedirs(build_dir, exist_ok=True)
os.makedirs(out_dir, exist_ok=True)
log(" - copy needed files")
for f in files_python_other:
shutil.copy(f"{prefix}/{f}", f"{build_dir}/{os.path.basename(f)}")
for f in files_other:
d = os.path.dirname(f)
os.makedirs(f"{build_dir}/{d}", exist_ok=True)
shutil.copy(f"{prefix}/{f}", f"{build_dir}/{f}")
res = 0
i = 0
for pfile in files_python:
log(" - copy", pfile)
shutil.copy(f"{prefix}/{pfile}", build_dir)
log(" - writing Makefile for", pfile)
with open(f'{build_dir}/Makefile', 'w') as f:
f.write(f".SILENT:\nSIM ?= {simulator}\nTOPLEVEL_LANG ?= {toplevel_langs[i]}\nWAVES = 1\n")
f.write(f"TOPLEVEL = {toplevels[i]}\nMODULE = {'.'.join(os.path.basename(pfile).split('.')[0:-1])}\n")
for vfile in files_vhdl:
f.write(f"VHDL_SOURCES += {prefix}/{vfile}\n")
for vfile in files_verilog:
f.write(f"VERILOG_SOURCES += {prefix}/{vfile}\n")
if simulator=='ghdl':
f.write(f"SIM_ARGS += --vcd={os.path.basename(pfile)}.vcd\n")
f.write("include $(shell cocotb-config --makefiles)/Makefile.sim\n")
log(" - start cocotb")
p = subprocess.Popen(f"make 2>&1 | tee {os.path.basename(pfile)}.log",
shell=True, cwd=build_dir,
stdin=subprocess.DEVNULL,
# stdout=subprocess.DEVNULL,
# stderr=subprocess.DEVNULL
)
subprocesses.append(p)
while p.poll() is None:
time.sleep(1)
res |= p.returncode
shutil.copy(f"{build_dir}/{os.path.basename(pfile)}.log", out_dir)
if simulator=='ghdl':
shutil.copy(f"{build_dir}/{os.path.basename(pfile)}.vcd", out_dir)
elif simulator=='questa':
os.system(f'wlf2vcd -o {out_dir}/{os.path.basename(pfile)}.vcd {build_dir}/vsim.wlf')
i += 1
return res

View File

@ -6,7 +6,10 @@ import subprocess
def execp(cmd, subprocesses, cwd):
p = subprocess.Popen(cmd,
shell=True, cwd=cwd,
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
stdin=subprocess.DEVNULL,
#stdout=subprocess.DEVNULL,
#stderr=subprocess.DEVNULL
)
subprocesses.append(p)
while p.poll() is None:
time.sleep(1)
@ -25,6 +28,7 @@ def do(config, target, log, subprocesses, prefix='.'):
ghdle_opts = config.get(f'target.{target}', 'ghdle_opts', fallback='')
ghdlr_opts = config.get(f'target.{target}', 'ghdlr_opts', fallback='')
files_vhdl = config.get(f'target.{target}', 'files_vhdl', fallback='').split()
files_other = config.get(f'target.{target}', 'files_other', fallback='').split()
build_dir = config.get(f'project', 'build_dir', fallback='build')
out_dir = config.get(f'project', 'out_dir', fallback='out')
@ -36,6 +40,12 @@ def do(config, target, log, subprocesses, prefix='.'):
os.makedirs(build_dir, exist_ok=True)
os.makedirs(out_dir, exist_ok=True)
log(" - copy needed files")
for f in files_other:
d = os.path.dirname(f)
os.makedirs(f"{build_dir}/{d}", exist_ok=True)
shutil.copy(f"{prefix}/{f}", f"{build_dir}/{f}")
log(" - analyze files")
res = 0
for f in files_vhdl:
@ -60,7 +70,8 @@ def do(config, target, log, subprocesses, prefix='.'):
extra = ''
if runtime!='all':
extra = f'--stop-time={runtime.replace(" ", "")}'
res = execp(f"echo {toplevel} >> r.log && ghdl -r {ghdlr_opts} {extra} {toplevel} --vcd=out.vcd 2>&1 1>> r.log", subprocesses, build_dir)
# res = execp(f"echo {toplevel} >> r.log && ghdl -r {ghdlr_opts} {toplevel} {extra} --vcd=out.vcd --wave=out.ghw 2>&1 | tee r.log", subprocesses, build_dir)
res = execp(f"echo {toplevel} >> r.log && ./{toplevel} {ghdlr_opts} {extra} --vcd=out.vcd --wave=out.ghw 2>&1 | tee r.log", subprocesses, build_dir)
log(" - copy logs")
shutil.copy(f'{build_dir}/r.log', f'{out_dir}/r.log')
# Ignore simulation errors: vhdl stopping with failure results in returned with 1
@ -70,5 +81,6 @@ def do(config, target, log, subprocesses, prefix='.'):
log(" - copy output files")
shutil.copy(f'{build_dir}/out.vcd', f'{out_dir}/out.vcd')
shutil.copy(f'{build_dir}/out.ghw', f'{out_dir}/out.ghw')
return 0

View File

@ -0,0 +1,135 @@
import shutil
import os
import time
import subprocess
import html2text
def do(config, target, log, subprocesses, prefix='.'):
shutil.rmtree(config.get('project', 'build_dir', fallback='build'), True)
shutil.rmtree(config.get('project', 'out_dir', fallback='out'), True)
log(" - parsing options")
family = config.get(f'target.{target}', 'family', fallback='')
device = config.get(f'target.{target}', 'device', fallback='')
toplevel = config.get(f'target.{target}', 'toplevel', fallback='toplevel')
files_vhdl = config.get(f'target.{target}', 'files_vhdl', fallback='').split()
files_verilog = config.get(f'target.{target}', 'files_verilog', fallback='').split()
files_con= config.get(f'target.{target}', 'files_con', fallback='').split()
build_dir = config.get(f'project', 'build_dir', fallback='build')
out_dir = config.get(f'project', 'out_dir', fallback='out')
prefix = f'{os.getcwd()}/{prefix}'
build_dir = f'{prefix}/{build_dir}'
out_dir = f'{prefix}/{out_dir}/{target}'
log(" - creating output directories")
os.makedirs(build_dir, exist_ok=True)
os.makedirs(out_dir, exist_ok=True)
log(" - writing scripts")
with open(f'{build_dir}/synth.tcl', 'w') as f:
f.write(f'set_device {device} -name {family}\n')
for s in files_vhdl:
if s=='':
continue
f.write(f'add_file {prefix}/{s}\n')
for s in files_verilog:
if s=='':
continue
f.write(f'add_file {prefix}/{s}\n')
for s in files_con:
if s=='':
continue
f.write(f'add_file {prefix}/{s}\n')
f.write('set_option -synthesis_tool gowinsynthesis\n')
f.write(f'set_option -output_base_name {toplevel}\n')
f.write(f'set_option -top_module {toplevel}\n')
f.write('run syn\n')
with open(f'{build_dir}/pnr.tcl', 'w') as f:
f.write(f'set_device {device} -name {family}\n')
f.write('set_option -synthesis_tool gowinsynthesis\n')
f.write(f'set_option -output_base_name {toplevel}\n')
f.write(f'set_option -top_module {toplevel}\n')
for s in files_con:
if s=='':
continue
f.write(f'add_file {prefix}/{s}\n')
f.write(f'add_file {build_dir}/impl/gwsynthesis/{toplevel}.vg\n')
f.write('run pnr\n')
log(' - run syntesis')
p = subprocess.Popen(f"gw_sh synth.tcl",
shell = True,
cwd = build_dir,
stdin = subprocess.DEVNULL,
# stdout = subprocess.DEVNULL,
# stderr = subprocess.DEVNULL,
)
subprocesses.append(p)
while p.poll() is None:
time.sleep(1)
res = p.returncode
shutil.copy(f'{build_dir}/impl/gwsynthesis/{toplevel}.log', f'{out_dir}/synth.log')
if res!=0:
log("ERROR: synthesis failed with:", res)
return res
shutil.copy(f'{build_dir}/impl/gwsynthesis/{toplevel}.vg', f'{out_dir}/synth_netlist.vg')
with open(f'{build_dir}/impl/gwsynthesis/{toplevel}_syn.rpt.html', 'r') as fin, open(f'{out_dir}/synth_rpt.md', 'w') as fout:
text_maker = html2text.HTML2Text()
text_maker.bypass_tables = False
text_maker.ignore_links = True
text_maker.body_width = 500
fout.write(text_maker.handle(fin.read()))
log(' - run PnR')
p = subprocess.Popen(f"gw_sh pnr.tcl",
shell = True,
cwd = build_dir,
stdin = subprocess.DEVNULL,
# stdout = subprocess.DEVNULL,
# stderr = subprocess.DEVNULL,
)
subprocesses.append(p)
while p.poll() is None:
time.sleep(1)
res = p.returncode
shutil.copy(f'{build_dir}/impl/pnr/{toplevel}.log', f'{out_dir}/pnr.log')
if res!=0:
log("ERROR: pnr failed with:", res)
return res
shutil.copy(f'{build_dir}/impl/pnr/{toplevel}.fs', f'{out_dir}/{toplevel}.fs')
shutil.copy(f'{build_dir}/impl/pnr/{toplevel}.bin', f'{out_dir}/{toplevel}.bin')
with open(f'{build_dir}/impl/pnr/{toplevel}.rpt.html', 'r') as fin, open(f'{out_dir}/rpt.md', 'w') as fout:
text_maker = html2text.HTML2Text()
text_maker.bypass_tables = False
text_maker.ignore_links = True
text_maker.body_width = 500
fout.write(text_maker.handle(fin.read()))
with open(f'{build_dir}/impl/pnr/{toplevel}.power.html', 'r') as fin, open(f'{out_dir}/power.md', 'w') as fout:
text_maker = html2text.HTML2Text()
text_maker.bypass_tables = False
text_maker.ignore_links = True
text_maker.body_width = 500
fout.write(text_maker.handle(fin.read()))
with open(f'{build_dir}/impl/pnr/{toplevel}.pin.html', 'r') as fin, open(f'{out_dir}/pin.md', 'w') as fout:
text_maker = html2text.HTML2Text()
text_maker.bypass_tables = False
text_maker.ignore_links = True
text_maker.body_width = 500
fout.write(text_maker.handle(fin.read()))
with open(f'{build_dir}/impl/pnr/{toplevel}_tr_content.html', 'r') as fin, open(f'{out_dir}/timing.md', 'w') as fout:
text_maker = html2text.HTML2Text()
text_maker.bypass_tables = False
text_maker.ignore_links = True
text_maker.body_width = 500
fout.write(text_maker.handle(fin.read()))
return res

View File

@ -10,12 +10,13 @@ def do(config, target, log, subprocesses, prefix='.'):
log(" - parsing options")
toplevel = config.get(f'target.{target}', 'toplevel', fallback='toplevel')
vcdlevels = config.get(f'target.{target}', 'vcdlevels', fallback='1')
vcdlevels = config.get(f'target.{target}', 'vcdlevels', fallback='10')
runtime = config.get(f'target.{target}', 'runtime', fallback='100 ns')
fuse_opts = config.get(f'target.{target}', 'fuse_opts', fallback='')
isim_opts = config.get(f'target.{target}', 'isim_opts', fallback='')
files_vhdl = config.get(f'target.{target}', 'files_vhdl', fallback='').split()
files_verilog = config.get(f'target.{target}', 'files_verilog', fallback='').split()
files_other = config.get(f'target.{target}', 'files_other', fallback='').split()
build_dir = config.get(f'project', 'build_dir', fallback='build')
out_dir = config.get(f'project', 'out_dir', fallback='out')
@ -30,6 +31,12 @@ def do(config, target, log, subprocesses, prefix='.'):
os.makedirs(build_dir, exist_ok=True)
os.makedirs(out_dir, exist_ok=True)
log(" - copy needed files")
for f in files_other:
d = os.path.dirname(f)
os.makedirs(f"{build_dir}/{d}", exist_ok=True)
shutil.copy(f"{prefix}/{f}", f"{build_dir}/{f}")
log(" - writing project file")
with open(f'{build_dir}/sim.prj', 'w') as f:
for s in files_vhdl:
@ -51,7 +58,7 @@ def do(config, target, log, subprocesses, prefix='.'):
res = p.returncode
log(" - copy logs")
shutil.copy(f'{build_dir}/ffuse.log', f'{out_dir}/fuse.log')
shutil.copy(f'{build_dir}/fuse.log', f'{out_dir}/fuse.log')
if res!=0:
log("ERROR: fuse returned with:", res)
@ -61,15 +68,18 @@ def do(config, target, log, subprocesses, prefix='.'):
with open(f'{build_dir}/sim.tcl', 'w') as f:
f.write("onerror {resume}\n")
f.write("vcd dumpfile sim.vcd\n")
f.write(f"vcd dumpvars -m {toplevel} -l {vcdlevels}\n")
f.write(f"vcd dumpvars -m {toplevel.split()[0]} -l {vcdlevels}\n")
f.write("vcd dumpon\n")
f.write(f"run {runtime}\n")
f.write("vcd dumpflush\nquit\n")
log(" - run sim")
p = subprocess.Popen(f"./sim {isim_opts} -tclbatch sim.tcl > sim.log",
p = subprocess.Popen(f"./sim {isim_opts} -tclbatch sim.tcl | tee sim.log",
shell=True, cwd=build_dir,
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
stdin=subprocess.DEVNULL,
# stdout=subprocess.DEVNULL,
# stderr=subprocess.DEVNULL
)
subprocesses.append(p)
while p.poll() is None:
time.sleep(1)

View File

@ -0,0 +1,52 @@
import shutil
import os
import time
import subprocess
def do(config, target, log, subprocesses, prefix='.'):
shutil.rmtree(config.get('project', 'build_dir', fallback='build'), True)
log("Starting make build process")
log(" - parsing options")
files_makefile = config.get(f'target.{target}', 'files_makefile', fallback='')
buildroot = config.get(f'target.{target}', 'buildroot', fallback='.')
output_files = config.get(f'target.{target}', 'output_files', fallback='').split()
build_dir = config.get(f'project', 'build_dir', fallback='build')
out_dir = config.get(f'project', 'out_dir', fallback='out')
prefix = f'{os.getcwd()}/{prefix}'
build_dir = f'{prefix}/{build_dir}'
out_dir = f'{prefix}/{out_dir}/{target}'
log(" - creating output directories")
os.makedirs(build_dir, exist_ok=True)
os.makedirs(out_dir, exist_ok=True)
log(" - Copy makefile to build directory")
shutil.copy(f"{prefix}/{files_makefile}", f"{build_dir}/Makefile")
log(" - run make")
p = subprocess.Popen(f"BUILDROOT={prefix}/{buildroot} make 2>make.log",
shell=True, cwd=build_dir,
stdin=subprocess.DEVNULL,
# stdout=subprocess.DEVNULL,
# stderr=subprocess.DEVNULL
)
subprocesses.append(p)
while p.poll() is None:
time.sleep(1)
res = p.returncode
log(" - copy logs")
shutil.copy(f'{build_dir}/make.log', f'{out_dir}/make.log')
if res!=0:
log("ERROR: make returned with:", res)
return res
log(" - copy output files")
for f in output_files:
shutil.copy(f'{build_dir}/{f}', f'{out_dir}/{os.path.basename(f)}')
return 0

View File

@ -0,0 +1,41 @@
import shutil
import os
import time
import subprocess
def do(config, target, log, subprocesses, prefix='.'):
shutil.rmtree(config.get('project', 'build_dir', fallback='build'), True)
log("Starting QEMU simulation")
log(" - parsing options")
files_executable = config.get(f'target.{target}', 'files_executable', fallback='')
arch = config.get(f'target.{target}', 'arch', fallback='arm')
machine = config.get(f'target.{target}', 'machine', fallback='xilinx-zynq-a9')
ram = config.get(f'target.{target}', 'ram', fallback='500M')
extra_opts = config.get(f'target.{target}', 'extra_opts', fallback='')
build_dir = config.get(f'project', 'build_dir', fallback='build')
out_dir = config.get(f'project', 'out_dir', fallback='out')
prefix = f'{os.getcwd()}/{prefix}'
build_dir = f'{prefix}/{build_dir}'
out_dir = f'{prefix}/{out_dir}/{target}'
log(" - creating output directories")
os.makedirs(build_dir, exist_ok=True)
os.makedirs(out_dir, exist_ok=True)
log(" - run QEMU, quit r(m)build to stop")
p = subprocess.Popen(f"qemu-system-{arch} -machine {machine} -kernel {prefix}/{files_executable} {extra_opts} -m {ram} -nographic 2>error.log | tee run.log",
shell=True, cwd=build_dir,
stdin=subprocess.DEVNULL)
subprocesses.append(p)
while p.poll() is None:
time.sleep(1)
res = p.returncode
log(" - copy logs")
shutil.copy(f'{build_dir}/run.log', f'{out_dir}/run.log')
shutil.copy(f'{build_dir}/error.log', f'{out_dir}/error.log')
return 0

View File

@ -0,0 +1,87 @@
from importlib.metadata import files
import shutil
import os
import time
import subprocess
def do(config, target, log, subprocesses, prefix='.'):
# shutil.rmtree(config.get('project', 'build_dir', fallback='build'), True)
log("Starting simulation")
log(" - parsing options")
toplevel = config.get(f'target.{target}', 'toplevel', fallback='toplevel')
runtime = config.get(f'target.{target}', 'runtime', fallback='100 ns')
vsim_opts = config.get(f'target.{target}', 'vsim_opts', fallback='')
vcom_opts = config.get(f'target.{target}', 'vcom_opts', fallback='')
vlog_opts = config.get(f'target.{target}', 'vlog_opts', fallback='')
files_vhdl = config.get(f'target.{target}', 'files_vhdl', fallback='').split()
files_verilog = config.get(f'target.{target}', 'files_verilog', fallback='').split()
files_sysverilog = config.get(f'target.{target}', 'files_sysverilog', fallback='').split()
files_c = config.get(f'target.{target}', 'files_c', fallback='').split()
files_other = config.get(f'target.{target}', 'files_other', fallback='').split()
build_dir = config.get(f'project', 'build_dir', fallback='build')
out_dir = config.get(f'project', 'out_dir', fallback='out')
prefix = f'{os.getcwd()}/{prefix}'
build_dir = f'{prefix}/{build_dir}'
out_dir = f'{prefix}/{out_dir}/{target}'
log(" - creating output directories")
os.makedirs(build_dir, exist_ok=True)
os.makedirs(out_dir, exist_ok=True)
log(" - copy needed files")
for f in files_other:
d = os.path.dirname(f)
os.makedirs(f"{build_dir}/{d}", exist_ok=True)
shutil.copy(f"{prefix}/{f}", f"{build_dir}/{f}")
files_c_wp = {f'{prefix}/{f}' for f in files_c}
log(" - writing compile file")
with open(f'{build_dir}/do.sh', 'w') as f:
f.write(f'vlib work\nvmap work work\n')
for s in files_verilog:
f.write(f"vlog {vlog_opts} {prefix}/{s}\n")
for s in files_vhdl:
f.write(f"vcom {vcom_opts} {prefix}/{s}\n")
for s in files_sysverilog:
f.write(f"vlog -sv {vlog_opts} {prefix}/{s}\n")
f.write(f"gcc -g -fPIC -shared -Bsymbolic -o import.so {' '.join(files_c_wp)}\n")
extra = vsim_opts
if len(files_c_wp)>0:
extra = ' -sv_lib import'
f.write(f"vsim -c -do do.do {extra} -vcd=+multid+vhvar -vcddump=out.vcd {toplevel}")
log(" - writing do file")
rtime = "-all"
if runtime != "all":
rtime = runtime
with open(f'{build_dir}/do.do', 'w') as f:
# f.write(f"vcd file out.vcd\n vcd add -r -in -out -inout -internal -ports *\nrun {rtime}\nquit\n");
f.write(f"\nrun {rtime}\nquit\n");
log(" - run vsim")
p = subprocess.Popen(f"bash ./do.sh 2>&1 | tee do.log",
shell=True, cwd=build_dir,
stdin=subprocess.DEVNULL,
#stdout=subprocess.DEVNULL,
#stderr=subprocess.DEVNULL
)
subprocesses.append(p)
while p.poll() is None:
time.sleep(1)
res = p.returncode
log(" - copy logs")
shutil.copy(f'{build_dir}/do.log', f'{out_dir}/do.log')
if res!=0:
log("ERROR: vsim returned with", res)
return res
log(" - copy output files")
shutil.copy(f'{build_dir}/out.vcd', f'{out_dir}/out.vcd')
return 0

View File

@ -6,7 +6,9 @@ import subprocess
def execp(cmd, subprocesses, cwd):
p = subprocess.Popen(cmd,
shell=True, cwd=cwd,
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
stdin=subprocess.DEVNULL,
# stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
subprocesses.append(p)
while p.poll() is None:
time.sleep(1)
@ -55,7 +57,10 @@ def do(config, target, log, subprocesses, prefix='.'):
for d in os.listdir(f'{build_dir}'):
if os.path.isdir(f'{build_dir}/{d}') and d.startswith(oname):
shutil.copy(f'{build_dir}/{d}/logfile.txt', f'{out_dir}/{d}.log')
shutil.copytree(f'{build_dir}/{d}/engine_0', f'{out_dir}/{d}', dirs_exist_ok=True)
try:
shutil.copytree(f'{build_dir}/{d}/engine_0', f'{out_dir}/{d}', dirs_exist_ok=True)
except FileNotFoundError:
pass
if res!=0:
log(" - [-]")

View File

@ -20,7 +20,10 @@ def bitgen(config, target, log, subprocesses, prefix='.') -> int:
log(" - run bitgen")
p = subprocess.Popen(f"bitgen -intstyle xflow {bitgen_opts} -g Binary:Yes -w {out_dir}/{target}.ncd {target}.bit {out_dir}/{target}.pcf 2> bitgen.log",
shell=True, cwd=build_dir,
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
stdin=subprocess.DEVNULL,
# stdout=subprocess.DEVNULL,
# stderr=subprocess.DEVNULL
)
subprocesses.append(p)
while p.poll() is None:
time.sleep(1)

View File

@ -10,7 +10,7 @@ def coregen(config, target, log, subprocesses, prefix='.') -> int:
package = config.get(f'target.{target}', 'package', fallback='')
speedgrade = config.get(f'target.{target}', 'speedgrade', fallback='')
coregen_opts = config.get(f'target.{target}', 'coregen_opts', fallback='')
files_xco = config.get(f'target.{target}', 'files_xco', fallback='').split()
files_def = config.get(f'target.{target}', 'files_def', fallback='').split()
build_dir = config.get(f'project', 'build_dir', fallback='build')
out_dir = config.get(f'project', 'out_dir', fallback='out')
@ -24,7 +24,7 @@ def coregen(config, target, log, subprocesses, prefix='.') -> int:
res = 0
for fxco in files_xco:
for fxco in files_def:
cname = fxco.split('/')[-1].split('.')[0]
log(" - Generating", cname, "...")
@ -40,6 +40,7 @@ def coregen(config, target, log, subprocesses, prefix='.') -> int:
f.write(f'SET flowvendor = Other\n')
f.write(f'SET verilogsim = true\n')
f.write(f'SET vhdlsim = true\n')
f.write(f'SET implementationfiletype = ngc\n')
log(" - run coregen")
p = subprocess.Popen(f"coregen {coregen_opts} -p coregen_{cname}.cgp -b {prefix}/{fxco}",
@ -55,9 +56,22 @@ def coregen(config, target, log, subprocesses, prefix='.') -> int:
if res==0:
log(" - copy output files")
shutil.copy(f'{build_dir}/{cname}.vhd', f'{out_dir}/{cname}.vhd')
shutil.copy(f'{build_dir}/{cname}.v', f'{out_dir}/{cname}.v')
# shutil.copy(f'{build_dir}/{cname}.ngc', f'{out_dir}/{cname}.ngc')
try:
shutil.copy(f'{build_dir}/{cname}.vhd', f'{out_dir}/{cname}.vhd')
except FileNotFoundError:
pass
try:
shutil.copy(f'{build_dir}/{cname}.v', f'{out_dir}/{cname}.v')
except FileNotFoundError:
pass
try:
shutil.copy(f'{build_dir}/{cname}.ngc', f'{out_dir}/{cname}.ngc')
except FileNotFoundError:
pass
try:
shutil.copy(f'{build_dir}/{cname}.xco', f'{out_dir}/{cname}.xco')
except FileNotFoundError:
pass
else:
return res

View File

@ -24,7 +24,10 @@ def map(config, target, log, subprocesses, prefix='.') -> int:
log(" - run map")
p = subprocess.Popen(f"map -intstyle xflow -p {devstring} -detail {map_opts} -ol high -xe n -w {out_dir}/{target}.ngd -o impl.map.ncd impl.pcf",
shell=True, cwd=build_dir,
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
stdin=subprocess.DEVNULL,
# stdout=subprocess.DEVNULL,
# stderr=subprocess.DEVNULL
)
subprocesses.append(p)
while p.poll() is None:
time.sleep(1)

View File

@ -25,7 +25,10 @@ def ngdbuild(config, target, log, subprocesses, prefix='.') -> int:
log(" - run ngdbuild")
p = subprocess.Popen(f"ngdbuild -intstyle xflow -p {devstring} -uc {prefix}/{files_con[0]} {ngdbuild_opts} {out_dir}/{target}.ngc impl.ngd",
shell=True, cwd=build_dir,
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
stdin=subprocess.DEVNULL,
# stdout=subprocess.DEVNULL,
# stderr=subprocess.DEVNULL
)
subprocesses.append(p)
while p.poll() is None:
time.sleep(1)

View File

@ -28,5 +28,6 @@ def trce(config, target, log, subprocesses, prefix='.') -> int:
log(" - copy logs")
shutil.copy(f'{build_dir}/{target}.twr', f'{out_dir}/timing.log')
shutil.copy(f'{build_dir}/{target}.twx', f'{out_dir}/timing.twx')
return res

View File

@ -10,6 +10,8 @@ def xst(config, target, log, subprocesses, prefix='.') -> int:
speedgrade = config.get(f'target.{target}', 'speedgrade', fallback='')
toplevel = config.get(f'target.{target}', 'toplevel', fallback='toplevel')
xst_opts = config.get(f'target.{target}', 'xst_opts', fallback='')
netgensynth_opts = config.get(f'target.{target}', 'netgensynth_opts', fallback='-ofmt verilog')
netgensynth_type = config.get(f'target.{target}', 'netgensynth_type', fallback='-sim')
files_vhdl = config.get(f'target.{target}', 'files_vhdl', fallback='').split()
files_verilog = config.get(f'target.{target}', 'files_verilog', fallback='').split()
build_dir = config.get(f'project', 'build_dir', fallback='build')
@ -39,22 +41,52 @@ def xst(config, target, log, subprocesses, prefix='.') -> int:
with open(f'{build_dir}/prj.scr', 'w') as f:
f.write(f'run\n-ifn syn.prj\n-ofn syn.ngc\n-ifmt mixed\n')
f.write(f'-top {toplevel}\n')
f.write(f'-p {devstring}\n-glob_opt max_delay -opt_mode speed')
f.write(f'-p {devstring}\n-glob_opt max_delay -opt_mode speed\n')
f.write(f'-read_cores YES')
log(" - run xst")
p = subprocess.Popen(f"xst -intstyle xflow {xst_opts} -ifn prj.scr",
shell=True, cwd=build_dir,
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
stdin=subprocess.DEVNULL,
# stdout=subprocess.DEVNULL,
# stderr=subprocess.DEVNULL
)
subprocesses.append(p)
while p.poll() is None:
time.sleep(1)
res = p.returncode
if res==0:
log(" - copy output files")
shutil.copy(f'{build_dir}/syn.ngc', f'{out_dir}/{target}.ngc')
log(" - run netgen")
extra = ""
if netgensynth_type=="-sim" and not netgensynth_opts.__contains__("-ofmt vhdl"):
extra = "-insert_glbl true -ism"
p = subprocess.Popen(f"netgen -intstyle xflow {netgensynth_type} -w {extra} {netgensynth_opts} {out_dir}/{target}.ngc 2>&1 >> prj.srp",
shell=True, cwd=build_dir,
stdin=subprocess.DEVNULL,
# stdout=subprocess.DEVNULL,
# stderr=subprocess.DEVNULL
)
subprocesses.append(p)
while p.poll() is None:
time.sleep(1)
res |= p.returncode
log(" - copy logs")
shutil.copy(f'{build_dir}/prj.srp', f'{out_dir}/xst.log')
if res==0:
log(" - copy output files")
shutil.copy(f'{build_dir}/syn.ngc', f'{out_dir}/{target}.ngc')
try:
shutil.copy(f'{build_dir}/{target}.v', f'{out_dir}/{target}-synth.v')
except FileNotFoundError:
pass
try:
shutil.copy(f'{build_dir}/{target}.vhd', f'{out_dir}/{target}-synth.vhd')
except FileNotFoundError:
pass
return res

View File

@ -16,6 +16,7 @@ def do(config, target, log, subprocesses, prefix='.'):
files_verilog = config.get(f'target.{target}', 'files_verilog', fallback='').split()
files_sysverilog = config.get(f'target.{target}', 'files_sysverilog', fallback='').split()
files_xci = config.get(f'target.{target}', 'files_xci', fallback='').split()
files_c = config.get(f'target.{target}', 'files_c', fallback='').split()
files_other = config.get(f'target.{target}', 'files_other', fallback='').split()
build_dir = config.get(f'project', 'build_dir', fallback='build')
out_dir = config.get(f'project', 'out_dir', fallback='out')
@ -48,7 +49,9 @@ def do(config, target, log, subprocesses, prefix='.'):
for s in files_other:
f.write(f"add_files -norecurse -scan_for_includes \"{prefix}/{s}\"\n")
f.write(f"import_files -norecurse \"{prefix}/{s}\"\n")
# TODO C files for VPI
for s in files_c:
f.write(f"add_files -norecurse -scan_for_includes \"{prefix}/{s}\"\n")
f.write(f"import_files -norecurse \"{prefix}/{s}\"\n")
f.write(f"set_property top {toplevel} [get_filesets sim_1]\n")
f.write("set_property top_lib xil_defaultlib [get_filesets sim_1]\n")
@ -106,7 +109,7 @@ def do(config, target, log, subprocesses, prefix='.'):
log(" - compile")
p = subprocess.Popen(f'bash compile.sh',
p = subprocess.Popen(f'bash compile.sh 2>&1 | tee comp.log',
shell=True, cwd=f'{build_dir}/sim/sim.sim/sim_1/behav/xsim',
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
subprocesses.append(p)
@ -115,7 +118,7 @@ def do(config, target, log, subprocesses, prefix='.'):
res = p.returncode
log(" - copy logs")
shutil.copy(f'{build_dir}/sim/sim.sim/sim_1/behav/xsim/compile.log', f'{out_dir}/compile.log')
shutil.copy(f'{build_dir}/sim/sim.sim/sim_1/behav/xsim/comp.log', f'{out_dir}/compile.log')
if res!=0:
log("ERROR: compile returned with", res)
@ -123,7 +126,7 @@ def do(config, target, log, subprocesses, prefix='.'):
log(" - elaborate")
p = subprocess.Popen(f'bash elaborate.sh',
p = subprocess.Popen(f'bash elaborate.sh 2>&1 | tee elab.log',
shell=True, cwd=f'{build_dir}/sim/sim.sim/sim_1/behav/xsim',
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
subprocesses.append(p)
@ -132,7 +135,7 @@ def do(config, target, log, subprocesses, prefix='.'):
res = p.returncode
log(" - copy logs")
shutil.copy(f'{build_dir}/sim/sim.sim/sim_1/behav/xsim/elaborate.log', f'{out_dir}/elaborate.log')
shutil.copy(f'{build_dir}/sim/sim.sim/sim_1/behav/xsim/elab.log', f'{out_dir}/elaborate.log')
if res!=0:
log("ERROR: elaborate returned with", res)
@ -144,7 +147,7 @@ def do(config, target, log, subprocesses, prefix='.'):
log(" - simulate")
p = subprocess.Popen(f'bash simulate.sh',
p = subprocess.Popen(f'bash simulate.sh 2>&1 | tee simulate.log',
shell=True, cwd=f'{build_dir}/sim/sim.sim/sim_1/behav/xsim',
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
subprocesses.append(p)

View File

@ -1,12 +1,15 @@
#!/usr/bin/env python3
import configparser
from re import sub
import sys
import signal
def log(*args):
print(*args)
sys.stdout.flush()
def print_help():
log("Unified FPGA synthesizer frontend\r\n(c) Joppe Blondel - 2022\r\n")
log(f"Usage: {sys.argv[0]} [ OPTIONS ] target ...")
@ -45,31 +48,38 @@ if __name__=="__main__":
subprocesses = []
try:
def sighandler(num, frame):
if num==signal.SIGINT:
log("\rStopping rbuild")
for p in subprocesses:
p.terminate()
signal.alarm(4)
elif num==signal.SIGALRM:
log("Force killing subprocesses")
for p in subprocesses:
p.kill()
exit(0)
for target in targets:
signal.signal(signal.SIGINT, sighandler)
signal.signal(signal.SIGALRM, sighandler)
log("Target", target)
for target in targets:
toolchain = config.get(f'target.{target}', 'toolchain', fallback='NONE')
if toolchain=='NONE':
log("ERROR: No toolchain specified for target")
exit(1)
log("Target", target)
try:
exec(f"from remotesyn.toolchains.{toolchain} import do")
except ImportError:
log(f"ERROR: Unknown toolchain '{toolchain}'")
exit(1)
toolchain = config.get(f'target.{target}', 'toolchain', fallback='NONE')
if toolchain=='NONE':
log("ERROR: No toolchain specified for target")
exit(1)
ret = do(config, target, log, subprocesses)
try:
exec(f"from remotesyn.toolchains.{toolchain} import do")
except ImportError:
log(f"ERROR: Unknown toolchain '{toolchain}'")
exit(1)
if ret!=0:
log("ERROR: toolchain returned with", ret)
exit(ret)
ret = do(config, target, log, subprocesses)
except KeyboardInterrupt:
log("\rStopping rbuild")
for p in subprocesses:
p.kill()
exit(0)
if ret!=0:
log("ERROR: toolchain returned with", ret)
exit(ret)

View File

@ -7,6 +7,7 @@ import base64
import struct
import os
import json
import signal
def cmd(cmd, channel):
channel.exec_command(base64.encodebytes(cmd))
@ -68,9 +69,10 @@ def recv_dir(channel, dr):
print("<<<", dr)
cmd(b'ls'+sstr(dr), channel)
while True:
status = channel.recv(2)
if status != b'\x00\x00':
status = channel.recv(1)
if status != b'\x00':
break
status += channel.recv(1)
if status!=b'OK':
msg = channel.recv(1024)
print("Error:", bytes.decode(msg, 'ascii'))
@ -145,16 +147,31 @@ if __name__=="__main__":
exit(1)
subprocesses = []
stopped = False
def sighandler(num, frame):
global stopped
if num==signal.SIGINT:
print("\rStopping rbuild")
stopped = True
for p in subprocesses:
p.terminate()
exit(0)
signal.signal(signal.SIGINT, sighandler)
signal.signal(signal.SIGALRM, sighandler)
try:
# Send project identification
cmd(b'id' + struct.pack('>q', hash(host_key.get_base64())), channel)
# Send config
cmd(b'cf' + sstr(json.dumps({s:dict(config.items(s)) for s in config.sections()})), channel)
for target in targets:
if stopped:
break
print("Target", target)
# Send project identification
cmd(b'id' + struct.pack('>q', hash(host_key.get_base64())), channel)
# Send config
cmd(b'cf' + sstr(json.dumps({s:dict(config.items(s)) for s in config.sections()})), channel)
print("LOCAL: Target", target)
toolchain = config.get(f'target.{target}', 'toolchain', fallback='NONE')
if toolchain=='NONE':
@ -174,7 +191,11 @@ if __name__=="__main__":
send_file(channel, f)
cmd(b'do'+sstr(target), channel)
status = channel.recv(2)
while True:
status = channel.recv(1)
if status!='b\x00':
break
status += channel.recv(1)
end = -1
while end<0:
data = channel.recv(8)
@ -184,7 +205,7 @@ if __name__=="__main__":
print(str(data, 'utf-8'), end='', flush=True)
sys.stdout.flush()
ret = 0
ret = int.from_bytes(channel.recv(4), 'big')
# Receive output dir
recv_dir(channel, config.get('project', 'out_dir', fallback='out'))
@ -193,14 +214,10 @@ if __name__=="__main__":
print("ERROR: toolchain returned with", ret)
exit(ret)
cmd(b'ex', channel)
except paramiko.ssh_exception.SSHException as e:
print("ERROR: Connection error...", e)
for p in subprocesses:
p.kill()
exit(0)
except KeyboardInterrupt:
print("\rStopping rmbuild")
for p in subprocesses:
p.kill()
exit(0)

View File

@ -100,7 +100,6 @@ class SSHServer(paramiko.ServerInterface):
for t in self.threads:
if type(t) is not NoneType:
t.stop()
t.join()
def check_channel_request(self, kind, chanid):
if kind == 'session':
@ -143,7 +142,7 @@ class SSHServer(paramiko.ServerInterface):
# Exit
elif cmd==b'ex':
print('<', self.identifier)
self.event.set()
self.stop()
# Config
elif cmd==b'cf':
@ -245,9 +244,10 @@ class Connection(threading.Thread):
time.sleep(0.2)
else:
print("Connection", self.addr, "closed")
if server.identifier!='':
pass
shutil.rmtree(server.identifier, True)
print("Deleting directory")
shutil.rmtree(server.identifier, True)
transport.close()
def print_help():

View File

@ -20,6 +20,6 @@ setup(
],
packages=['remotesyn'],
licence='BSD Licence',
install_requires=['paramiko'],
install_requires=['paramiko', 'html2text'],
scripts=['scripts/rbuild', 'scripts/rmbuild', 'scripts/rmserver']
)