Skip to content

Commit 0fea22e

Browse files
committed
Add 'pythondata_cpu_serv/verilog/' from commit 'c0fc72b3535c6525ad93653d327080d9c85e9a8e'
git-subtree-dir: pythondata_cpu_serv/verilog git-subtree-mainline: b10024e git-subtree-split: c0fc72b
2 parents b10024e + c0fc72b commit 0fea22e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+20685
-0
lines changed
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[submodule "zephyr"]
2+
path = zephyr
3+
url = https://github.com/olofk/zephyr
4+
branch = serv

pythondata_cpu_serv/verilog/LICENSE

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
ISC License
2+
3+
Copyright 2019, Olof Kindgren
4+
5+
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
6+
7+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

pythondata_cpu_serv/verilog/README.md

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
<img align="right" src="https://svg.wavedrom.com/{signal:[{wave:'0.P...'},{wave:'023450',data:'S E R V'}]}"/>
2+
3+
# SERV
4+
5+
SERV is an award-winning bit-serial RISC-V core
6+
7+
## Prerequisites
8+
9+
Create a directory to keep all the different parts of the project together. We
10+
will refer to this directory as `$SERV` from now on.
11+
12+
Download the main serv repo
13+
14+
`cd $SERV && git clone https://github.com/olofk/serv`
15+
16+
Install FuseSoC
17+
18+
`pip install fusesoc`
19+
20+
Initialize the FuseSoC standard libraries
21+
22+
`fusesoc init`
23+
24+
Create a workspace directory for FuseSoC
25+
26+
`mkdir $SERV/workspace`
27+
28+
Register the serv repo as a core library
29+
30+
`cd $SERV/workspace && fusesoc library add serv $SERV`
31+
32+
Check that the CPU passes the linter
33+
34+
`cd $SERV/workspace && fusesoc run --target=lint serv`
35+
36+
## Running test software
37+
38+
Build and run the single threaded zephyr hello world example with verilator (should be stopped with Ctrl-C):
39+
40+
cd $SERV/workspace
41+
fusesoc run --target=verilator_tb servant --uart_baudrate=57600 --firmware=$SERV/serv/sw/zephyr_hello.hex
42+
43+
..or... the multithreaded version
44+
45+
fusesoc run --target=verilator_tb servant --uart_baudrate=57600 --firmware=$SERV/serv/sw/zephyr_hello_mt.hex --memsize=16384
46+
47+
...or... the philosophers example
48+
49+
fusesoc run --target=verilator_tb servant --uart_baudrate=57600 --firmware=$SERV/serv/sw/zephyr_phil.hex --memsize=32768
50+
51+
...or... the synchronization example
52+
53+
fusesoc run --target=verilator_tb servant --uart_baudrate=57600 --firmware=$SERV/serv/sw/zephyr_sync.hex --memsize=16384
54+
55+
Other applications can be tested by compiling and converting to bin and then hex e.g. with makehex.py found in `$SERV/serv/riscv-target/serv`
56+
57+
## Run the compliance tests
58+
59+
Build the verilator model (if not already done)
60+
61+
`cd $SERV/workspace && fusesoc run --target=verilator_tb --setup --build servant`
62+
63+
Download the tests repo
64+
65+
`cd $SERV && git clone https://github.com/riscv/riscv-compliance`
66+
67+
Run the compliance tests
68+
69+
`cd $SERV/riscv-compliance && make TARGETDIR=$SERV/serv/riscv-target RISCV_TARGET=serv RISCV_DECICE=rv32i RISCV_ISA=rv32i TARGET_SIM=$SERV/workspace/build/servant_1.0.1/verilator_tb-verilator/Vservant_sim`
70+
71+
## Run on hardware
72+
73+
The servant SoC has been ported to a number of different FPGA boards. To see all currently supported targets run
74+
75+
fusesoc core show servant
76+
77+
By default, these targets have the program memory preloaded with a small Zephyr hello world example that writes its output on a UART pin. Don't forget to install the appropriate toolchain (e.g. icestorm, Vivado, Quartus...) and add to your PATH
78+
79+
Some targets also depend on functionality in the FuseSoC base library (fusesoc-cores). Running `fusesoc library list` should tell you if fusesoc-cores is already available. If not, add it to your workspace with
80+
81+
fusesoc library add fusesoc-cores https://github.com/fusesoc/fusesoc-cores
82+
83+
Now we're ready to build. Note, for all the cases below, it's possible to run with `--memfile=$SERV/sw/blinky.hex`
84+
(or any other suitable program) as the last argument to preload the LED blink example
85+
instead of hello world.
86+
87+
### TinyFPGA BX
88+
89+
Pin A6 is used for UART output with 115200 baud rate.
90+
91+
cd $SERV/workspace
92+
fusesoc run --target=tinyfpga_bx servant
93+
tinyprog --program build/servant_1.0.1/tinyfpga_bx-icestorm/servant_1.0.1.bin
94+
95+
### Icebreaker
96+
97+
Pin 9 is used for UART output with 57600 baud rate.
98+
99+
cd $SERV/workspace
100+
fusesoc run --target=icebreaker servant
101+
102+
### Arty A7 35T
103+
104+
Pin D10 (uart_rxd_out) is used for UART output with 57600 baud rate (to use
105+
blinky.hex change D10 to H5 (led[4]) in data/arty_a7_35t.xdc).
106+
107+
cd $SERV/workspace
108+
fusesoc run --target=arty_a7_35t servant
109+
110+
### Alhambra II
111+
112+
Pin 61 is used for UART output with 38400 baud rate (note that it works with non-standard 43200 value too). This pin is connected to a FT2232H chip in board, that manages the communications between the FPGA and the computer.
113+
114+
cd $SERV/workspace
115+
fusesoc run --target=alhambra servant
116+
iceprog -d i:0x0403:0x6010:0 build/servant_1.0.1/alhambra-icestorm/servant_1.0.1.bin
117+
118+
## Other targets
119+
120+
The above targets are run on the servant SoC, but there are some targets defined for the CPU itself. Verilator can be run in lint mode to check for design problems by running
121+
122+
fusesoc run --target=lint serv
123+
124+
It's also possible to just synthesise for different targets to check resource usage and such. To do that for the iCE40 devices, run
125+
126+
fusesoc run --tool=icestorm serv --pnr=none
127+
128+
...or to synthesize with vivado for Xilinx targets, run
129+
130+
fusesoc run --tool=vivado serv --pnr=none
131+
132+
This will synthesize for the default Vivado part. To synthesise for a specific device, run e.g.
133+
134+
fusesoc run --tool=vivado serv --pnr=none --part=xc7a100tcsg324-1
135+
136+
137+
## Good to know
138+
139+
Don't feed serv any illegal instructions after midnight. Many logic expressions are hand-optimized using the old-fashioned method with Karnaugh maps on paper, and shamelessly take advantage of the fact that some opcodes aren't supposed to appear. As serv was written with 4-input LUT FPGAs as target, and opcodes are 5 bits, this can save quite a bit of resources in the decoder.
140+
141+
The bus interface is kind of Wishbone, but with most signals removed. There's an important difference though. Don't send acks on the instruction or data buses unless serv explicitly asks for something by raising its cyc signal. Otherwise serv becomes very confused.
142+
143+
Don't go changing the clock frequency on a whim when running Zephyr. Or well, it's ok I guess, but since the UART is bitbanged, this will change the baud rate as well. As of writing, the UART is running at 115200 baud rate when the CPU is 32 MHz. There are two NOPs in the driver to slow it down a bit, so if those are removed I think it could achieve baud rate 115200 on a 24MHz clock.. in case someone wants to try
144+
145+
## TODO
146+
147+
- Applications have to be preloaded to RAM at compile-time
148+
- Store bootloader and register file together in a RAM
149+
- Make it faster and smaller
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
`default_nettype none
2+
module servant_sim
3+
(input wire wb_clk,
4+
input wire wb_rst,
5+
output wire q);
6+
7+
parameter memfile = "";
8+
parameter memsize = 8192;
9+
parameter with_csr = 1;
10+
11+
reg [1023:0] firmware_file;
12+
initial
13+
if ($value$plusargs("firmware=%s", firmware_file)) begin
14+
$display("Loading RAM from %0s", firmware_file);
15+
$readmemh(firmware_file, dut.ram.mem);
16+
end
17+
18+
servant
19+
#(.memfile (memfile),
20+
.memsize (memsize),
21+
.sim (1),
22+
.with_csr (with_csr))
23+
dut(wb_clk, wb_rst, q);
24+
25+
endmodule
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#include <stdint.h>
2+
#include <signal.h>
3+
4+
#include "verilated_vcd_c.h"
5+
#include "Vservant_sim.h"
6+
7+
using namespace std;
8+
9+
static bool done;
10+
11+
vluint64_t main_time = 0; // Current simulation time
12+
// This is a 64-bit integer to reduce wrap over issues and
13+
// allow modulus. You can also use a double, if you wish.
14+
15+
double sc_time_stamp () { // Called by $time in Verilog
16+
return main_time; // converts to double, to match
17+
// what SystemC does
18+
}
19+
20+
void INThandler(int signal)
21+
{
22+
printf("\nCaught ctrl-c\n");
23+
done = true;
24+
}
25+
26+
typedef struct {
27+
bool last_value;
28+
} gpio_context_t;
29+
30+
void do_gpio(gpio_context_t *context, bool gpio) {
31+
if (context->last_value != gpio) {
32+
context->last_value = gpio;
33+
printf("%lu output q is %s\n", main_time, gpio ? "ON" : "OFF");
34+
}
35+
}
36+
37+
typedef struct {
38+
uint8_t state;
39+
char ch;
40+
uint32_t baud_t;
41+
vluint64_t last_update;
42+
} uart_context_t;
43+
44+
void uart_init(uart_context_t *context, uint32_t baud_rate) {
45+
context->baud_t = 1000*1000*1000/baud_rate;
46+
context->state = 0;
47+
}
48+
49+
void do_uart(uart_context_t *context, bool rx) {
50+
if (context->state == 0) {
51+
if (rx)
52+
context->state++;
53+
}
54+
else if (context->state == 1) {
55+
if (!rx) {
56+
context->last_update = main_time + context->baud_t/2;
57+
context->state++;
58+
}
59+
}
60+
else if(context->state == 2) {
61+
if (main_time > context->last_update) {
62+
context->last_update += context->baud_t;
63+
context->ch = 0;
64+
context->state++;
65+
}
66+
}
67+
else if (context->state < 11) {
68+
if (main_time > context->last_update) {
69+
context->last_update += context->baud_t;
70+
context->ch |= rx << (context->state-3);
71+
context->state++;
72+
}
73+
}
74+
else {
75+
if (main_time > context->last_update) {
76+
context->last_update += context->baud_t;
77+
putchar(context->ch);
78+
context->state=1;
79+
}
80+
}
81+
}
82+
83+
int main(int argc, char **argv, char **env)
84+
{
85+
vluint64_t sample_time = 0;
86+
uint32_t insn = 0;
87+
uint32_t ex_pc = 0;
88+
int baud_rate = 0;
89+
90+
gpio_context_t gpio_context;
91+
uart_context_t uart_context;
92+
Verilated::commandArgs(argc, argv);
93+
94+
Vservant_sim* top = new Vservant_sim;
95+
96+
const char *arg = Verilated::commandArgsPlusMatch("uart_baudrate=");
97+
if (arg[0]) {
98+
baud_rate = atoi(arg+15);
99+
if (baud_rate) {
100+
uart_init(&uart_context, baud_rate);
101+
}
102+
}
103+
104+
VerilatedVcdC * tfp = 0;
105+
const char *vcd = Verilated::commandArgsPlusMatch("vcd=");
106+
if (vcd[0]) {
107+
Verilated::traceEverOn(true);
108+
tfp = new VerilatedVcdC;
109+
top->trace (tfp, 99);
110+
tfp->open ("trace.vcd");
111+
}
112+
113+
signal(SIGINT, INThandler);
114+
115+
vluint64_t timeout = 0;
116+
const char *arg_timeout = Verilated::commandArgsPlusMatch("timeout=");
117+
if (arg_timeout[0])
118+
timeout = atoi(arg_timeout+9);
119+
120+
vluint64_t vcd_start = 0;
121+
const char *arg_vcd_start = Verilated::commandArgsPlusMatch("vcd_start=");
122+
if (arg_vcd_start[0])
123+
vcd_start = atoi(arg_vcd_start+11);
124+
125+
bool dump = false;
126+
top->wb_clk = 1;
127+
bool q = top->q;
128+
while (!(done || Verilated::gotFinish())) {
129+
if (tfp && !dump && (main_time > vcd_start)) {
130+
dump = true;
131+
}
132+
top->wb_rst = main_time < 100;
133+
top->eval();
134+
if (dump)
135+
tfp->dump(main_time);
136+
if (baud_rate)
137+
do_uart(&uart_context, top->q);
138+
else
139+
do_gpio(&gpio_context, top->q);
140+
141+
if (timeout && (main_time >= timeout)) {
142+
printf("Timeout: Exiting at time %lu\n", main_time);
143+
done = true;
144+
}
145+
146+
top->wb_clk = !top->wb_clk;
147+
main_time+=31.25;
148+
149+
}
150+
if (tfp)
151+
tfp->close();
152+
exit(0);
153+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
`default_nettype none
2+
module servant_tb;
3+
4+
parameter memfile = "";
5+
parameter memsize = 8192;
6+
parameter with_csr = 1;
7+
8+
reg wb_clk = 1'b0;
9+
reg wb_rst = 1'b1;
10+
11+
always #31 wb_clk <= !wb_clk;
12+
initial #62 wb_rst <= 1'b0;
13+
14+
vlog_tb_utils vtu();
15+
16+
uart_decoder #(57600) uart_decoder (q);
17+
18+
servant_sim
19+
#(.memfile (memfile),
20+
.memsize (memsize),
21+
.with_csr (with_csr))
22+
dut(wb_clk, wb_rst, q);
23+
24+
endmodule
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module uart_decoder
2+
#(parameter BAUD_RATE = 115200)
3+
(input rx);
4+
5+
localparam T = 1000000000/BAUD_RATE;
6+
7+
integer i;
8+
reg [7:0] ch;
9+
10+
initial forever begin
11+
@(negedge rx);
12+
#(T/2) ch = 0;
13+
for (i=0;i<8;i=i+1)
14+
#T ch[i] = rx;
15+
$write("%c",ch);
16+
$fflush;
17+
end
18+
endmodule
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# 12 MHz clock
2+
set_io i_clk 49
3+
4+
# RS232
5+
set_io q 61

0 commit comments

Comments
 (0)