more cleanup and bug finding
This commit is contained in:
parent
a10ad772bc
commit
4e3df09bb8
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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}
|
|
|
@ -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];
|
wb_ack <= 1;
|
||||||
end⟩)
|
if (wb_we) begin
|
||||||
|
if (wb_sel[0])
|
||||||
always @ (posedge clk) if (wb_cyc && wb_stb && !wb_ack)
|
buffer[ind][7:0] <= wb_dat_w[7:0];
|
||||||
if (!wb_we) begin
|
if (wb_sel[1])
|
||||||
wb_dat_r <= buffer[ind];
|
buffer[ind][15:8] <= wb_dat_w[15:8];
|
||||||
wb_ack <= 1;
|
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
524
gateware/soc.py
524
gateware/soc.py
|
@ -92,124 +92,122 @@ 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,
|
||||||
polarity = 0,
|
polarity = 0,
|
||||||
phase = 0,
|
phase = 0,
|
||||||
ss_wait = 1,
|
ss_wait = 1,
|
||||||
enable_miso = 1,
|
enable_miso = 1,
|
||||||
enable_mosi = 1,
|
enable_mosi = 1,
|
||||||
spi_wid = 24,
|
spi_wid = 24,
|
||||||
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():
|
||||||
|
|
Loading…
Reference in New Issue