soc/cores/hyperbus: Shorten reg signals and use common done for read/write register accesses.
This commit is contained in:
parent
19f47aa317
commit
2dd7e3b9b3
|
@ -164,13 +164,12 @@ class HyperRAM(LiteXModule):
|
||||||
self.conf_rst = Signal()
|
self.conf_rst = Signal()
|
||||||
self.conf_latency = Signal(8, reset=latency)
|
self.conf_latency = Signal(8, reset=latency)
|
||||||
self.stat_latency_mode = Signal(reset={"fixed": 0, "variable": 1}[latency_mode])
|
self.stat_latency_mode = Signal(reset={"fixed": 0, "variable": 1}[latency_mode])
|
||||||
self.reg_write = Signal()
|
self.reg_wr = Signal()
|
||||||
self.reg_read = Signal()
|
self.reg_rd = Signal()
|
||||||
self.reg_addr = Signal(2)
|
self.reg_addr = Signal(2)
|
||||||
self.reg_write_done = Signal()
|
self.reg_done = Signal()
|
||||||
self.reg_read_done = Signal()
|
self.reg_wr_data = Signal(16)
|
||||||
self.reg_write_data = Signal(16)
|
self.reg_rd_data = Signal(16)
|
||||||
self.reg_read_data = Signal(16)
|
|
||||||
if with_csr:
|
if with_csr:
|
||||||
self.add_csr(default_latency=latency)
|
self.add_csr(default_latency=latency)
|
||||||
|
|
||||||
|
@ -189,8 +188,6 @@ class HyperRAM(LiteXModule):
|
||||||
# Burst Timer ------------------------------------------------------------------------------
|
# Burst Timer ------------------------------------------------------------------------------
|
||||||
self.burst_timer = burst_timer = WaitTimer(sys_clk_freq * self.tCSM)
|
self.burst_timer = burst_timer = WaitTimer(sys_clk_freq * self.tCSM)
|
||||||
|
|
||||||
# Clk Generation ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# Data Shift-In Register -------------------------------------------------------------------
|
# Data Shift-In Register -------------------------------------------------------------------
|
||||||
self.comb += [
|
self.comb += [
|
||||||
# Command/Address: On 8-bit, so 8-bit shift and no input.
|
# Command/Address: On 8-bit, so 8-bit shift and no input.
|
||||||
|
@ -223,32 +220,31 @@ class HyperRAM(LiteXModule):
|
||||||
]
|
]
|
||||||
|
|
||||||
# Register Access/Buffer -------------------------------------------------------------------
|
# Register Access/Buffer -------------------------------------------------------------------
|
||||||
reg_write_req = Signal()
|
reg_wr_req = Signal()
|
||||||
reg_read_req = Signal()
|
reg_rd_req = Signal()
|
||||||
self.reg_buf = reg_buf = stream.SyncFIFO(
|
self.reg_buf = reg_buf = stream.SyncFIFO(
|
||||||
layout = [("write", 1), ("read", 1), ("addr", 4), ("data", 16)],
|
layout = [("write", 1), ("read", 1), ("addr", 4), ("data", 16)],
|
||||||
depth = 4,
|
depth = 4,
|
||||||
)
|
)
|
||||||
reg_ep = reg_buf.source
|
reg_ep = reg_buf.source
|
||||||
self.comb += [
|
self.comb += [
|
||||||
reg_buf.sink.valid.eq(self.reg_write | self.reg_read),
|
reg_buf.sink.valid.eq(self.reg_wr | self.reg_rd),
|
||||||
reg_buf.sink.write.eq(self.reg_write),
|
reg_buf.sink.write.eq(self.reg_wr),
|
||||||
reg_buf.sink.read.eq(self.reg_read),
|
reg_buf.sink.read.eq(self.reg_rd),
|
||||||
reg_buf.sink.addr.eq(self.reg_addr),
|
reg_buf.sink.addr.eq(self.reg_addr),
|
||||||
reg_buf.sink.data.eq(self.reg_write_data),
|
reg_buf.sink.data.eq(self.reg_wr_data),
|
||||||
reg_write_req.eq(reg_ep.valid & reg_ep.write),
|
reg_wr_req.eq(reg_ep.valid & reg_ep.write),
|
||||||
reg_read_req.eq( reg_ep.valid & reg_ep.read),
|
reg_rd_req.eq( reg_ep.valid & reg_ep.read),
|
||||||
]
|
]
|
||||||
self.sync += If(reg_buf.sink.valid,
|
self.sync += If(reg_buf.sink.valid,
|
||||||
self.reg_write_done.eq(0),
|
self.reg_done.eq(0),
|
||||||
self.reg_read_done.eq(0),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Command generation -----------------------------------------------------------------------
|
# Command generation -----------------------------------------------------------------------
|
||||||
ashift = {8:1, 16:0}[data_width]
|
ashift = {8:1, 16:0}[data_width]
|
||||||
self.comb += [
|
self.comb += [
|
||||||
# Register Command Generation.
|
# Register Command Generation.
|
||||||
If(reg_write_req | reg_read_req,
|
If(reg_wr_req | reg_rd_req,
|
||||||
ca[47].eq(reg_ep.read), # R/W#
|
ca[47].eq(reg_ep.read), # R/W#
|
||||||
ca[46].eq(1), # Register Space.
|
ca[46].eq(1), # Register Space.
|
||||||
ca[45].eq(1), # Burst Type (Linear)
|
ca[45].eq(1), # Burst Type (Linear)
|
||||||
|
@ -290,7 +286,7 @@ class HyperRAM(LiteXModule):
|
||||||
self.fsm = fsm = FSM(reset_state="IDLE")
|
self.fsm = fsm = FSM(reset_state="IDLE")
|
||||||
fsm.act("IDLE",
|
fsm.act("IDLE",
|
||||||
NextValue(first, 1),
|
NextValue(first, 1),
|
||||||
If((bus.cyc & bus.stb) | reg_write_req | reg_read_req,
|
If((bus.cyc & bus.stb) | reg_wr_req | reg_rd_req,
|
||||||
sr_load.eq(1),
|
sr_load.eq(1),
|
||||||
sr_load_value.eq(ca),
|
sr_load_value.eq(ca),
|
||||||
NextState("SEND-COMMAND-ADDRESS")
|
NextState("SEND-COMMAND-ADDRESS")
|
||||||
|
@ -302,9 +298,9 @@ class HyperRAM(LiteXModule):
|
||||||
phy.dq_oe.eq(1),
|
phy.dq_oe.eq(1),
|
||||||
# Wait for 6*2 cycles.
|
# Wait for 6*2 cycles.
|
||||||
If(cycles == (6*2 - 1),
|
If(cycles == (6*2 - 1),
|
||||||
If(reg_write_req,
|
If(reg_wr_req,
|
||||||
sr_load.eq(1),
|
sr_load.eq(1),
|
||||||
sr_load_value.eq(Cat(Signal(40), self.reg_write_data[8:])),
|
sr_load_value.eq(Cat(Signal(40), self.reg_wr_data[8:])),
|
||||||
NextState("REG-WRITE-0")
|
NextState("REG-WRITE-0")
|
||||||
).Else(
|
).Else(
|
||||||
# Sample RWDS to know if 1X/2X Latency should be used (Refresh).
|
# Sample RWDS to know if 1X/2X Latency should be used (Refresh).
|
||||||
|
@ -320,7 +316,7 @@ class HyperRAM(LiteXModule):
|
||||||
# Wait for 2 cycles.
|
# Wait for 2 cycles.
|
||||||
If(cycles == (2 - 1),
|
If(cycles == (2 - 1),
|
||||||
sr_load.eq(1),
|
sr_load.eq(1),
|
||||||
sr_load_value.eq(Cat(Signal(40), self.reg_write_data[:8])),
|
sr_load_value.eq(Cat(Signal(40), self.reg_wr_data[:8])),
|
||||||
NextState("REG-WRITE-1")
|
NextState("REG-WRITE-1")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -331,7 +327,7 @@ class HyperRAM(LiteXModule):
|
||||||
# Wait for 2 cycles.
|
# Wait for 2 cycles.
|
||||||
If(cycles == (2 - 1),
|
If(cycles == (2 - 1),
|
||||||
reg_ep.ready.eq(1),
|
reg_ep.ready.eq(1),
|
||||||
NextValue(self.reg_write_done, 1),
|
NextValue(self.reg_done, 1),
|
||||||
NextState("IDLE")
|
NextState("IDLE")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -342,7 +338,7 @@ class HyperRAM(LiteXModule):
|
||||||
# Latch Bus.
|
# Latch Bus.
|
||||||
bus_latch.eq(1),
|
bus_latch.eq(1),
|
||||||
# Early Write Ack (to allow bursting).
|
# Early Write Ack (to allow bursting).
|
||||||
If(~reg_read_req,
|
If(~reg_rd_req,
|
||||||
bus.ack.eq(bus.we),
|
bus.ack.eq(bus.we),
|
||||||
),
|
),
|
||||||
NextState("READ-WRITE-DATA0")
|
NextState("READ-WRITE-DATA0")
|
||||||
|
@ -353,7 +349,7 @@ class HyperRAM(LiteXModule):
|
||||||
fsm.act(f"READ-WRITE-DATA{n}",
|
fsm.act(f"READ-WRITE-DATA{n}",
|
||||||
# Enable Burst Timer.
|
# Enable Burst Timer.
|
||||||
burst_timer.wait.eq(1),
|
burst_timer.wait.eq(1),
|
||||||
ca_oe.eq(reg_read_req),
|
ca_oe.eq(reg_rd_req),
|
||||||
# Send Data on DQ/RWDS (for write).
|
# Send Data on DQ/RWDS (for write).
|
||||||
If(bus_we,
|
If(bus_we,
|
||||||
phy.dq_oe.eq(1),
|
phy.dq_oe.eq(1),
|
||||||
|
@ -368,7 +364,7 @@ class HyperRAM(LiteXModule):
|
||||||
If(n == (states - 1),
|
If(n == (states - 1),
|
||||||
NextValue(first, 0),
|
NextValue(first, 0),
|
||||||
# Continue burst when a consecutive access is ready.
|
# Continue burst when a consecutive access is ready.
|
||||||
If(~reg_read_req & bus.stb & bus.cyc & (bus.we == bus_we) & (bus.adr == (bus_adr + 1)) & (~burst_timer.done),
|
If(~reg_rd_req & bus.stb & bus.cyc & (bus.we == bus_we) & (bus.adr == (bus_adr + 1)) & (~burst_timer.done),
|
||||||
# Latch Bus.
|
# Latch Bus.
|
||||||
bus_latch.eq(1),
|
bus_latch.eq(1),
|
||||||
# Early Write Ack (to allow bursting).
|
# Early Write Ack (to allow bursting).
|
||||||
|
@ -380,10 +376,10 @@ class HyperRAM(LiteXModule):
|
||||||
),
|
),
|
||||||
# Read Ack (when dat_r ready).
|
# Read Ack (when dat_r ready).
|
||||||
If((n == 0) & ~first,
|
If((n == 0) & ~first,
|
||||||
If(reg_read_req,
|
If(reg_rd_req,
|
||||||
reg_ep.ready.eq(1),
|
reg_ep.ready.eq(1),
|
||||||
NextValue(self.reg_read_done, 1),
|
NextValue(self.reg_done, 1),
|
||||||
NextValue(self.reg_read_data, bus.dat_r),
|
NextValue(self.reg_rd_data, bus.dat_r),
|
||||||
NextState("IDLE"),
|
NextState("IDLE"),
|
||||||
).Else(
|
).Else(
|
||||||
bus.ack.eq(~bus_we),
|
bus.ack.eq(~bus_we),
|
||||||
|
@ -452,23 +448,21 @@ class HyperRAM(LiteXModule):
|
||||||
]),
|
]),
|
||||||
])
|
])
|
||||||
self.reg_status = CSRStatus(fields=[
|
self.reg_status = CSRStatus(fields=[
|
||||||
CSRField("write_done", offset=0, size=1, description="Register Write Done."),
|
CSRField("done", offset=0, size=1, description="Register Access Done."),
|
||||||
CSRField("read_done", offset=1, size=1, description="Register Read Done."),
|
|
||||||
])
|
])
|
||||||
self.reg_wdata = CSRStorage(16, description="Register Write Data.")
|
self.reg_wdata = CSRStorage(16, description="Register Write Data.")
|
||||||
self.reg_rdata = CSRStatus( 16, description="Register Read Data.")
|
self.reg_rdata = CSRStatus( 16, description="Register Read Data.")
|
||||||
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
# Control.
|
# Control.
|
||||||
self.reg_write.eq(self.reg_control.fields.write),
|
self.reg_wr.eq(self.reg_control.fields.write),
|
||||||
self.reg_read.eq( self.reg_control.fields.read),
|
self.reg_rd.eq( self.reg_control.fields.read),
|
||||||
self.reg_addr.eq( self.reg_control.fields.addr),
|
self.reg_addr.eq( self.reg_control.fields.addr),
|
||||||
|
|
||||||
# Status.
|
# Status.
|
||||||
self.reg_status.fields.write_done.eq(self.reg_write_done),
|
self.reg_status.fields.done.eq(self.reg_done),
|
||||||
self.reg_status.fields.read_done.eq( self.reg_read_done),
|
|
||||||
|
|
||||||
# Data.
|
# Data.
|
||||||
self.reg_write_data.eq(self.reg_wdata.storage),
|
self.reg_wr_data.eq(self.reg_wdata.storage),
|
||||||
self.reg_rdata.status.eq(self.reg_read_data),
|
self.reg_rdata.status.eq(self.reg_rd_data),
|
||||||
]
|
]
|
||||||
|
|
|
@ -18,7 +18,7 @@ static void hyperram_write_reg(uint16_t reg_addr, uint16_t data) {
|
||||||
reg_addr << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET
|
reg_addr << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET
|
||||||
);
|
);
|
||||||
/* Wait for write to complete */
|
/* Wait for write to complete */
|
||||||
while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_WRITE_DONE_OFFSET)) == 0);
|
while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_DONE_OFFSET)) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t hyperram_read_reg(uint16_t reg_addr) {
|
static uint16_t hyperram_read_reg(uint16_t reg_addr) {
|
||||||
|
@ -29,7 +29,7 @@ static uint16_t hyperram_read_reg(uint16_t reg_addr) {
|
||||||
reg_addr << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET
|
reg_addr << CSR_HYPERRAM_REG_CONTROL_ADDR_OFFSET
|
||||||
);
|
);
|
||||||
/* Wait for read to complete */
|
/* Wait for read to complete */
|
||||||
while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_READ_DONE_OFFSET)) == 0);
|
while ((hyperram_reg_status_read() & (1 << CSR_HYPERRAM_REG_STATUS_DONE_OFFSET)) == 0);
|
||||||
return hyperram_reg_rdata_read();
|
return hyperram_reg_rdata_read();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -277,11 +277,11 @@ class TestHyperBus(unittest.TestCase):
|
||||||
def test_hyperram_reg_write(self):
|
def test_hyperram_reg_write(self):
|
||||||
def fpga_gen(dut):
|
def fpga_gen(dut):
|
||||||
yield dut.reg_addr.eq(2)
|
yield dut.reg_addr.eq(2)
|
||||||
yield dut.reg_write_data.eq(0x1234)
|
yield dut.reg_wr_data.eq(0x1234)
|
||||||
yield
|
yield
|
||||||
yield dut.reg_write.eq(1)
|
yield dut.reg_wr.eq(1)
|
||||||
yield
|
yield
|
||||||
yield dut.reg_write.eq(0)
|
yield dut.reg_wr.eq(0)
|
||||||
for i in range(128):
|
for i in range(128):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue