mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-21 21:49:15 +01:00
reset improvement
This commit is contained in:
parent
f669f730da
commit
6d460e83bd
@ -394,13 +394,13 @@ module mcu_top (
|
||||
|
||||
REG_USB_SCR: begin
|
||||
reg_rdata <= {
|
||||
2'd0,
|
||||
1'd0,
|
||||
usb_scb.fifo_flush_busy,
|
||||
usb_scb.pwrsav,
|
||||
usb_scb.reset_state,
|
||||
usb_scb.tx_count,
|
||||
usb_scb.rx_count,
|
||||
2'b00,
|
||||
usb_scb.reset_pending,
|
||||
3'b000,
|
||||
~fifo_bus.tx_full,
|
||||
~fifo_bus.rx_empty,
|
||||
1'b0
|
||||
@ -681,9 +681,10 @@ module mcu_top (
|
||||
mem_start <= 1'b0;
|
||||
mem_stop <= 1'b0;
|
||||
|
||||
usb_scb.write_buffer_flush <= 1'b0;
|
||||
usb_scb.reset_ack <= 1'b0;
|
||||
usb_scb.fifo_flush <= 1'b0;
|
||||
usb_scb.write_buffer_flush <= 1'b0;
|
||||
usb_scb.reset_on_ack <= 1'b0;
|
||||
usb_scb.reset_off_ack <= 1'b0;
|
||||
|
||||
usb_dma_scb.start <= 1'b0;
|
||||
usb_dma_scb.stop <= 1'b0;
|
||||
@ -770,11 +771,10 @@ module mcu_top (
|
||||
end
|
||||
|
||||
REG_USB_SCR: begin
|
||||
{
|
||||
usb_scb.write_buffer_flush,
|
||||
usb_scb.reset_ack,
|
||||
usb_scb.fifo_flush
|
||||
} <= {reg_wdata[5:4], reg_wdata[0]};
|
||||
usb_scb.write_buffer_flush <= reg_wdata[5];
|
||||
usb_scb.reset_off_ack <= reg_wdata[4];
|
||||
usb_scb.reset_on_ack <= reg_wdata[3];
|
||||
usb_scb.fifo_flush <= reg_wdata[0];
|
||||
end
|
||||
|
||||
REG_USB_DMA_ADDRESS: begin
|
||||
|
@ -1,34 +1,37 @@
|
||||
interface usb_scb ();
|
||||
|
||||
logic fifo_flush;
|
||||
logic reset_pending;
|
||||
logic reset_ack;
|
||||
logic fifo_flush_busy;
|
||||
logic write_buffer_flush;
|
||||
logic [10:0] rx_count;
|
||||
logic [10:0] tx_count;
|
||||
logic pwrsav;
|
||||
logic reset_state;
|
||||
logic reset_on_ack;
|
||||
logic reset_off_ack;
|
||||
|
||||
modport controller (
|
||||
output fifo_flush,
|
||||
input reset_pending,
|
||||
output reset_ack,
|
||||
input fifo_flush_busy,
|
||||
output write_buffer_flush,
|
||||
input rx_count,
|
||||
input tx_count,
|
||||
input pwrsav,
|
||||
input reset_state
|
||||
input reset_state,
|
||||
output reset_on_ack,
|
||||
output reset_off_ack
|
||||
);
|
||||
|
||||
modport usb (
|
||||
input fifo_flush,
|
||||
output reset_pending,
|
||||
input reset_ack,
|
||||
output fifo_flush_busy,
|
||||
input write_buffer_flush,
|
||||
output rx_count,
|
||||
output tx_count,
|
||||
output pwrsav,
|
||||
output reset_state
|
||||
output reset_state,
|
||||
input reset_on_ack,
|
||||
input reset_off_ack
|
||||
);
|
||||
|
||||
endinterface
|
||||
@ -59,9 +62,11 @@ module usb_ft1248 (
|
||||
logic tx_read;
|
||||
logic [7:0] tx_rdata;
|
||||
|
||||
logic fifo_flush;
|
||||
|
||||
fifo_8kb fifo_8kb_rx_inst (
|
||||
.clk(clk),
|
||||
.reset(reset || usb_scb.fifo_flush),
|
||||
.reset(reset || fifo_flush),
|
||||
|
||||
.empty(fifo_bus.rx_empty),
|
||||
.almost_empty(fifo_bus.rx_almost_empty),
|
||||
@ -78,7 +83,7 @@ module usb_ft1248 (
|
||||
|
||||
fifo_8kb fifo_8kb_tx_inst (
|
||||
.clk(clk),
|
||||
.reset(reset || usb_scb.fifo_flush),
|
||||
.reset(reset || fifo_flush),
|
||||
|
||||
.empty(tx_empty),
|
||||
.almost_empty(tx_almost_empty),
|
||||
@ -142,7 +147,6 @@ module usb_ft1248 (
|
||||
logic [3:0] phase;
|
||||
logic last_tx_failed;
|
||||
logic reset_reply;
|
||||
logic last_reset_status;
|
||||
logic [4:0] modem_status_counter;
|
||||
logic write_modem_status_pending;
|
||||
logic write_buffer_flush_pending;
|
||||
@ -152,7 +156,7 @@ module usb_ft1248 (
|
||||
cmd <= next_cmd;
|
||||
|
||||
usb_scb.pwrsav <= !ft_pwrsav;
|
||||
usb_scb.reset_state <= last_reset_status;
|
||||
fifo_flush <= 1'b0;
|
||||
|
||||
phase <= {phase[2:0], phase[3]};
|
||||
if (state == STATE_IDLE) begin
|
||||
@ -160,25 +164,38 @@ module usb_ft1248 (
|
||||
end
|
||||
|
||||
if (reset) begin
|
||||
usb_scb.fifo_flush_busy <= 1'b0;
|
||||
usb_scb.reset_state <= 1'b0;
|
||||
last_tx_failed <= 1'b0;
|
||||
usb_scb.reset_pending <= 1'b0;
|
||||
last_reset_status <= 1'b0;
|
||||
reset_reply <= 1'b0;
|
||||
modem_status_counter <= 5'd0;
|
||||
write_modem_status_pending <= 1'b0;
|
||||
write_modem_status_pending <= 1'b1;
|
||||
write_buffer_flush_pending <= 1'b0;
|
||||
end else begin
|
||||
if (usb_scb.reset_ack) begin
|
||||
usb_scb.reset_pending <= 1'b0;
|
||||
if (usb_scb.fifo_flush) begin
|
||||
usb_scb.fifo_flush_busy <= 1'b1;
|
||||
end
|
||||
|
||||
if (usb_scb.reset_on_ack) begin
|
||||
reset_reply <= 1'b1;
|
||||
write_modem_status_pending <= 1'b1;
|
||||
end
|
||||
|
||||
if (usb_scb.reset_off_ack) begin
|
||||
reset_reply <= 1'b0;
|
||||
write_modem_status_pending <= 1'b1;
|
||||
end
|
||||
|
||||
if (usb_scb.write_buffer_flush) begin
|
||||
write_buffer_flush_pending <= 1'b1;
|
||||
end
|
||||
|
||||
if (state == STATE_IDLE) begin
|
||||
modem_status_counter <= modem_status_counter + 1'd1;
|
||||
if (usb_scb.fifo_flush_busy) begin
|
||||
usb_scb.fifo_flush_busy <= 1'b0;
|
||||
fifo_flush <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
if ((state == STATE_DATA) && (cmd == CMD_WRITE) && phase[3]) begin
|
||||
@ -187,14 +204,7 @@ module usb_ft1248 (
|
||||
|
||||
if (!ft_miso && (state == STATE_DATA) && phase[3]) begin
|
||||
if (cmd == CMD_READ_MODEM_STATUS) begin
|
||||
last_reset_status <= ft_miosi_in[0];
|
||||
if (!last_reset_status && ft_miosi_in[0]) begin
|
||||
usb_scb.reset_pending <= 1'b1;
|
||||
end
|
||||
if (last_reset_status && !ft_miosi_in[0]) begin
|
||||
reset_reply <= 1'b0;
|
||||
write_modem_status_pending <= 1'b1;
|
||||
end
|
||||
usb_scb.reset_state <= ft_miosi_in[0];
|
||||
end
|
||||
if (cmd == CMD_WRITE_MODEM_STATUS) begin
|
||||
write_modem_status_pending <= 1'b0;
|
||||
@ -283,7 +293,7 @@ module usb_ft1248 (
|
||||
end else begin
|
||||
case (state)
|
||||
STATE_IDLE: begin
|
||||
if (ft_pwrsav) begin
|
||||
if (ft_pwrsav && !(usb_scb.fifo_flush || usb_scb.fifo_flush_busy || fifo_flush)) begin
|
||||
if (write_modem_status_pending) begin
|
||||
next_state = STATE_SELECT;
|
||||
next_cmd = CMD_WRITE_MODEM_STATUS;
|
||||
|
@ -79,8 +79,8 @@ typedef enum {
|
||||
#define USB_SCR_FIFO_FLUSH (1 << 0)
|
||||
#define USB_SCR_RXNE (1 << 1)
|
||||
#define USB_SCR_TXE (1 << 2)
|
||||
#define USB_SCR_RESET_PENDING (1 << 3)
|
||||
#define USB_SCR_RESET_ACK (1 << 4)
|
||||
#define USB_SCR_RESET_ON_ACK (1 << 3)
|
||||
#define USB_SCR_RESET_OFF_ACK (1 << 4)
|
||||
#define USB_SCR_WRITE_FLUSH (1 << 5)
|
||||
#define USB_SCR_RX_COUNT_BIT (6)
|
||||
#define USB_SCR_RX_COUNT_MASK (0x7FF << USB_SCR_RX_COUNT_BIT)
|
||||
@ -88,6 +88,7 @@ typedef enum {
|
||||
#define USB_SCR_TX_COUNT_MASK (0x7FF << USB_SCR_TX_COUNT_BIT)
|
||||
#define USB_SCR_RESET_STATE (1 << 28)
|
||||
#define USB_SCR_PWRSAV (1 << 29)
|
||||
#define USB_SCR_FIFO_FLUSH_BUSY (1 << 30)
|
||||
|
||||
#define DMA_SCR_START (1 << 0)
|
||||
#define DMA_SCR_STOP (1 << 1)
|
||||
|
@ -43,6 +43,8 @@ enum tx_state {
|
||||
|
||||
|
||||
struct process {
|
||||
bool last_reset_state;
|
||||
|
||||
enum rx_state rx_state;
|
||||
uint8_t rx_counter;
|
||||
uint8_t rx_cmd;
|
||||
@ -80,10 +82,6 @@ static const uint32_t ERR_TOKEN = (0x45525200UL);
|
||||
static const uint32_t PKT_TOKEN = (0x504B5400UL);
|
||||
|
||||
|
||||
static bool usb_dma_ready (void) {
|
||||
return !((fpga_reg_get(REG_USB_DMA_SCR) & DMA_SCR_BUSY));
|
||||
}
|
||||
|
||||
static bool usb_rx_byte (uint8_t *data) {
|
||||
if (fpga_usb_status_get() & USB_STATUS_RXNE) {
|
||||
*data = fpga_usb_pop();
|
||||
@ -149,6 +147,59 @@ static bool usb_rx_cmd (uint8_t *cmd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void usb_reset (void) {
|
||||
fpga_reg_set(REG_USB_DMA_SCR, DMA_SCR_STOP);
|
||||
while (fpga_reg_get(REG_USB_DMA_SCR) & DMA_SCR_BUSY);
|
||||
fpga_reg_set(REG_USB_SCR, USB_SCR_FIFO_FLUSH);
|
||||
while (fpga_reg_get(REG_USB_SCR) & USB_SCR_FIFO_FLUSH_BUSY);
|
||||
|
||||
p.rx_state = RX_STATE_IDLE;
|
||||
p.tx_state = TX_STATE_IDLE;
|
||||
|
||||
p.response_pending = false;
|
||||
p.packet_pending = false;
|
||||
|
||||
p.read_ready = true;
|
||||
p.read_length = 0;
|
||||
p.read_address = 0;
|
||||
|
||||
usb_rx_word_counter = 0;
|
||||
usb_rx_word_buffer = 0;
|
||||
usb_tx_word_counter = 0;
|
||||
usb_rx_cmd_counter = 0;
|
||||
}
|
||||
|
||||
static void usb_flush_packet (void) {
|
||||
if (p.packet_pending && p.packet_info.done_callback) {
|
||||
p.packet_pending = false;
|
||||
p.packet_info.done_callback();
|
||||
}
|
||||
|
||||
if (p.tx_state != TX_STATE_IDLE && p.tx_info.done_callback) {
|
||||
p.tx_info.done_callback();
|
||||
}
|
||||
}
|
||||
|
||||
static bool usb_is_active (void) {
|
||||
uint32_t scr = fpga_reg_get(REG_USB_SCR);
|
||||
bool reset_state = (scr & USB_SCR_RESET_STATE);
|
||||
if (p.last_reset_state != reset_state) {
|
||||
p.last_reset_state = reset_state;
|
||||
if (reset_state) {
|
||||
usb_flush_packet();
|
||||
usb_reset();
|
||||
fpga_reg_set(REG_USB_SCR, USB_SCR_WRITE_FLUSH);
|
||||
}
|
||||
fpga_reg_set(REG_USB_SCR, reset_state ? USB_SCR_RESET_ON_ACK : USB_SCR_RESET_OFF_ACK);
|
||||
return false;
|
||||
}
|
||||
return !(reset_state || (scr & USB_SCR_PWRSAV));
|
||||
}
|
||||
|
||||
static bool usb_dma_ready (void) {
|
||||
return !((fpga_reg_get(REG_USB_DMA_SCR) & DMA_SCR_BUSY));
|
||||
}
|
||||
|
||||
static bool usb_validate_address_length (uint32_t address, uint32_t length, bool exclude_bootloader) {
|
||||
if ((address >= MEMORY_LENGTH) || (length > MEMORY_LENGTH)) {
|
||||
return true;
|
||||
@ -556,42 +607,16 @@ void usb_get_read_info (uint32_t *args) {
|
||||
|
||||
|
||||
void usb_init (void) {
|
||||
fpga_reg_set(REG_USB_DMA_SCR, DMA_SCR_STOP);
|
||||
fpga_reg_set(REG_USB_SCR, USB_SCR_FIFO_FLUSH);
|
||||
|
||||
p.rx_state = RX_STATE_IDLE;
|
||||
p.tx_state = TX_STATE_IDLE;
|
||||
|
||||
p.response_pending = false;
|
||||
p.packet_pending = false;
|
||||
|
||||
p.read_ready = true;
|
||||
p.read_length = 0;
|
||||
p.read_address = 0;
|
||||
|
||||
usb_rx_word_counter = 0;
|
||||
usb_rx_word_buffer = 0;
|
||||
usb_tx_word_counter = 0;
|
||||
usb_rx_cmd_counter = 0;
|
||||
p.last_reset_state = false;
|
||||
usb_reset();
|
||||
}
|
||||
|
||||
|
||||
void usb_process (void) {
|
||||
uint32_t scr = fpga_reg_get(REG_USB_SCR);
|
||||
if (scr & (USB_SCR_PWRSAV | USB_SCR_RESET_STATE | USB_SCR_RESET_PENDING)) {
|
||||
if (p.packet_pending && p.packet_info.done_callback) {
|
||||
p.packet_pending = false;
|
||||
p.packet_info.done_callback();
|
||||
}
|
||||
if (scr & USB_SCR_RESET_PENDING) {
|
||||
if (p.tx_state != TX_STATE_IDLE && p.tx_info.done_callback) {
|
||||
p.tx_info.done_callback();
|
||||
}
|
||||
usb_init();
|
||||
fpga_reg_set(REG_USB_SCR, USB_SCR_RESET_ACK);
|
||||
}
|
||||
} else {
|
||||
if (usb_is_active()) {
|
||||
usb_rx_process();
|
||||
usb_tx_process();
|
||||
} else {
|
||||
usb_flush_packet();
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ struct Wrapper {
|
||||
context: *mut libftdi1_sys::ftdi_context,
|
||||
unclog_buffer: std::collections::VecDeque<u8>,
|
||||
write_buffer: Vec<u8>,
|
||||
read_timeout: std::time::Duration,
|
||||
write_timeout: std::time::Duration,
|
||||
read_chunksize: usize,
|
||||
write_chunksize: usize,
|
||||
@ -49,6 +50,7 @@ impl Wrapper {
|
||||
context,
|
||||
unclog_buffer: std::collections::VecDeque::new(),
|
||||
write_buffer: vec![],
|
||||
read_timeout: Wrapper::DEFAULT_RW_TIMEOUT,
|
||||
write_timeout: Wrapper::DEFAULT_RW_TIMEOUT,
|
||||
read_chunksize: Wrapper::DEFAULT_CHUNKSIZE,
|
||||
write_chunksize: Wrapper::DEFAULT_CHUNKSIZE,
|
||||
@ -158,6 +160,7 @@ impl Wrapper {
|
||||
(*self.context).usb_write_timeout = i32::try_from(write_timeout.as_millis())
|
||||
.map_err(|_| std::io::ErrorKind::InvalidInput)?;
|
||||
}
|
||||
self.read_timeout = read_timeout;
|
||||
self.write_timeout = write_timeout;
|
||||
Ok(())
|
||||
}
|
||||
@ -221,6 +224,17 @@ impl Wrapper {
|
||||
}
|
||||
}
|
||||
|
||||
fn usb_reset(&mut self) -> std::io::Result<()> {
|
||||
match unsafe { libftdi1_sys::ftdi_usb_reset(self.context) } {
|
||||
0 => Ok(()),
|
||||
-1 => Err(std::io::ErrorKind::BrokenPipe.into()),
|
||||
-2 => Err(std::io::ErrorKind::NotConnected.into()),
|
||||
result => Err(std::io::Error::other(format!(
|
||||
"Unexpected response from ftdi_usb_reset: {result}"
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_latency_timer(&mut self, latency: Option<std::time::Duration>) -> std::io::Result<()> {
|
||||
let latency = u8::try_from(latency.unwrap_or(Wrapper::DEFAULT_POLL_TIMEOUT).as_millis())
|
||||
.map_err(|_| std::io::ErrorKind::InvalidInput)?;
|
||||
@ -300,14 +314,33 @@ impl Wrapper {
|
||||
}
|
||||
}
|
||||
|
||||
fn tcioflush(&mut self) -> std::io::Result<()> {
|
||||
match unsafe { libftdi1_sys::ftdi_tcioflush(self.context) } {
|
||||
fn tciflush(&mut self) -> std::io::Result<()> {
|
||||
let timeout = std::time::Instant::now();
|
||||
loop {
|
||||
match self.read(&mut vec![0u8; self.read_chunksize]) {
|
||||
Ok(_) => {}
|
||||
Err(error) => match error.kind() {
|
||||
std::io::ErrorKind::Interrupted | std::io::ErrorKind::WouldBlock => {
|
||||
return Ok(());
|
||||
}
|
||||
_ => return Err(error),
|
||||
},
|
||||
};
|
||||
if timeout.elapsed() > self.read_timeout {
|
||||
return Err(std::io::ErrorKind::TimedOut.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tcoflush(&mut self) -> std::io::Result<()> {
|
||||
self.write_buffer.clear();
|
||||
match unsafe { libftdi1_sys::ftdi_tcoflush(self.context) } {
|
||||
0 => Ok(()),
|
||||
-1 => Err(std::io::ErrorKind::BrokenPipe.into()),
|
||||
-2 => Err(std::io::ErrorKind::BrokenPipe.into()),
|
||||
-3 => Err(std::io::ErrorKind::NotConnected.into()),
|
||||
result => Err(std::io::Error::other(format!(
|
||||
"Unexpected response from ftdi_tcioflush: {result}"
|
||||
"Unexpected response from ftdi_tcoflush: {result}"
|
||||
))),
|
||||
}
|
||||
}
|
||||
@ -443,6 +476,8 @@ impl FtdiDevice {
|
||||
|
||||
wrapper.usb_open_string(description)?;
|
||||
|
||||
wrapper.usb_reset()?;
|
||||
|
||||
wrapper.set_latency_timer(poll_timeout)?;
|
||||
|
||||
Ok(FtdiDevice { wrapper })
|
||||
@ -456,8 +491,12 @@ impl FtdiDevice {
|
||||
Ok(self.wrapper.poll_modem_status()?.dsr)
|
||||
}
|
||||
|
||||
pub fn discard_buffers(&mut self) -> std::io::Result<()> {
|
||||
self.wrapper.tcioflush()
|
||||
pub fn discard_input(&mut self) -> std::io::Result<()> {
|
||||
self.wrapper.tciflush()
|
||||
}
|
||||
|
||||
pub fn discard_output(&mut self) -> std::io::Result<()> {
|
||||
self.wrapper.tcoflush()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
use super::{error::Error, ftdi::FtdiDevice};
|
||||
use serial2::SerialPort;
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
fmt::Display,
|
||||
@ -197,7 +196,7 @@ pub trait Backend {
|
||||
}
|
||||
|
||||
pub struct SerialBackend {
|
||||
device: SerialPort,
|
||||
device: serial2::SerialPort,
|
||||
}
|
||||
|
||||
impl Backend for SerialBackend {
|
||||
@ -250,7 +249,7 @@ impl Backend for SerialBackend {
|
||||
}
|
||||
|
||||
fn new_serial_backend(port: &str) -> std::io::Result<SerialBackend> {
|
||||
let mut serial = SerialPort::open(port, 115_200)?;
|
||||
let mut serial = serial2::SerialPort::open(port, 115_200)?;
|
||||
serial.set_read_timeout(POLL_TIMEOUT)?;
|
||||
serial.set_write_timeout(WRITE_TIMEOUT)?;
|
||||
Ok(SerialBackend { device: serial })
|
||||
@ -274,10 +273,11 @@ impl Backend for FtdiBackend {
|
||||
}
|
||||
|
||||
fn reset(&mut self) -> std::io::Result<()> {
|
||||
self.device.set_dtr(true)?;
|
||||
self.device.discard_output()?;
|
||||
|
||||
let timeout = Instant::now();
|
||||
self.device.set_dtr(true)?;
|
||||
loop {
|
||||
self.device.discard_buffers()?;
|
||||
if self.device.read_dsr()? {
|
||||
break;
|
||||
}
|
||||
@ -289,10 +289,10 @@ impl Backend for FtdiBackend {
|
||||
}
|
||||
}
|
||||
|
||||
self.purge_incoming_data()?;
|
||||
self.device.discard_input()?;
|
||||
|
||||
self.device.set_dtr(false)?;
|
||||
let timeout = Instant::now();
|
||||
self.device.set_dtr(false)?;
|
||||
loop {
|
||||
if !self.device.read_dsr()? {
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user