Add uart2csr
This commit is contained in:
parent
60e2cdfe79
commit
36f3556028
|
@ -1,6 +1,4 @@
|
|||
import os
|
||||
from mibuild.platforms import de0nano
|
||||
from mibuild.altera_quartus import _add_period_constraint
|
||||
import top
|
||||
|
||||
def main():
|
||||
|
@ -8,8 +6,6 @@ def main():
|
|||
soc = top.SoC()
|
||||
|
||||
# set pin constraints
|
||||
plat.request("clk50", obj=soc.clk50)
|
||||
plat.request("key", obj=soc.key)
|
||||
plat.request("led", obj=soc.led)
|
||||
plat.request("gpio_2", obj=soc.gpio_2)
|
||||
|
||||
|
@ -25,10 +21,7 @@ set_global_assignment -name RESERVE_DATA1_AFTER_CONFIGURATION "USE AS REGULAR IO
|
|||
set_global_assignment -name RESERVE_DCLK_AFTER_CONFIGURATION "USE AS REGULAR IO"
|
||||
""")
|
||||
|
||||
_add_period_constraint(plat, "sys_clk", 20.0)
|
||||
cd = dict()
|
||||
cd["sys"] = soc.cd_sys
|
||||
plat.build_cmdline(soc.get_fragment(), clock_domains=cd)
|
||||
plat.build_cmdline(soc.get_fragment())
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -1,4 +0,0 @@
|
|||
#
|
||||
# Clocks
|
||||
#
|
||||
create_clock -period 50MHz [get_ports clk50]
|
|
@ -1,4 +0,0 @@
|
|||
#
|
||||
# Clocks
|
||||
#
|
||||
create_clock -period 50MHz [get_ports clk50]
|
|
@ -1,97 +1,73 @@
|
|||
from migen.fhdl.structure import *
|
||||
from migen.genlib.misc import *
|
||||
from migen.genlib.cdc import *
|
||||
from migen.bus import csr
|
||||
from migen.bank import description, csrgen
|
||||
from migen.bank.description import *
|
||||
|
||||
class Spi2Csr :
|
||||
def __init__(self, a_width, d_width, max_burst = 8):
|
||||
self.a_width = a_width
|
||||
self.d_width = d_width
|
||||
self.max_burst = 8
|
||||
class Spi2Csr(Module):
|
||||
def __init__(self, a_w, d_w, burst_length=8):
|
||||
self.a_w = a_w
|
||||
self.d_w = d_w
|
||||
self.burst_length = 8
|
||||
|
||||
# Csr interface
|
||||
self.csr = csr.Interface(self.a_width, self.d_width)
|
||||
self.csr = csr.Interface(self.a_w, self.d_w)
|
||||
|
||||
# Spi interface
|
||||
self.spi_clk = Signal()
|
||||
self.spi_cs_n = Signal(reset=1)
|
||||
self.spi_mosi = Signal()
|
||||
self.spi_miso = Signal()
|
||||
self.spi_int_n = Signal(reset=1)
|
||||
|
||||
def get_fragment(self):
|
||||
comb = []
|
||||
sync = []
|
||||
###
|
||||
|
||||
# Resychronisation
|
||||
spi_clk_d1 = Signal()
|
||||
spi_clk_d2 = Signal()
|
||||
spi_clk_d3 = Signal()
|
||||
|
||||
sync += [
|
||||
spi_clk_d1.eq(self.spi_clk),
|
||||
spi_clk_d2.eq(spi_clk_d1),
|
||||
spi_clk_d3.eq(spi_clk_d2)
|
||||
]
|
||||
|
||||
spi_cs_n_d1 = Signal()
|
||||
spi_cs_n_d2 = Signal()
|
||||
spi_cs_n_d3 = Signal()
|
||||
|
||||
sync += [
|
||||
spi_cs_n_d1.eq(self.spi_cs_n),
|
||||
spi_cs_n_d2.eq(spi_cs_n_d1),
|
||||
spi_cs_n_d3.eq(spi_cs_n_d2)
|
||||
]
|
||||
|
||||
spi_mosi_d1 = Signal()
|
||||
spi_mosi_d2 = Signal()
|
||||
spi_mosi_d3 = Signal()
|
||||
|
||||
sync += [
|
||||
spi_mosi_d1.eq(self.spi_mosi),
|
||||
spi_mosi_d2.eq(spi_mosi_d1),
|
||||
spi_mosi_d3.eq(spi_mosi_d2)
|
||||
]
|
||||
|
||||
clk_synchro = Synchronizer(i=self.spi_clk)
|
||||
cs_n_synchro = Synchronizer(i=self.spi_cs_n)
|
||||
mosi_synchro = Synchronizer(i=self.spi_mosi)
|
||||
|
||||
self.specials += {clk_synchro, cs_n_synchro, mosi_synchro}
|
||||
|
||||
# Decode
|
||||
spi_clk_rising = Signal()
|
||||
spi_clk_falling = Signal()
|
||||
spi_cs_n_active = Signal()
|
||||
spi_mosi_dat = Signal()
|
||||
|
||||
comb += [
|
||||
spi_clk_rising.eq(spi_clk_d2 & ~spi_clk_d3),
|
||||
spi_clk_falling.eq(~spi_clk_d2 & spi_clk_d3),
|
||||
spi_cs_n_active.eq(~spi_cs_n_d3),
|
||||
spi_mosi_dat.eq(spi_mosi_d3)
|
||||
self.specials += RisingEdge(i=clk_synchro.o, o=spi_clk_rising)
|
||||
self.specials += FallingEdge(i=clk_synchro.o, o=spi_clk_falling)
|
||||
|
||||
self.sync +=[
|
||||
spi_cs_n_active.eq(~cs_n_synchro.o),
|
||||
spi_mosi_dat.eq(~mosi_synchro.o),
|
||||
]
|
||||
|
||||
#
|
||||
# Spi --> Csr
|
||||
#
|
||||
spi_cnt = Signal(bits_for(self.a_width+self.max_burst*self.d_width))
|
||||
spi_addr = Signal(self.a_width)
|
||||
spi_w_dat = Signal(self.d_width)
|
||||
spi_r_dat = Signal(self.d_width)
|
||||
spi_cnt = Signal(bits_for(self.a_w + self.burst_length*self.d_w))
|
||||
spi_addr = Signal(self.a_w)
|
||||
spi_w_dat = Signal(self.d_w)
|
||||
spi_r_dat = Signal(self.d_w)
|
||||
spi_we = Signal()
|
||||
spi_re = Signal()
|
||||
spi_we_re_done = Signal(reset = 1)
|
||||
spi_we_re_done = Signal(reset=1)
|
||||
spi_miso_dat = Signal()
|
||||
|
||||
# Re/We Signals Decoding
|
||||
first_b = Signal()
|
||||
last_b = Signal()
|
||||
|
||||
comb +=[
|
||||
first_b.eq(spi_cnt[0:bits_for(self.d_width)-1] == 0),
|
||||
last_b.eq(spi_cnt[0:bits_for(self.d_width)-1] == 2**(bits_for(self.d_width)-1)-1)
|
||||
self.comb +=[
|
||||
first_b.eq(spi_cnt[0:bits_for(self.d_w)-1] == 0),
|
||||
last_b.eq(spi_cnt[0:bits_for(self.d_w)-1] == 2**(bits_for(self.d_w-1))-1)
|
||||
]
|
||||
sync +=[
|
||||
If((spi_cnt >= (self.a_width + self.d_width)) & first_b,
|
||||
spi_we.eq(spi_addr[self.a_width-1] & ~spi_we_re_done),
|
||||
spi_re.eq(~spi_addr[self.a_width-1] & ~spi_we_re_done),
|
||||
self.sync +=[
|
||||
If((spi_cnt >= (self.a_w + self.d_w)) & first_b,
|
||||
spi_we.eq(spi_addr[self.a_w-1] & ~spi_we_re_done),
|
||||
spi_re.eq(~spi_addr[self.a_w-1] & ~spi_we_re_done),
|
||||
spi_we_re_done.eq(1)
|
||||
).Elif((spi_cnt >= self.a_width) & first_b,
|
||||
spi_re.eq(~spi_addr[self.a_width-1] & ~spi_we_re_done),
|
||||
).Elif((spi_cnt >= self.a_w) & first_b,
|
||||
spi_re.eq(~spi_addr[self.a_w-1] & ~spi_we_re_done),
|
||||
spi_we_re_done.eq(1)
|
||||
).Else(
|
||||
spi_we.eq(0),
|
||||
|
@ -101,21 +77,21 @@ class Spi2Csr :
|
|||
]
|
||||
|
||||
# Spi Addr / Data Decoding
|
||||
sync +=[
|
||||
self.sync +=[
|
||||
If(~spi_cs_n_active,
|
||||
spi_cnt.eq(0),
|
||||
).Elif(spi_clk_rising,
|
||||
# addr
|
||||
If(spi_cnt < self.a_width,
|
||||
spi_addr.eq(Cat(spi_mosi_dat,spi_addr[:self.a_width-1]))
|
||||
).Elif((spi_cnt >= (self.a_width+self.d_width)) & last_b,
|
||||
If(spi_cnt < self.a_w,
|
||||
spi_addr.eq(Cat(spi_mosi_dat,spi_addr[:self.a_w-1]))
|
||||
).Elif((spi_cnt >= (self.a_w+self.d_w)) & last_b,
|
||||
spi_addr.eq(spi_addr+1)
|
||||
).Elif((spi_cnt >= self.a_width) & last_b & (spi_addr[self.a_width-1] == 0),
|
||||
).Elif((spi_cnt >= self.a_w) & last_b & (spi_addr[self.a_w-1] == 0),
|
||||
spi_addr.eq(spi_addr+1)
|
||||
),
|
||||
# dat
|
||||
If(spi_cnt >= self.a_width,
|
||||
spi_w_dat.eq(Cat(spi_mosi_dat,spi_w_dat[:self.d_width-1]))
|
||||
If(spi_cnt >= self.a_w,
|
||||
spi_w_dat.eq(Cat(spi_mosi_dat,spi_w_dat[:self.d_w-1]))
|
||||
),
|
||||
|
||||
# spi_cnt
|
||||
|
@ -126,8 +102,8 @@ class Spi2Csr :
|
|||
#
|
||||
# Csr --> Spi
|
||||
#
|
||||
spi_r_dat_shift = Signal(self.d_width)
|
||||
sync +=[
|
||||
spi_r_dat_shift = Signal(self.d_w)
|
||||
self.sync +=[
|
||||
If(spi_re,
|
||||
spi_r_dat_shift.eq(spi_r_dat)
|
||||
),
|
||||
|
@ -135,16 +111,16 @@ class Spi2Csr :
|
|||
If(~spi_cs_n_active,
|
||||
spi_miso_dat.eq(0)
|
||||
).Elif(spi_clk_falling,
|
||||
spi_miso_dat.eq(spi_r_dat_shift[self.d_width-1]),
|
||||
spi_r_dat_shift.eq(Cat(0,spi_r_dat_shift[:self.d_width-1]))
|
||||
spi_miso_dat.eq(spi_r_dat_shift[self.d_w-1]),
|
||||
spi_r_dat_shift.eq(Cat(0,spi_r_dat_shift[:self.d_w-1]))
|
||||
)
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
#
|
||||
# Csr Interface
|
||||
#
|
||||
comb += [
|
||||
self.comb += [
|
||||
self.csr.adr.eq(spi_addr),
|
||||
self.csr.dat_w.eq(spi_w_dat),
|
||||
self.csr.we.eq(spi_we)
|
||||
|
@ -153,8 +129,7 @@ class Spi2Csr :
|
|||
#
|
||||
# Spi Interface
|
||||
#
|
||||
comb += [
|
||||
self.comb += [
|
||||
spi_r_dat.eq(self.csr.dat_r),
|
||||
self.spi_miso.eq(spi_miso_dat)
|
||||
]
|
||||
return Fragment(comb=comb,sync=sync)
|
||||
]
|
|
@ -0,0 +1,181 @@
|
|||
from migen.fhdl.structure import *
|
||||
from migen.genlib.misc import *
|
||||
from migen.genlib.cdc import *
|
||||
from migen.bus import csr
|
||||
|
||||
from miscope.bridges.uart2csr.uart import *
|
||||
|
||||
WRITE_CMD = 0x01
|
||||
READ_CMD = 0x02
|
||||
CLOSE_CMD = 0x03
|
||||
|
||||
class Uart2Csr(Module):
|
||||
def __init__(self, clk_freq, baud):
|
||||
# Uart interface
|
||||
self.rx = Signal()
|
||||
self.tx = Signal()
|
||||
|
||||
# Csr interface
|
||||
self.csr = csr.Interface(32, 8)
|
||||
|
||||
###
|
||||
|
||||
uart = Uart(clk_freq, baud)
|
||||
self.specials +=uart
|
||||
|
||||
#
|
||||
# In/Out
|
||||
#
|
||||
self.comb +=[
|
||||
uart.rx.eq(self.rx),
|
||||
self.tx.eq(uart.tx)
|
||||
]
|
||||
|
||||
cmd = Signal(8)
|
||||
cnt = Signal(3)
|
||||
sr = Signal(32)
|
||||
burst_cnt = Signal(8)
|
||||
addr = Signal(32)
|
||||
data = Signal(8)
|
||||
|
||||
#
|
||||
# Global
|
||||
#
|
||||
self.sync +=[
|
||||
If(fsm.ongoing(fsm.IDLE), cnt.eq(0)
|
||||
).Elif(uart_rx_ev, cnt.eq(cnt + 1)),
|
||||
|
||||
sr.eq(Cat(uart.rx_dat, sr[0:24]))
|
||||
]
|
||||
|
||||
# FSM
|
||||
fsm = FSM("IDLE",
|
||||
"GET_BL", "GET_ADDR",
|
||||
"GET_DATA", "WRITE_CSR",
|
||||
"READ_CSR", "SEND_DATA")
|
||||
|
||||
# State done
|
||||
get_bl_done = Signal()
|
||||
get_addr_done = Signal()
|
||||
get_data_done = Signal()
|
||||
send_data_done = Signal()
|
||||
|
||||
#
|
||||
# Idle
|
||||
#
|
||||
fsm.act(fsm.IDLE,
|
||||
If(uart.rx_ev and (uart.rx_dat == WRITE_CMD or uart.rx_dat == READ_CMD),
|
||||
fsm.next_state(fsm.GET_BL)
|
||||
)
|
||||
)
|
||||
|
||||
self.sync +=[
|
||||
If(fsm.ongoing(fsm.IDLE) and uart_rx_env,
|
||||
cmd.eq(uart.rx_dat)
|
||||
)
|
||||
|
||||
]
|
||||
|
||||
#
|
||||
# Get burst length
|
||||
#
|
||||
fsm.act(fsm.GET_BL,
|
||||
If(get_bl_done,
|
||||
fsm.next_state(fsm.GET_ADDR)
|
||||
)
|
||||
)
|
||||
|
||||
self.comb += get_bl_done.eq(uart_rx_ev and fsm.ongoing(fsm.GET_BL))
|
||||
|
||||
self.sync +=[
|
||||
If(get_bl_done,
|
||||
burst_cnt.eq(uart.rx_dat)
|
||||
)
|
||||
]
|
||||
|
||||
#
|
||||
# Get address
|
||||
#
|
||||
fsm.act(fsm.GET_ADDR,
|
||||
If(get_addr_done and cmd == WRITE_CMD,
|
||||
fsm.next_state(fsm.GET_DATA)
|
||||
).Elif(get_addr_done and cmd == READ_CMD,
|
||||
fsm.next_state(fsm.READ_CSR)
|
||||
)
|
||||
)
|
||||
|
||||
self.comb += get_addr_done.eq(uart_rx_ev and rx_cnt == 4 and fsm.ongoing(fsm.GET_ADDR))
|
||||
|
||||
self.sync +=[
|
||||
If(get_addr_done,
|
||||
addr.eq(sr)
|
||||
).Elif(write_data_done or send_data_done,
|
||||
addr.eq(addr + 4)
|
||||
)
|
||||
]
|
||||
|
||||
#
|
||||
# Get data
|
||||
#
|
||||
fsm.act(fsm.GET_DATA,
|
||||
If(get_data_done,
|
||||
fsm.next_state(fsm.IDLE)
|
||||
)
|
||||
)
|
||||
|
||||
self.comb += get_data_done.eq(uart_rx_ev and fsm.ongoing(fsm.GET_DATA))
|
||||
|
||||
self.sync +=[
|
||||
If(get_data_done,
|
||||
burst_cnt.eq(burst_cnt-1),
|
||||
data.eq(uart.rx_dat)
|
||||
)
|
||||
]
|
||||
|
||||
#
|
||||
# Write Csr
|
||||
#
|
||||
fsm.act(fsm.WRITE_CSR,
|
||||
If((not burst_cnt),
|
||||
fsm.next_state(fsm.IDLE)
|
||||
).Else(fsm.next_state(fsm.GET_DATA))
|
||||
)
|
||||
|
||||
#
|
||||
# Read Csr
|
||||
#
|
||||
fsm.act(fsm.READ_CSR,
|
||||
fsm.next_state(fsm.SEND_DATA)
|
||||
)
|
||||
|
||||
#
|
||||
# Send Data
|
||||
#
|
||||
fsm.act(fsm.SEND_DATA,
|
||||
If(send_data_done and (not burst_cnt),
|
||||
fsm.next_state(fsm.IDLE)
|
||||
).Elif(send_data_done,
|
||||
fsm.next_state(fsm.READ_CSR)
|
||||
)
|
||||
)
|
||||
|
||||
self.comb += [
|
||||
uart.tx_dat.eq(csr.dat_r),
|
||||
uart.we.eq(fsm.entering(fsm.SEND_DATA)),
|
||||
send_data_done.eq(~uart.we or uart.tx_ev)
|
||||
]
|
||||
|
||||
#
|
||||
# Csr access
|
||||
#
|
||||
self.sync +=[
|
||||
self.csr.adr.eq(addr),
|
||||
self.csr.dat_w.eq(data),
|
||||
If(fsm.ongoing(fsm.WRITE_CSR,
|
||||
self.csr.we.eq(1)
|
||||
).Else(
|
||||
self.csr.we.eq(0)
|
||||
)
|
||||
]
|
||||
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
from migen.fhdl.structure import *
|
||||
from migen.fhdl.module import Module
|
||||
from migen.genlib.cdc import MultiReg
|
||||
from migen.bank.description import *
|
||||
from migen.bank.eventmanager import *
|
||||
|
||||
class UART(Module):
|
||||
def __init__(self, clk_freq, baud=115200):
|
||||
|
||||
self.rx_ev = Signal()
|
||||
self.rx_dat = Signal(8)
|
||||
|
||||
self.tx_we = Signal()
|
||||
self.tx_ev = Signal()
|
||||
self.tx_dat = Signal(8)
|
||||
|
||||
self.divisor = Signal(16, reset=int(clk_freq/baud/16))
|
||||
|
||||
self.tx = Signal(reset=1)
|
||||
self.rx = Signal()
|
||||
|
||||
###
|
||||
|
||||
enable16 = Signal()
|
||||
enable16_counter = Signal(16)
|
||||
self.comb += enable16.eq(enable16_counter == 0)
|
||||
self.sync += [
|
||||
enable16_counter.eq(enable16_counter - 1),
|
||||
If(enable16,
|
||||
enable16_counter.eq(self.divisor - 1))
|
||||
]
|
||||
|
||||
# TX
|
||||
tx_reg = Signal(8)
|
||||
tx_bitcount = Signal(4)
|
||||
tx_count16 = Signal(4)
|
||||
tx_busy = self.tx_ev
|
||||
self.sync += [
|
||||
If(self.tx_we,
|
||||
tx_reg.eq(self.tx_dat),
|
||||
tx_bitcount.eq(0),
|
||||
tx_count16.eq(1),
|
||||
tx_busy.eq(1),
|
||||
self.tx.eq(0)
|
||||
).Elif(enable16 & tx_busy,
|
||||
tx_count16.eq(tx_count16 + 1),
|
||||
If(tx_count16 == 0,
|
||||
tx_bitcount.eq(tx_bitcount + 1),
|
||||
If(tx_bitcount == 8,
|
||||
self.tx.eq(1)
|
||||
).Elif(tx_bitcount == 9,
|
||||
self.tx.eq(1),
|
||||
tx_busy.eq(0)
|
||||
).Else(
|
||||
self.tx.eq(tx_reg[0]),
|
||||
tx_reg.eq(Cat(tx_reg[1:], 0))
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
# RX
|
||||
rx = Signal()
|
||||
self.specials += MultiReg(self.rx, "ext", rx, "sys")
|
||||
rx_r = Signal()
|
||||
rx_reg = Signal(8)
|
||||
rx_bitcount = Signal(4)
|
||||
rx_count16 = Signal(4)
|
||||
rx_busy = Signal()
|
||||
rx_done = self.rx_ev
|
||||
rx_data = self.rx_dat
|
||||
self.sync += [
|
||||
rx_done.eq(0),
|
||||
If(enable16,
|
||||
rx_r.eq(rx),
|
||||
If(~rx_busy,
|
||||
If(~rx & rx_r, # look for start bit
|
||||
rx_busy.eq(1),
|
||||
rx_count16.eq(7),
|
||||
rx_bitcount.eq(0)
|
||||
)
|
||||
).Else(
|
||||
rx_count16.eq(rx_count16 + 1),
|
||||
If(rx_count16 == 0,
|
||||
rx_bitcount.eq(rx_bitcount + 1),
|
||||
|
||||
If(rx_bitcount == 0,
|
||||
If(rx, # verify start bit
|
||||
rx_busy.eq(0)
|
||||
)
|
||||
).Elif(rx_bitcount == 9,
|
||||
rx_busy.eq(0),
|
||||
If(rx, # verify stop bit
|
||||
rx_data.eq(rx_reg),
|
||||
rx_done.eq(1)
|
||||
)
|
||||
).Else(
|
||||
rx_reg.eq(Cat(rx_reg[1:], rx))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
|
@ -7,22 +7,20 @@ class MiIo:
|
|||
#
|
||||
# Definition
|
||||
#
|
||||
def __init__(self, address, width, mode = "IO", interface=None):
|
||||
def __init__(self, address, width, mode="IO", interface=None):
|
||||
self.address = address
|
||||
self.width = width
|
||||
self.mode = mode
|
||||
self.mode = mode.upper()
|
||||
self.interface = interface
|
||||
self.words = int(2**bits_for(width-1)/8)
|
||||
self.words = int((2**bits_for(width-1))/8)
|
||||
|
||||
if "I" in self.mode:
|
||||
self.i = Signal(self.width)
|
||||
self.ireg = description.RegisterField("i", self.width, READ_ONLY, WRITE_ONLY)
|
||||
self.ireg.field.w.name_override = "inputs"
|
||||
|
||||
if "O" in self.mode:
|
||||
self.o = Signal(self.width)
|
||||
self.oreg = description.RegisterField("o", self.width)
|
||||
self.oreg.field.r.name_override = "ouptuts"
|
||||
|
||||
self.bank = csrgen.Bank([self.oreg, self.ireg], address=self.address)
|
||||
|
||||
|
@ -30,18 +28,18 @@ class MiIo:
|
|||
comb = []
|
||||
|
||||
if "I" in self.mode:
|
||||
comb += [self.ireg.field.w.eq(self.i)]
|
||||
comb += self.ireg.field.w.eq(self.i)
|
||||
|
||||
if "O" in self.mode:
|
||||
comb += [self.o.eq(self.oreg.field.r)]
|
||||
comb += self.o.eq(self.oreg.field.r)
|
||||
|
||||
return Fragment(comb) + self.bank.get_fragment()
|
||||
#
|
||||
#Driver
|
||||
#
|
||||
def write(self, data):
|
||||
self.interface.write_n(self.address, data, self.width)
|
||||
self.interface.write(self.address, data, self.width)
|
||||
|
||||
def read(self):
|
||||
r = self.interface.read_n(self.address + self.words, self.width)
|
||||
r = self.interface.read(self.address + self.words, self.width)
|
||||
return r
|
Loading…
Reference in New Issue