more cleanup and bug finding

This commit is contained in:
Peter McGoron 2024-02-08 12:57:22 +00:00
parent a10ad772bc
commit 4e3df09bb8
12 changed files with 304 additions and 741 deletions

7
.gitignore vendored
View File

@ -35,17 +35,10 @@ gateware/csr_bitwidth.json
boot/* boot/*
!boot/boot.json !boot/boot.json
*.tar.gz *.tar.gz
build/buildroot.tar.gz
build/buildroot/ build/buildroot/
build/f4pga/ build/f4pga/
build/litex/ build/litex/
build/opensbi/ build/opensbi/
build/upsilon/ build/upsilon/
build/upsilon.tar.gz
build/f4pga.tar.gz
build/opensbi.tar.gz
build/upsilon-opensbi.tar.gz
build/upsilon-hardware.tar.gz
build/upsilon-buildroot.tar.gz
swic/*.bin swic/*.bin
swic/*.elf swic/*.elf

View File

@ -30,6 +30,7 @@ COPY --chown=user:user f4pga.tar.gz /home/user
RUN tar -xvf f4pga.tar.gz \ RUN tar -xvf f4pga.tar.gz \
&& rm f4pga.tar.gz \ && rm f4pga.tar.gz \
&& cd f4pga/f4pga \ && cd f4pga/f4pga \
# && sed -i 's/-abc9//g' ./wrappers/tcl/xc7.f4pga.tcl \
&& bash -c 'source ~/conda/xc7/conda/etc/profile.d/conda.sh; conda activate xc7; pip install . ninja meson' && bash -c 'source ~/conda/xc7/conda/etc/profile.d/conda.sh; conda activate xc7; pip install . ninja meson'
#LITEX #LITEX

View File

@ -35,9 +35,9 @@ hardware-copy: upsilon-hardware.tar.gz
# XXX: this always fails if there are very high UIDs, but the # XXX: this always fails if there are very high UIDs, but the
# file is copied successfully. # file is copied successfully.
-docker cp upsilon-hardware.tar.gz upsilon-hardware:/home/user/upsilon-hardware.tar.gz -docker cp upsilon-hardware.tar.gz upsilon-hardware:/home/user/upsilon-hardware.tar.gz
docker exec -ti upsilon-hardware tar -xvf upsilon-hardware.tar.gz
hardware-execute: hardware-execute:
docker exec -ti upsilon-hardware /bin/bash -lc ' \ docker exec -ti upsilon-hardware /bin/bash -lc ' \
tar -xvf upsilon-hardware.tar.gz && \
cd upsilon/gateware && \ cd upsilon/gateware && \
source ~/conda/xc7/conda/etc/profile.d/conda.sh && \ source ~/conda/xc7/conda/etc/profile.d/conda.sh && \
conda activate xc7 && \ conda activate xc7 && \
@ -49,7 +49,7 @@ hardware-get:
docker cp upsilon-hardware:/home/user/upsilon/gateware/arty.dtb ../boot/ docker cp upsilon-hardware:/home/user/upsilon/gateware/arty.dtb ../boot/
# docker cp upsilon-hardware:/home/user/upsilon/gateware/mmio.py ../boot/ # docker cp upsilon-hardware:/home/user/upsilon/gateware/mmio.py ../boot/
docker cp upsilon-hardware:/home/user/upsilon/gateware/csr.json ../boot/ docker cp upsilon-hardware:/home/user/upsilon/gateware/csr.json ../boot/
docker cp upsilon-hardware:/home/user/upsilon/gateware/picorv32.json ../boot/ # docker cp upsilon-hardware:/home/user/upsilon/gateware/picorv32.json ../boot/
hardware-clean: hardware-clean:
-docker container stop upsilon-hardware -docker container stop upsilon-hardware
-docker container rm upsilon-hardware -docker container rm upsilon-hardware

View File

@ -8,19 +8,13 @@
DEVICETREE_GEN_DIR=. DEVICETREE_GEN_DIR=.
all: rtl_codegen build/digilent_arty/digilent_arty.bit arty.dtb# mmio.py all: build/digilent_arty/digilent_arty.bit arty.dtb# mmio.py
rtl_codegen:
cd rtl && make
csr.json build/digilent_arty/digilent_arty.bit: soc.py csr.json build/digilent_arty/digilent_arty.bit: soc.py
python3 soc.py python3 soc.py
clean: clean:
rm -rf build csr.json arty.dts arty.dtb mmio.py rm -rf build csr.json arty.dts arty.dtb mmio.py
cd rtl && make clean
test:
cd rtl && make test
arty.dts: csr.json arty.dts: csr.json
litex_json2dts_linux csr.json > arty.dts litex_json2dts_linux csr.json > arty.dts

View File

@ -3,22 +3,12 @@
# For license terms, refer to the files in `doc/copying` in the Upsilon # For license terms, refer to the files in `doc/copying` in the Upsilon
# source distribution. # source distribution.
all: make_base make_spi make_control_loop make_bram #all: make_bram
test: dummy:
cd control_loop && make test @echo empty
make_base:
cd base && make codegen #make_bram:
make_spi: # cd bram && make codegen
cd spi && make codegen #clean:
make_control_loop: # cd bram && make clean
cd control_loop && make codegen
make_waveform:
cd waveform && make codegen
make_bram:
cd bram && make codegen
clean:
cd base && make clean
cd spi && make clean
cd control_loop && make clean
cd waveform && make clean

View File

@ -1,9 +0,0 @@
.PHONY: lint
include ../common.makefile
codegen: base.v
base.v: base.v.m4
lint: base.v
verilator --lint-only base.v -I../spi -I../control_loop -I../waveform
clean:
rm -f base.v

View File

@ -1,396 +0,0 @@
m4_changequote(`⟨', `⟩')
m4_changecom(⟨/*⟩, ⟨*/⟩)
m4_define(generate_macro, ⟨m4_define(M4_$1, $2)⟩)
/*
Copyright 2023 (C) Peter McGoron
This file is a part of Upsilon, a free and open source software project.
For license terms, refer to the files in `doc/copying` in the Upsilon
source distribution.
_____________________________________________________________________
This is the module that collects all Verilog and exports a single interface
that is connected to the CPU by LiteX.
In this future, this module should be written into soc.py
Since yosys only allows for standard Verilog (no system verilog),
arrays (which would make everything much cleaner) cannot be used.
A preprocessor is used instead, and M4 is used because it is much
cleaner than the Verilog preprocessor (which is bad).
TODO: individual RST pins
*/
/*********************************************************/
/********************** M4 macros ************************/
/*********************************************************/
/* This macro is used in the module declaration.
* The first argument is the number of wires the select switch must
* support (2 for most DACs, 3 for the control loop DAC).
* The second argument is the DAC number.
*/
m4_define(m4_dac_wires, ⟨
input [$1-1:0] dac_sel_$2,
output dac_finished_$2,
input dac_arm_$2,
output [DAC_WID-1:0] dac_recv_buf_$2,
input [DAC_WID-1:0] dac_send_buf_$2
/*
input wf_arm_$2,
input wf_halt_on_finish_$2,
output wf_finished_$2,
input [WF_TIMER_WID-1:0] wf_time_to_wait_$2,
input wf_refresh_start_$2,
input [WF_RAM_WID-1:0] wf_start_addr_$2,
output wf_refresh_finished_$2,
output wf_running_$2,
output [WF_RAM_WID-1:0] wf_ram_dma_addr_$2,
input [WF_RAM_WORD_WID-1:0] wf_ram_word_$2,
output wf_ram_read_$2,
input wf_ram_valid_$2
*/
⟩)
/* Same thing but for ADCs */
m4_define(m4_adc_wires, ⟨
input [$3-1:0] adc_sel_$2,
output adc_finished_$2,
input adc_arm_$2,
output [$1-1:0] adc_recv_buf_$2
⟩)
/* This is used in the body of the module. It declares the interconnect
* for each DAC. The first argument is the amount of switch ports the
* DAC requires (2 for most DACs, 3 for the control loop DAC). The
* second argument is the DAC number.
*/
m4_define(m4_dac_switch, ⟨
wire [$1-1:0] mosi_port_$2;
wire [$1-1:0] miso_port_$2;
wire [$1-1:0] sck_port_$2;
wire [$1-1:0] ss_L_port_$2;
spi_switch #(
.PORTS($1)
) switch_$2 (
.select(dac_sel_$2),
.mosi(dac_mosi[$2]),
.miso(dac_miso[$2]),
.sck(dac_sck[$2]),
.ss_L(dac_ss_L[$2]),
.mosi_ports(mosi_port_$2),
.miso_ports(miso_port_$2),
.sck_ports(sck_port_$2),
.ss_L_ports(ss_L_port_$2)
);
spi_master_ss #(
.WID(DAC_WID),
.WID_LEN(DAC_WID_SIZ),
.CYCLE_HALF_WAIT(DAC_CYCLE_HALF_WAIT),
.TIMER_LEN(DAC_CYCLE_HALF_WAIT_SIZ),
.POLARITY(DAC_POLARITY),
.PHASE(DAC_PHASE),
.SS_WAIT(DAC_SS_WAIT),
.SS_WAIT_TIMER_LEN(DAC_SS_WAIT_SIZ)
) dac_master_$2 (
.clk(clk),
.rst_L(rst_L),
.mosi(mosi_port_$2[0]),
.miso(miso_port_$2[0]),
.sck_wire(sck_port_$2[0]),
.ss_L(ss_L_port_$2[0]),
.finished(dac_finished_$2),
.arm(dac_arm_$2),
.from_slave(dac_recv_buf_$2),
.to_slave(dac_send_buf_$2)
)
/*
waveform #(
.DAC_WID(DAC_WID),
.DAC_WID_SIZ(DAC_WID_SIZ),
.DAC_POLARITY(DAC_POLARITY),
.DAC_PHASE(DAC_PHASE),
.DAC_CYCLE_HALF_WAIT(DAC_CYCLE_HALF_WAIT),
.DAC_CYCLE_HALF_WAIT_SIZ(DAC_CYCLE_HALF_WAIT_SIZ),
.DAC_SS_WAIT(DAC_SS_WAIT),
.DAC_SS_WAIT_SIZ(DAC_SS_WAIT_SIZ),
.TIMER_WID(WF_TIMER_WID),
.WORD_WID(WF_WORD_WID),
.WORD_AMNT_WID(WF_WORD_AMNT_WID),
.WORD_AMNT(WF_WORD_AMNT),
.RAM_WID(WF_RAM_WID),
.RAM_WORD_WID(WF_RAM_WORD_WID),
.RAM_WORD_INCR(WF_RAM_WORD_INCR)
) waveform_$2 (
.clk(clk),
.arm(wf_arm_$2),
.halt_on_finish(wf_halt_on_finish_$2),
.running(wf_running_$2),
.finished(wf_finished_$2),
.time_to_wait(wf_time_to_wait_$2),
.refresh_start(wf_refresh_start_$2),
.start_addr(wf_start_addr_$2),
.refresh_finished(wf_refresh_finished_$2),
.ram_dma_addr(wf_ram_dma_addr_$2),
.ram_word(wf_ram_word_$2),
.ram_read(wf_ram_read_$2),
.ram_valid(wf_ram_valid_$2),
.mosi(mosi_port_$2[1]),
.sck(sck_port_$2[1]),
.ss_L(ss_L_port_$2[1])
)
*/
⟩)
/* Same thing but for ADCs */
m4_define(m4_adc_switch, ⟨
wire adc_mosi_unused_output_$2;
wire [$3-1:0] adc_mosi_port_$2; /* Unused! */
wire [$3-1:0] adc_sdo_port_$2;
wire [$3-1:0] adc_sck_port_$2;
wire [$3-1:0] adc_conv_L_port_$2;
spi_switch #(
.PORTS($3)
) adc_switch_$2 (
.select(adc_sel_$2),
.mosi(adc_mosi_unused_output_$2),
.miso(adc_sdo[$2]),
.sck(adc_sck[$2]),
.ss_L(adc_conv_L[$2]),
.mosi_ports(adc_mosi_port_$2),
.miso_ports(adc_sdo_port_$2),
.sck_ports(adc_sck_port_$2),
.ss_L_ports(adc_conv_L_port_$2)
);
spi_master_ss_no_write #(
.WID($1),
.WID_LEN(ADC_WID_SIZ),
.CYCLE_HALF_WAIT(ADC_CYCLE_HALF_WAIT),
.TIMER_LEN(ADC_CYCLE_HALF_WAIT_SIZ),
.SS_WAIT(ADC_CONV_WAIT),
.SS_WAIT_TIMER_LEN(ADC_CONV_WAIT_SIZ),
.POLARITY(ADC_POLARITY),
.PHASE(ADC_PHASE)
) adc_master_$2 (
.clk(clk),
.rst_L(rst_L),
.miso(adc_sdo_port_$2[0]),
.sck_wire(adc_sck_port_$2[0]),
.ss_L(adc_conv_L_port_$2[0]),
.finished(adc_finished_$2),
.arm(adc_arm_$2),
.from_slave(adc_recv_buf_$2)
);
/* 2nd option for each ADC is the non-converting option.
* This is used to flush output from reset ADCs.
* TODO: Lower power consumption by having SCK low while converter is
* not running? May require change to spi code.
*/
assign adc_sdo_port[1] = adc_sdo_port[0];
assign adc_sck_port[1] = adc_sck_port[0];
assign adc_conv_L_port[1] = 1;
⟩)
/*********************************************************/
/*********************** Verilog *************************/
/*********************************************************/
module base #(
parameter DAC_PORTS = 1,
m4_define(DAC_PORTS_CONTROL_LOOP, (DAC_PORTS + 1))
parameter DAC_NUM = 8, // Number of DACs
parameter DAC_WID = 24, // Bit width of DAC command
parameter DAC_DATA_WID = 20, // Bit with of DAC register
parameter DAC_WID_SIZ = 5, // number of bits required to store DAC_DATA_WID
parameter DAC_POLARITY = 0, // DAC SCK polarity
parameter DAC_PHASE = 1, // DAC SCK phase
parameter DAC_CYCLE_HALF_WAIT = 10,
parameter DAC_CYCLE_HALF_WAIT_SIZ = 4,
parameter DAC_SS_WAIT = 5,
parameter DAC_SS_WAIT_SIZ = 3,
parameter WF_TIMER_WID = 32,
parameter WF_WORD_WID = 20,
parameter WF_WORD_AMNT_WID = 11,
parameter [WF_WORD_AMNT_WID-1:0] WF_WORD_AMNT = 2047,
parameter WF_RAM_WID = 32,
parameter WF_RAM_WORD_WID = 16,
parameter WF_RAM_WORD_INCR = 2,
parameter ADC_PORTS = 2,
m4_define(ADC_PORTS_CONTROL_LOOP, (ADC_PORTS + 1))
parameter ADC_NUM = 8,
/* Three types of ADC. For now assume that their electronics
* are similar enough, just need different numbers for the width.
*/
parameter ADC_TYPE1_WID = 18,
parameter ADC_TYPE2_WID = 16,
parameter ADC_TYPE3_WID = 24,
parameter ADC_WID_SIZ = 5,
parameter ADC_CYCLE_HALF_WAIT = 5,
parameter ADC_CYCLE_HALF_WAIT_SIZ = 3,
parameter ADC_POLARITY = 1,
parameter ADC_PHASE = 0,
/* The ADC takes maximum 527 ns to capture a value.
* The clock ticks at 10 ns. Change for different clocks!
*/
parameter ADC_CONV_WAIT = 60,
parameter ADC_CONV_WAIT_SIZ = 6,
parameter CL_CONSTS_WHOLE = 21,
parameter CL_CONSTS_FRAC = 43,
parameter CL_CONSTS_SIZ = 7,
parameter CL_DELAY_WID = 16,
m4_define(CL_CONSTS_WID, (CL_CONSTS_WHOLE + CL_CONSTS_FRAC))
m4_define(CL_DATA_WID, CL_CONSTS_WID)
parameter CL_READ_DAC_DELAY = 5,
parameter CL_CYCLE_COUNT_WID = 18
) (
input clk,
input rst_L,
output [11-1:0] set_low,
output [DAC_NUM-1:0] dac_mosi,
input [DAC_NUM-1:0] dac_miso,
output [DAC_NUM-1:0] dac_sck,
output [DAC_NUM-1:0] dac_ss_L,
output [ADC_NUM-1:0] adc_conv,
input [ADC_NUM-1:0] adc_sdo,
output [ADC_NUM-1:0] adc_sck,
m4_dac_wires(DAC_PORTS_CONTROL_LOOP, 0),
m4_dac_wires(DAC_PORTS, 1),
m4_dac_wires(DAC_PORTS, 2),
m4_dac_wires(DAC_PORTS, 3),
m4_dac_wires(DAC_PORTS, 4),
m4_dac_wires(DAC_PORTS, 5),
m4_dac_wires(DAC_PORTS, 6),
m4_dac_wires(DAC_PORTS, 7),
m4_adc_wires(ADC_TYPE1_WID, 0, ADC_PORTS_CONTROL_LOOP),
m4_adc_wires(ADC_TYPE1_WID, 1, ADC_PORTS),
m4_adc_wires(ADC_TYPE1_WID, 2, ADC_PORTS),
m4_adc_wires(ADC_TYPE2_WID, 3, ADC_PORTS),
m4_adc_wires(ADC_TYPE2_WID, 4, ADC_PORTS),
m4_adc_wires(ADC_TYPE2_WID, 5, ADC_PORTS),
m4_adc_wires(ADC_TYPE3_WID, 6, ADC_PORTS),
m4_adc_wires(ADC_TYPE3_WID, 7, ADC_PORTS),
input cl_assert_change,
output cl_change_made,
output cl_in_loop,
input cl_run_loop_in,
input [ADC_TYPE1_WID-1:0] cl_setpt_in,
input [CL_DATA_WID-1:0] cl_P_in,
input [CL_DATA_WID-1:0] cl_I_in,
input [CL_DELAY_WID-1:0] cl_delay_in,
output [CL_CYCLE_COUNT_WID-1:0] cl_cycle_count,
output [DAC_DATA_WID-1:0] cl_z_pos,
output [ADC_TYPE1_WID-1:0] cl_z_measured
);
assign set_low = 0;
wire [ADC_NUM-1:0] adc_conv_L;
assign adc_conv = ~adc_conv_L;
m4_dac_switch(DAC_PORTS_CONTROL_LOOP, 0);
m4_dac_switch(DAC_PORTS, 1);
m4_dac_switch(DAC_PORTS, 2);
m4_dac_switch(DAC_PORTS, 3);
m4_dac_switch(DAC_PORTS, 4);
m4_dac_switch(DAC_PORTS, 5);
m4_dac_switch(DAC_PORTS, 6);
m4_dac_switch(DAC_PORTS, 7);
`define MAKE_TEST_CLOCK
`ifdef MAKE_TEST_CLOCK
reg [8-1:0] counter = 0;
always @ (posedge clk) begin
if (!rst_L) begin
counter <= 0;
test_clock <= 0;
end else begin
if (counter == ADC_CYCLE_HALF_WAIT) begin
counter <= 0;
test_clock <= !test_clock;
end else begin
counter <= counter + 1;
end
end
end
`endif
m4_adc_switch(ADC_TYPE1_WID, 0, ADC_PORTS_CONTROL_LOOP);
m4_adc_switch(ADC_TYPE1_WID, 1, ADC_PORTS);
m4_adc_switch(ADC_TYPE1_WID, 2, ADC_PORTS);
m4_adc_switch(ADC_TYPE1_WID, 3, ADC_PORTS);
m4_adc_switch(ADC_TYPE1_WID, 4, ADC_PORTS);
m4_adc_switch(ADC_TYPE1_WID, 5, ADC_PORTS);
m4_adc_switch(ADC_TYPE1_WID, 6, ADC_PORTS);
m4_adc_switch(ADC_TYPE1_WID, 7, ADC_PORTS);
control_loop #(
.ADC_WID(ADC_TYPE1_WID),
.ADC_WID_SIZ(ADC_WID_SIZ),
.ADC_CYCLE_HALF_WAIT(ADC_CYCLE_HALF_WAIT),
.ADC_CYCLE_HALF_WAIT_SIZ(ADC_CYCLE_HALF_WAIT_SIZ),
.ADC_POLARITY(ADC_POLARITY),
.ADC_PHASE(ADC_PHASE),
.ADC_CONV_WAIT(ADC_CONV_WAIT),
.ADC_CONV_WAIT_SIZ(ADC_CONV_WAIT_SIZ),
.CONSTS_WHOLE(CL_CONSTS_WHOLE),
.CONSTS_FRAC(CL_CONSTS_FRAC),
.CONSTS_SIZ(CL_CONSTS_SIZ),
.DELAY_WID(CL_DELAY_WID),
.READ_DAC_DELAY(CL_READ_DAC_DELAY),
.CYCLE_COUNT_WID(CL_CYCLE_COUNT_WID),
.DAC_WID(DAC_WID),
.DAC_WID_SIZ(DAC_WID_SIZ),
.DAC_DATA_WID(DAC_DATA_WID),
.DAC_POLARITY(DAC_POLARITY),
.DAC_PHASE(DAC_PHASE),
.DAC_CYCLE_HALF_WAIT(DAC_CYCLE_HALF_WAIT),
.DAC_CYCLE_HALF_WAIT_SIZ(DAC_CYCLE_HALF_WAIT_SIZ),
.DAC_SS_WAIT(DAC_SS_WAIT),
.DAC_SS_WAIT_SIZ(DAC_SS_WAIT_SIZ)
) cl (
.clk(clk),
.rst_L(rst_L),
.in_loop(cl_in_loop),
.dac_mosi(mosi_port_0[1]),
.dac_miso(miso_port_0[1]),
.dac_ss_L(ss_L_port_0[1]),
.dac_sck(sck_port_0[1]),
.adc_miso(adc_sdo_port_0[2]),
.adc_conv_L(adc_conv_L_port_0[2]),
.adc_sck(adc_sck_port_0[2]),
.assert_change(cl_assert_change),
.change_made(cl_change_made),
.run_loop_in(cl_run_loop_in),
.setpt_in(cl_setpt_in),
.P_in(cl_P_in),
.I_in(cl_I_in),
.delay_in(cl_delay_in),
.cycle_count(cl_cycle_count),
.z_pos(cl_z_pos),
.z_measured(cl_z_measured)
);
endmodule

View File

@ -1,15 +0,0 @@
# Copyright 2024 (C) Peter McGoron
# This file is a part of Upsilon, a free and open source software project.
# For license terms, refer to the files in `doc/copying` in the Upsilon
# source distribution.
.PHONY: codegen
all: codegen
####### Codegen ########
include ../common.makefile
CODEGEN_FILES=bram.v
codegen: ${CODEGEN_FILES}
clean:
rm -rf obj_dir *.fst ${CODEGEN_FILES}

View File

@ -1,6 +1,3 @@
m4_changequote(`', `')
m4_changecom(/*, */)
/* Copyright 2024 (C) Peter McGoron /* Copyright 2024 (C) Peter McGoron
* This file is a part of Upsilon, a free and open source software project. * This file is a part of Upsilon, a free and open source software project.
* For license terms, refer to the files in `doc/copying` in the Upsilon * For license terms, refer to the files in `doc/copying` in the Upsilon
@ -25,9 +22,12 @@ module bram #(
input [BUS_WID-1:0] wb_addr, input [BUS_WID-1:0] wb_addr,
input [BUS_WID-1:0] wb_dat_w, input [BUS_WID-1:0] wb_dat_w,
output reg wb_ack, output reg wb_ack,
output reg [BUS_WID-1:0] wb_dat_r, output reg [BUS_WID-1:0] wb_dat_r
); );
initial wb_ack <= 0;
initial wb_dat_r <= 0;
/* When the size of the memory is a power of 2, the mask is the /* When the size of the memory is a power of 2, the mask is the
* last addressable index in the array. * last addressable index in the array.
* *
@ -38,33 +38,27 @@ module bram #(
* the 32 bit word that contains the address. This applies to halfwords * the 32 bit word that contains the address. This applies to halfwords
* and words as long as the accesses are aligned. * and words as long as the accesses are aligned.
*/ */
(* ram_style = "block" *)
reg [WORD_WID-1:0] buffer [(ADDR_MASK >> 2):0]; reg [WORD_WID-1:0] buffer [(ADDR_MASK >> 2):0];
/* Current index into the buffer. */ /* Current index into the buffer. */
wire [13-1:0] ind = (wb_addr & ADDR_MASK) >> 2; wire [13-1:0] ind = (wb_addr & ADDR_MASK) >> 2;
m4_define(bufwrite, begin always @ (posedge clk) if (wb_cyc && wb_stb && !wb_ack) begin
buffer[ind] <= (buffer[ind] & $1) | wb_dat_w[$2];
end)
always @ (posedge clk) if (wb_cyc && wb_stb && !wb_ack)
if (!wb_we) begin
wb_dat_r <= buffer[ind];
wb_ack <= 1; wb_ack <= 1;
if (wb_we) begin
if (wb_sel[0])
buffer[ind][7:0] <= wb_dat_w[7:0];
if (wb_sel[1])
buffer[ind][15:8] <= wb_dat_w[15:8];
if (wb_sel[2])
buffer[ind][23:16] <= wb_dat_w[23:16];
if (wb_sel[3])
buffer[ind][31:24] <= wb_dat_w[31:24];
end else begin end else begin
wb_ack <= 1; wb_dat_r <= buffer[ind];
case (wb_sel)
4'b1111: buffer[ind] <= wb_dat_w;
4'b0011: bufwrite(32'hFFFF0000, 15:0)
4'b1100: bufwrite(32'h0000FFFF, 31:16)
4'b0001: bufwrite(32'hFFFFFF00, 7:0)
4'b0010: bufwrite(32'hFFFF00FF, 15:8)
4'b0100: bufwrite(32'hFF00FFFF, 23:16)
4'b1000: bufwrite(32'h00FFFFFF, 31:24)
default: ;
endcase
end end
else if (!wb_stb) begin end else if (!wb_stb) begin
wb_ack <= 0; wb_ack <= 0;
end end

View File

@ -2167,6 +2167,7 @@ module picorv32 #(
`endif `endif
endmodule endmodule
`ifdef 0
// This is a simple example implementation of PICORV32_REGS. // This is a simple example implementation of PICORV32_REGS.
// Use the PICORV32_REGS mechanism if you want to use custom // Use the PICORV32_REGS mechanism if you want to use custom
// memory resources to implement the processor register file. // memory resources to implement the processor register file.
@ -2315,7 +2316,9 @@ module picorv32_pcpi_mul #(
end end
end end
endmodule endmodule
`endif
`ifdef 0
module picorv32_pcpi_fast_mul #( module picorv32_pcpi_fast_mul #(
parameter EXTRA_MUL_FFS = 0, parameter EXTRA_MUL_FFS = 0,
parameter EXTRA_INSN_FFS = 0, parameter EXTRA_INSN_FFS = 0,
@ -2418,6 +2421,7 @@ endmodule
* picorv32_pcpi_div * picorv32_pcpi_div
***************************************************************/ ***************************************************************/
`ifdef 0
module picorv32_pcpi_div ( module picorv32_pcpi_div (
input clk, resetn, input clk, resetn,
@ -2510,11 +2514,13 @@ module picorv32_pcpi_div (
end end
endmodule endmodule
`endif
/*************************************************************** /***************************************************************
* picorv32_axi * picorv32_axi
***************************************************************/ ***************************************************************/
`ifdef 0
module picorv32_axi #( module picorv32_axi #(
parameter [ 0:0] ENABLE_COUNTERS = 1, parameter [ 0:0] ENABLE_COUNTERS = 1,
parameter [ 0:0] ENABLE_COUNTERS64 = 1, parameter [ 0:0] ENABLE_COUNTERS64 = 1,
@ -2723,12 +2729,13 @@ module picorv32_axi #(
.trace_data (trace_data) .trace_data (trace_data)
); );
endmodule endmodule
`endif
/*************************************************************** /***************************************************************
* picorv32_axi_adapter * picorv32_axi_adapter
***************************************************************/ ***************************************************************/
`ifdef 0
module picorv32_axi_adapter ( module picorv32_axi_adapter (
input clk, resetn, input clk, resetn,
@ -2807,7 +2814,7 @@ module picorv32_axi_adapter (
end end
end end
endmodule endmodule
`endif
/*************************************************************** /***************************************************************
* picorv32_wb * picorv32_wb

View File

@ -99,7 +99,7 @@ always @ (posedge clk) if (wb_cyc && wb_stb && !wb_ack) begin
default: ; default: ;
endcase endcase
wb_ack <= 1; wb_ack <= 1;
end else begin end else if (!wb_cyc) begin
wb_ack <= 0; wb_ack <= 0;
end end

View File

@ -92,94 +92,92 @@ If there is more than one pin in the Pins string, the resulting
name will be a vector of pins. name will be a vector of pins.
""" """
io = [ io = [
("differntial_output_low", 0, Pins("J17 J18 K15 J15 U14 V14 T13 U13 B6 E5 A3"), IOStandard("LVCMOS33")), # ("differntial_output_low", 0, Pins("J17 J18 K15 J15 U14 V14 T13 U13 B6 E5 A3"), IOStandard("LVCMOS33")),
("dac_ss_L", 0, Pins("G13 D13 E15 F5 U12 D7 D4 E2"), IOStandard("LVCMOS33")), ("dac_ss_L_0", 0, Pins("G13"), IOStandard("LVCMOS33")),
("dac_mosi", 0, Pins("B11 B18 E16 D8 V12 D5 D3 D2"), IOStandard("LVCMOS33")), ("dac_mosi_0", 0, Pins("B11"), IOStandard("LVCMOS33")),
("dac_miso", 0, Pins("A11 A18 D15 C7 V10 B7 F4 H2"), IOStandard("LVCMOS33")), ("dac_miso_0", 0, Pins("A11"), IOStandard("LVCMOS33")),
("dac_sck", 0, Pins("D12 K16 C15 E7 V11 E6 F3 G2"), IOStandard("LVCMOS33")), ("dac_sck_0", 0, Pins("D12"), IOStandard("LVCMOS33")),
("adc_conv", 0, Pins("V15 T11 N15 U18 U11 R10 R16 U17"), IOStandard("LVCMOS33")), # ("dac_ss_L", 0, Pins("G13 D13 E15 F5 U12 D7 D4 E2"), IOStandard("LVCMOS33")),
("adc_sck", 0, Pins("U16 R12 M16 R17 V16 R11 N16 T18"), IOStandard("LVCMOS33")), # ("dac_mosi", 0, Pins("B11 B18 E16 D8 V12 D5 D3 D2"), IOStandard("LVCMOS33")),
("adc_sdo", 0, Pins("P14 T14 V17 P17 M13 R13 N14 R18"), IOStandard("LVCMOS33")), # ("dac_miso", 0, Pins("A11 A18 D15 C7 V10 B7 F4 H2"), IOStandard("LVCMOS33")),
# ("dac_sck", 0, Pins("D12 K16 C15 E7 V11 E6 F3 G2"), IOStandard("LVCMOS33")),
# ("adc_conv", 0, Pins("V15 T11 N15 U18 U11 R10 R16 U17"), IOStandard("LVCMOS33")),
# ("adc_sck", 0, Pins("U16 R12 M16 R17 V16 R11 N16 T18"), IOStandard("LVCMOS33")),
# ("adc_sdo", 0, Pins("P14 T14 V17 P17 M13 R13 N14 R18"), IOStandard("LVCMOS33")),
("module_reset", 0, Pins("D9"), IOStandard("LVCMOS33")), ("module_reset", 0, Pins("D9"), IOStandard("LVCMOS33")),
("test_clock", 0, Pins("P18"), IOStandard("LVCMOS33")) # ("test_clock", 0, Pins("P18"), IOStandard("LVCMOS33"))
] ]
class PreemptiveInterface(Module, AutoCSR): # class PreemptiveInterface(Module, AutoCSR):
""" A preemptive interface is a manually controlled Wishbone interface # """ A preemptive interface is a manually controlled Wishbone interface
that stands between multiple masters (potentially interconnects) and a # that stands between multiple masters (potentially interconnects) and a
single slave. A master controls which master (or interconnect) has access # single slave. A master controls which master (or interconnect) has access
to the slave. This is to avoid bus contention by having multiple buses. """ # to the slave. This is to avoid bus contention by having multiple buses. """
#
def __init__(self, masters_len, slave): # def __init__(self, masters_len, slave):
""" # """
:param masters_len: The amount of buses accessing this slave. This number # :param masters_len: The amount of buses accessing this slave. This number
must be greater than one. # must be greater than one.
:param slave: The slave device. This object must have an Interface object # :param slave: The slave device. This object must have an Interface object
accessable as ``bus``. # accessable as ``bus``.
""" # """
#
assert masters_len > 1 # assert masters_len > 1
self.buses = [] # self.buses = []
self.master_select = CSRStorage(masters_len, name='master_select', description='RW bitstring of which master interconnect to connect to') # self.master_select = CSRStorage(masters_len, name='master_select', description='RW bitstring of which master interconnect to connect to')
self.slave = slave # self.slave = slave
#
for i in range(masters_len): # for i in range(masters_len):
# Add the slave interface each master interconnect sees. # # Add the slave interface each master interconnect sees.
self.buses.append(Interface(data_width=32, address_width=32, addressing="byte")) # self.buses.append(Interface(data_width=32, address_width=32, addressing="byte"))
self.comb += [ #
self.buses[i].cti.eq(0), # """
self.buses[i].bte.eq(0), # Construct a combinatorial case statement. In verilog, the if
] # statment would look like
#
""" # always @ (*) case (master_select)
Construct a combinatorial case statement. In verilog, the if # 1: begin
statment would look like # // Bus assignments...
# end
always @ (*) case (master_select) # 2: begin
1: begin # // Bus assignments...
// Bus assignments... # end
end # // more cases:
2: begin # default:
// Bus assignments... # // assign everything to master 0
end # end
// more cases: #
default: # The If statement in Migen (Python HDL) is an object with a method
// assign everything to master 0 # called "ElseIf" and "Else", that return objects with the specified
end # case attached. Instead of directly writing an If statement into
# the combinatorial block, the If statement is constructed in a
The If statement in Migen (Python HDL) is an object with a method # for loop.
called "ElseIf" and "Else", that return objects with the specified #
case attached. Instead of directly writing an If statement into # The "assign_for_case" function constructs the body of the If
the combinatorial block, the If statement is constructed in a # statement. It assigns all output ports to avoid latches.
for loop. # """
#
The "assign_for_case" function constructs the body of the If # def assign_for_case(i):
statement. It assigns all output ports to avoid latches. # asn = [ ]
""" #
# for j in range(masters_len):
def assign_for_case(i): # asn += [
asn = [ ] # self.buses[i].cyc.eq(self.slave.bus.cyc if i == j else 0),
# self.buses[i].stb.eq(self.slave.bus.stb if i == j else 0),
for j in range(masters_len): # self.buses[i].we.eq(self.slave.bus.we if i == j else 0),
asn += [ # self.buses[i].sel.eq(self.slave.bus.sel if i == j else 0),
self.buses[i].cyc.eq(self.slave.bus.cyc if i == j else 0), # self.buses[i].adr.eq(self.slave.bus.adr if i == j else 0),
self.buses[i].stb.eq(self.slave.bus.stb if i == j else 0), # self.buses[i].dat_w.eq(self.slave.bus.dat_w if i == j else 0),
self.buses[i].we.eq(self.slave.bus.we if i == j else 0), # self.buses[i].ack.eq(self.slave.bus.ack if i == j else 0),
self.buses[i].sel.eq(self.slave.bus.sel if i == j else 0), # self.buses[i].dat_r.eq(self.slave.bus.dat_r if i == j else 0),
self.buses[i].adr.eq(self.slave.bus.adr if i == j else 0), # ]
self.buses[i].dat_w.eq(self.slave.bus.dat_w if i == j else 0), # return asn
self.buses[i].ack.eq(self.slave.bus.ack if i == j else 0), #
self.buses[i].dat_r.eq(self.slave.bus.dat_r if i == j else 0), # cases = {"default": assign_for_case(0)}
self.buses[i].cti.eq(0), # for i in range(1, masters_len):
self.buses[i].bte.eq(0), # cases[i] = assign_for_case(i)
] #
return asn # self.comb += Case(self.master_select.storage, cases)
cases = {"default": assign_for_case(0)}
for i in range(1, masters_len):
cases[i] = assign_for_case(i)
self.comb += Case(self.master_select.storage, cases)
class SPIMaster(Module): class SPIMaster(Module):
def __init__(self, rst, miso, mosi, sck, ss, def __init__(self, rst, miso, mosi, sck, ss,
@ -192,24 +190,24 @@ class SPIMaster(Module):
spi_cycle_half_wait = 1, spi_cycle_half_wait = 1,
): ):
self.bus = Interface(data_width = 32, address_width=32, addressing="word") self.bus = Interface(data_width = 32, address_width=32, addressing="byte")
self.region = SoCIORegion(size=0x10, cached=False) self.region = SoCRegion(size=0x10, cached=False)
self.comb += [ self.comb += [
self.bus.cti.eq(0), self.bus.err.eq(0),
self.bus.bte.eq(0),
] ]
self.specials += Instance("spi_master_ss_wb", self.specials += Instance("spi_master_ss_wb",
SS_WAIT = ss_wait, p_SS_WAIT = ss_wait,
SS_WAIT_TIMER_LEN = minwid(ss_wait), p_SS_WAIT_TIMER_LEN = minbits(ss_wait),
CYCLE_HALF_WAIT = spi_cycle_half_wait, p_CYCLE_HALF_WAIT = spi_cycle_half_wait,
TIMER_LEN = minwid(spi_cycle_half_wait), p_TIMER_LEN = minbits(spi_cycle_half_wait),
WID = spi_wid, p_WID = spi_wid,
WID_LEN = minwid(spi_wid), p_WID_LEN = minbits(spi_wid),
ENABLE_MISO = enable_miso, p_ENABLE_MISO = enable_miso,
ENABLE_MOSI = enable_mosi, p_ENABLE_MOSI = enable_mosi,
POLARITY = polarity, p_POLARITY = polarity,
PHASE = phase, p_PHASE = phase,
i_clk = ClockSignal(), i_clk = ClockSignal(),
i_rst_L = rst, i_rst_L = rst,
@ -229,158 +227,150 @@ class SPIMaster(Module):
) )
# TODO: Generalize CSR stuff # TODO: Generalize CSR stuff
class ControlLoopParameters(Module, AutoCSR): # class ControlLoopParameters(Module, AutoCSR):
def __init__(self): # def __init__(self):
self.cl_I = CSRStorage(32, description='Integral parameter') # self.cl_I = CSRStorage(32, description='Integral parameter')
self.cl_P = CSRStorage(32, description='Proportional parameter') # self.cl_P = CSRStorage(32, description='Proportional parameter')
self.deltaT = CSRStorage(32, description='Wait parameter') # self.deltaT = CSRStorage(32, description='Wait parameter')
self.setpt = CSRStorage(32, description='Setpoint') # self.setpt = CSRStorage(32, description='Setpoint')
self.zset = CSRStatus(32, description='Set Z position') # self.zset = CSRStatus(32, description='Set Z position')
self.zpos = CSRStatus(32, description='Measured Z position') # self.zpos = CSRStatus(32, description='Measured Z position')
#
self.bus = Interface(data_width = 32, address_width = 32, addressing="word") # self.bus = Interface(data_width = 32, address_width = 32, addressing="word")
self.region = SoCRegion(size=minbits(0x17), cached=False) # self.region = SoCRegion(size=minbits(0x17), cached=False)
self.comb += [ # self.sync += [
self.bus.cti.eq(0), # If(self.bus.cyc == 1 and self.bus.stb == 1 and self.bus.ack == 0,
self.bus.bte.eq(0), # Case(self.bus.adr[0:4], {
] # 0x0: self.bus.dat_r.eq(self.cl_I.storage),
self.sync += [ # 0x4: self.bus.dat_r.eq(self.cl_P.storage),
If(self.bus.cyc == 1 and self.bus.stb == 1 and self.bus.ack == 0, # 0x8: self.bus.dat_r.eq(self.deltaT.storage),
Case(self.bus.adr[0:4], { # 0xC: self.bus.dat_r.eq(self.setpt.storage),
0x0: self.bus.dat_r.eq(self.cl_I.storage), # 0x10: If(self.bus.we,
0x4: self.bus.dat_r.eq(self.cl_P.storage), # self.zset.status.eq(self.bus.dat_w)
0x8: self.bus.dat_r.eq(self.deltaT.storage), # ).Else(
0xC: self.bus.dat_r.eq(self.setpt.storage), # self.bus.dat_r.eq(self.zset.status)
0x10: If(self.bus.we, # ),
self.zset.status.eq(self.bus.dat_w) # 0x14: If(self.bus.we,
).Else( # self.zpos.status.eq(self.bus.dat_w),
self.bus.dat_r.eq(self.zset.status) # ).Else(
), # self.bus.dat_r.eq(self.zpos.status)
0x14: If(self.bus.we, # ),
self.zpos.status.eq(self.bus.dat_w), # }),
).Else( # self.bus.ack.eq(1),
self.bus.dat_r.eq(self.zpos.status) # ).Else(
), # self.bus.ack.eq(0),
}), # )
self.bus.ack.eq(1), # ]
).Else( #
self.bus.ack.eq(0), # class BRAM(Module):
) # """ A BRAM (block ram) is a memory store that is completely separate from
] # the system RAM. They are much smaller.
# """
class BRAM(Module): # def __init__(self, addr_mask, origin=None):
""" A BRAM (block ram) is a memory store that is completely separate from # """
the system RAM. They are much smaller. # :param addr_mask: Mask which defines the amount of bytes accessable
""" # by the BRAM.
def __init__(self, addr_mask, origin=None): # :param origin: Origin of the BRAM module region. This is seen by the
""" # subordinate master, not the usual master.
:param addr_mask: Mask which defines the amount of bytes accessable # """
by the BRAM. # self.bus = Interface(data_width=32, address_width=32, addressing="byte")
:param origin: Origin of the BRAM module region. This is seen by the #
subordinate master, not the usual master. # # Non-IO (i.e. MMIO) regions need to be cached
""" # self.region = SoCRegion(origin=origin, size=addr_mask+1, cached=True)
self.bus = Interface(data_width=32, address_width=32, addressing="byte") #
# self.specials += Instance("bram",
# Non-IO (i.e. MMIO) regions need to be cached # p_ADDR_MASK = addr_mask,
self.region = SoCRegion(origin=origin, size=addr_mask+1, cached=True) # i_clk = ClockSignal(),
# i_wb_cyc = self.bus.cyc,
self.comb += [ # i_wb_stb = self.bus.stb,
self.bus.cti.eq(0), # i_wb_we = self.bus.we,
self.bus.bte.eq(0), # i_wb_sel = self.bus.sel,
] # i_wb_addr = self.bus.adr,
self.specials += Instance("bram", # i_wb_dat_w = self.bus.dat_w,
p_ADDR_MASK = addr_mask, # o_wb_ack = self.bus.ack,
i_clk = ClockSignal(), # o_wb_dat_r = self.bus.dat_r,
i_wb_cyc = self.bus.cyc, # )
i_wb_stb = self.bus.stb, #
i_wb_we = self.bus.we, # class PicoRV32(Module, AutoCSR):
i_wb_sel = self.bus.sel, # def __init__(self, bramwid=0x1000):
i_wb_addr = self.bus.adr, # self.submodules.params = params = ControlLoopParameters()
i_wb_dat_w = self.bus.dat_w, # self.submodules.bram = self.bram = bram = BRAM(bramwid-1, origin=0x10000)
o_wb_ack = self.bus.ack, # self.submodules.bram_iface = self.bram_iface = bram_iface = PreemptiveInterface(2, bram)
o_wb_dat_r = self.bus.dat_r, #
) # # This is the PicoRV32 master
# self.masterbus = Interface(data_width=32, address_width=32, addressing="byte")
class PicoRV32(Module, AutoCSR): #
def __init__(self, bramwid=0x1000): # self.resetpin = CSRStorage(1, name="picorv32_reset", description="PicoRV32 reset")
self.submodules.params = params = ControlLoopParameters() # self.trap = CSRStatus(1, name="picorv32_trap", description="Trap bit")
self.submodules.bram = self.bram = bram = BRAM(bramwid-1, origin=0x10000) #
self.submodules.bram_iface = self.bram_iface = bram_iface = PreemptiveInterface(2, bram) # self.ic = ic = SoCBusHandler(
# standard="wishbone",
# This is the PicoRV32 master # data_width=32,
self.masterbus = Interface(data_width=32, address_width=32, addressing="byte") # address_width=32,
# timeout=1e6,
self.resetpin = CSRStorage(1, name="picorv32_reset", description="PicoRV32 reset") # bursting=False,
self.trap = CSRStatus(1, name="picorv32_trap", description="Trap bit") # interconnect="shared",
# interconnect_register=True,
self.ic = ic = SoCBusHandler( # reserved_regions={
standard="wishbone", # "picorv32_null_region": SoCRegion(origin=0,size=0x10000, mode="ro", cached=True),
data_width=32, # "picorv32_io": SoCIORegion(origin=0x100000, size=0x100, mode="rw", cached=False),
address_width=32, # },
timeout=1e6, # )
bursting=False, #
interconnect="shared", # ic.add_slave("picorv32_bram", bram_iface.buses[1], bram.region)
interconnect_register=True, # ic.add_slave("picorv32_params", params.bus, params.region)
reserved_regions={ # ic.add_master("picorv32_master", self.masterbus)
"picorv32_null_region": SoCRegion(origin=0,size=0x10000, mode="ro", cached=True), #
"picorv32_io": SoCIORegion(origin=0x100000, size=0x100, mode="rw", cached=False), # # NOTE: need to compile to these extact instructions
}, # self.specials += Instance("picorv32_wb",
) # p_COMPRESSED_ISA = 1,
# p_ENABLE_MUL = 1,
ic.add_slave("picorv32_bram", bram_iface.buses[1], bram.region) # p_PROGADDR_RESET=0x10000,
ic.add_slave("picorv32_params", params.bus, params.region) # p_PROGADDR_IRQ=0x100010,
ic.add_master("picorv32_master", self.masterbus) # p_REGS_INIT_ZERO = 1,
# o_trap = self.trap.status,
# NOTE: need to compile to these extact instructions #
self.specials += Instance("picorv32_wb", # i_wb_rst_i = ~self.resetpin.storage,
p_COMPRESSED_ISA = 1, # i_wb_clk_i = ClockSignal(),
p_ENABLE_MUL = 1, # o_wbm_adr_o = self.masterbus.adr,
p_PROGADDR_RESET=0x10000, # o_wbm_dat_o = self.masterbus.dat_r,
p_PROGADDR_IRQ=0x100010, # i_wbm_dat_i = self.masterbus.dat_w,
p_REGS_INIT_ZERO = 1, # o_wbm_we_o = self.masterbus.we,
o_trap = self.trap.status, # o_wbm_sel_o = self.masterbus.sel,
# o_wbm_stb_o = self.masterbus.stb,
i_wb_rst_i = ~self.resetpin.storage, # i_wbm_ack_i = self.masterbus.ack,
i_wb_clk_i = ClockSignal(), # o_wbm_cyc_o = self.masterbus.cyc,
o_wbm_adr_o = self.masterbus.adr, #
o_wbm_dat_o = self.masterbus.dat_r, # o_pcpi_valid = Signal(),
i_wbm_dat_i = self.masterbus.dat_w, # o_pcpi_insn = Signal(32),
o_wbm_we_o = self.masterbus.we, # o_pcpi_rs1 = Signal(32),
o_wbm_sel_o = self.masterbus.sel, # o_pcpi_rs2 = Signal(32),
o_wbm_stb_o = self.masterbus.stb, # i_pcpi_wr = 0,
i_wbm_ack_i = self.masterbus.ack, # i_pcpi_wait = 0,
o_wbm_cyc_o = self.masterbus.cyc, # i_pcpi_rd = 0,
# i_pcpi_ready = 0,
o_pcpi_valid = Signal(), #
o_pcpi_insn = Signal(32), # i_irq = 0,
o_pcpi_rs1 = Signal(32), # o_eoi = Signal(32),
o_pcpi_rs2 = Signal(32), #
i_pcpi_wr = 0, # o_trace_valid = Signal(),
i_pcpi_wait = 0, # o_trace_data = Signal(36),
i_pcpi_rd = 0, # )
i_pcpi_ready = 0, #
# def do_finalize(self):
i_irq = 0, # self.ic.finalize()
o_eoi = Signal(32), # jsondata = {}
#
o_trace_valid = Signal(), # for region in self.ic.regions:
o_trace_data = Signal(36), # d = self.ic.regions[region]
) # jsondata[region] = {
# "origin": d.origin,
def do_finalize(self): # "size": d.size,
self.ic.finalize() # }
jsondata = {} #
# with open('picorv32.json', 'w') as f:
for region in self.ic.regions: # import json
d = self.ic.regions[region] # json.dump(jsondata, f)
jsondata[region] = {
"origin": d.origin,
"size": d.size,
}
with open('picorv32.json', 'w') as f:
import json
json.dump(jsondata, f)
# Clock and Reset Generator # Clock and Reset Generator
# I don't know how this works, I only know that it does. # I don't know how this works, I only know that it does.
@ -423,7 +413,11 @@ class UpsilonSoC(SoCCore):
def add_picorv32(self): def add_picorv32(self):
self.submodules.picorv32 = pr = PicoRV32() self.submodules.picorv32 = pr = PicoRV32()
self.bus.add_slave("picorv32_master_bram", pr.bram_iface.buses[0], self.bus.add_slave("picorv32_master_bram", pr.bram_iface.buses[0],
SoCRegion(size=pr.bram.region.size, cached=True)) SoCRegion(origin=None,size=pr.bram.region.size, cached=True))
def add_bram(self):
self.submodules.bram = br = BRAM(0x1FF)
self.bus.add_slave("bram", br.bus, br.region)
def __init__(self, def __init__(self,
variant="a7-100", variant="a7-100",
@ -456,7 +450,7 @@ class UpsilonSoC(SoCCore):
# SoCCore does not have sane defaults (no integrated rom) # SoCCore does not have sane defaults (no integrated rom)
SoCCore.__init__(self, SoCCore.__init__(self,
clk_freq=sys_clk_freq, clk_freq=sys_clk_freq,
toolchain="f4pga", toolchain="symbiflow",
platform = platform, platform = platform,
bus_standard = "wishbone", bus_standard = "wishbone",
ident = f"Arty-{variant} F4PGA LiteX VexRiscV Zephyr - Upsilon", ident = f"Arty-{variant} F4PGA LiteX VexRiscV Zephyr - Upsilon",
@ -500,6 +494,16 @@ class UpsilonSoC(SoCCore):
# Add pins # Add pins
platform.add_extension(io) platform.add_extension(io)
self.submodules.spi0 = SPIMaster(
platform.request("module_reset"),
platform.request("dac_miso_0"),
platform.request("dac_mosi_0"),
platform.request("dac_sck_0"),
platform.request("dac_ss_L_0"),
)
self.bus.add_slave("spi0", self.spi0.bus, self.spi0.region)
#self.add_bram()
#self.add_picorv32() #self.add_picorv32()
def main(): def main():