Add uart2csr

This commit is contained in:
Florent Kermarrec 2013-03-18 21:45:07 +01:00
parent 60e2cdfe79
commit 36f3556028
7 changed files with 344 additions and 102 deletions

View File

@ -1,6 +1,4 @@
import os
from mibuild.platforms import de0nano from mibuild.platforms import de0nano
from mibuild.altera_quartus import _add_period_constraint
import top import top
def main(): def main():
@ -8,8 +6,6 @@ def main():
soc = top.SoC() soc = top.SoC()
# set pin constraints # set pin constraints
plat.request("clk50", obj=soc.clk50)
plat.request("key", obj=soc.key)
plat.request("led", obj=soc.led) plat.request("led", obj=soc.led)
plat.request("gpio_2", obj=soc.gpio_2) 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" set_global_assignment -name RESERVE_DCLK_AFTER_CONFIGURATION "USE AS REGULAR IO"
""") """)
_add_period_constraint(plat, "sys_clk", 20.0) plat.build_cmdline(soc.get_fragment())
cd = dict()
cd["sys"] = soc.cd_sys
plat.build_cmdline(soc.get_fragment(), clock_domains=cd)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -1,4 +0,0 @@
#
# Clocks
#
create_clock -period 50MHz [get_ports clk50]

View File

@ -1,4 +0,0 @@
#
# Clocks
#
create_clock -period 50MHz [get_ports clk50]

View File

@ -1,97 +1,73 @@
from migen.fhdl.structure import * from migen.fhdl.structure import *
from migen.genlib.misc import *
from migen.genlib.cdc import *
from migen.bus import csr from migen.bus import csr
from migen.bank import description, csrgen
from migen.bank.description import *
class Spi2Csr : class Spi2Csr(Module):
def __init__(self, a_width, d_width, max_burst = 8): def __init__(self, a_w, d_w, burst_length=8):
self.a_width = a_width self.a_w = a_w
self.d_width = d_width self.d_w = d_w
self.max_burst = 8 self.burst_length = 8
# Csr interface # Csr interface
self.csr = csr.Interface(self.a_width, self.d_width) self.csr = csr.Interface(self.a_w, self.d_w)
# Spi interface # Spi interface
self.spi_clk = Signal() self.spi_clk = Signal()
self.spi_cs_n = Signal(reset=1) self.spi_cs_n = Signal(reset=1)
self.spi_mosi = Signal() self.spi_mosi = Signal()
self.spi_miso = Signal() self.spi_miso = Signal()
self.spi_int_n = Signal(reset=1)
def get_fragment(self): ###
comb = []
sync = []
# Resychronisation # Resychronisation
spi_clk_d1 = Signal() clk_synchro = Synchronizer(i=self.spi_clk)
spi_clk_d2 = Signal() cs_n_synchro = Synchronizer(i=self.spi_cs_n)
spi_clk_d3 = Signal() mosi_synchro = Synchronizer(i=self.spi_mosi)
sync += [ self.specials += {clk_synchro, cs_n_synchro, mosi_synchro}
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)
]
# Decode # Decode
spi_clk_rising = Signal() spi_clk_rising = Signal()
spi_clk_falling = Signal() spi_clk_falling = Signal()
spi_cs_n_active = Signal() spi_cs_n_active = Signal()
spi_mosi_dat = Signal() spi_mosi_dat = Signal()
comb += [ self.specials += RisingEdge(i=clk_synchro.o, o=spi_clk_rising)
spi_clk_rising.eq(spi_clk_d2 & ~spi_clk_d3), self.specials += FallingEdge(i=clk_synchro.o, o=spi_clk_falling)
spi_clk_falling.eq(~spi_clk_d2 & spi_clk_d3),
spi_cs_n_active.eq(~spi_cs_n_d3), self.sync +=[
spi_mosi_dat.eq(spi_mosi_d3) spi_cs_n_active.eq(~cs_n_synchro.o),
spi_mosi_dat.eq(~mosi_synchro.o),
] ]
# #
# Spi --> Csr # Spi --> Csr
# #
spi_cnt = Signal(bits_for(self.a_width+self.max_burst*self.d_width)) spi_cnt = Signal(bits_for(self.a_w + self.burst_length*self.d_w))
spi_addr = Signal(self.a_width) spi_addr = Signal(self.a_w)
spi_w_dat = Signal(self.d_width) spi_w_dat = Signal(self.d_w)
spi_r_dat = Signal(self.d_width) spi_r_dat = Signal(self.d_w)
spi_we = Signal() spi_we = Signal()
spi_re = Signal() spi_re = Signal()
spi_we_re_done = Signal(reset = 1) spi_we_re_done = Signal(reset=1)
spi_miso_dat = Signal() spi_miso_dat = Signal()
# Re/We Signals Decoding # Re/We Signals Decoding
first_b = Signal() first_b = Signal()
last_b = Signal() last_b = Signal()
comb +=[ self.comb +=[
first_b.eq(spi_cnt[0:bits_for(self.d_width)-1] == 0), first_b.eq(spi_cnt[0:bits_for(self.d_w)-1] == 0),
last_b.eq(spi_cnt[0:bits_for(self.d_width)-1] == 2**(bits_for(self.d_width)-1)-1) last_b.eq(spi_cnt[0:bits_for(self.d_w)-1] == 2**(bits_for(self.d_w-1))-1)
] ]
sync +=[ self.sync +=[
If((spi_cnt >= (self.a_width + self.d_width)) & first_b, If((spi_cnt >= (self.a_w + self.d_w)) & first_b,
spi_we.eq(spi_addr[self.a_width-1] & ~spi_we_re_done), spi_we.eq(spi_addr[self.a_w-1] & ~spi_we_re_done),
spi_re.eq(~spi_addr[self.a_width-1] & ~spi_we_re_done), spi_re.eq(~spi_addr[self.a_w-1] & ~spi_we_re_done),
spi_we_re_done.eq(1) spi_we_re_done.eq(1)
).Elif((spi_cnt >= self.a_width) & first_b, ).Elif((spi_cnt >= self.a_w) & first_b,
spi_re.eq(~spi_addr[self.a_width-1] & ~spi_we_re_done), spi_re.eq(~spi_addr[self.a_w-1] & ~spi_we_re_done),
spi_we_re_done.eq(1) spi_we_re_done.eq(1)
).Else( ).Else(
spi_we.eq(0), spi_we.eq(0),
@ -101,21 +77,21 @@ class Spi2Csr :
] ]
# Spi Addr / Data Decoding # Spi Addr / Data Decoding
sync +=[ self.sync +=[
If(~spi_cs_n_active, If(~spi_cs_n_active,
spi_cnt.eq(0), spi_cnt.eq(0),
).Elif(spi_clk_rising, ).Elif(spi_clk_rising,
# addr # addr
If(spi_cnt < self.a_width, If(spi_cnt < self.a_w,
spi_addr.eq(Cat(spi_mosi_dat,spi_addr[:self.a_width-1])) spi_addr.eq(Cat(spi_mosi_dat,spi_addr[:self.a_w-1]))
).Elif((spi_cnt >= (self.a_width+self.d_width)) & last_b, ).Elif((spi_cnt >= (self.a_w+self.d_w)) & last_b,
spi_addr.eq(spi_addr+1) 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) spi_addr.eq(spi_addr+1)
), ),
# dat # dat
If(spi_cnt >= self.a_width, If(spi_cnt >= self.a_w,
spi_w_dat.eq(Cat(spi_mosi_dat,spi_w_dat[:self.d_width-1])) spi_w_dat.eq(Cat(spi_mosi_dat,spi_w_dat[:self.d_w-1]))
), ),
# spi_cnt # spi_cnt
@ -126,8 +102,8 @@ class Spi2Csr :
# #
# Csr --> Spi # Csr --> Spi
# #
spi_r_dat_shift = Signal(self.d_width) spi_r_dat_shift = Signal(self.d_w)
sync +=[ self.sync +=[
If(spi_re, If(spi_re,
spi_r_dat_shift.eq(spi_r_dat) spi_r_dat_shift.eq(spi_r_dat)
), ),
@ -135,16 +111,16 @@ class Spi2Csr :
If(~spi_cs_n_active, If(~spi_cs_n_active,
spi_miso_dat.eq(0) spi_miso_dat.eq(0)
).Elif(spi_clk_falling, ).Elif(spi_clk_falling,
spi_miso_dat.eq(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_width-1])) spi_r_dat_shift.eq(Cat(0,spi_r_dat_shift[:self.d_w-1]))
) )
] ]
# #
# Csr Interface # Csr Interface
# #
comb += [ self.comb += [
self.csr.adr.eq(spi_addr), self.csr.adr.eq(spi_addr),
self.csr.dat_w.eq(spi_w_dat), self.csr.dat_w.eq(spi_w_dat),
self.csr.we.eq(spi_we) self.csr.we.eq(spi_we)
@ -153,8 +129,7 @@ class Spi2Csr :
# #
# Spi Interface # Spi Interface
# #
comb += [ self.comb += [
spi_r_dat.eq(self.csr.dat_r), spi_r_dat.eq(self.csr.dat_r),
self.spi_miso.eq(spi_miso_dat) self.spi_miso.eq(spi_miso_dat)
] ]
return Fragment(comb=comb,sync=sync)

View File

@ -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)
)
]

View File

@ -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))
)
)
)
)
]

View File

@ -7,22 +7,20 @@ class MiIo:
# #
# Definition # Definition
# #
def __init__(self, address, width, mode = "IO", interface=None): def __init__(self, address, width, mode="IO", interface=None):
self.address = address self.address = address
self.width = width self.width = width
self.mode = mode self.mode = mode.upper()
self.interface = interface 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: if "I" in self.mode:
self.i = Signal(self.width) self.i = Signal(self.width)
self.ireg = description.RegisterField("i", self.width, READ_ONLY, WRITE_ONLY) self.ireg = description.RegisterField("i", self.width, READ_ONLY, WRITE_ONLY)
self.ireg.field.w.name_override = "inputs"
if "O" in self.mode: if "O" in self.mode:
self.o = Signal(self.width) self.o = Signal(self.width)
self.oreg = description.RegisterField("o", 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) self.bank = csrgen.Bank([self.oreg, self.ireg], address=self.address)
@ -30,18 +28,18 @@ class MiIo:
comb = [] comb = []
if "I" in self.mode: 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: 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() return Fragment(comb) + self.bank.get_fragment()
# #
#Driver #Driver
# #
def write(self, data): def write(self, data):
self.interface.write_n(self.address, data, self.width) self.interface.write(self.address, data, self.width)
def read(self): 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 return r