mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-22 22:19:14 +01:00
almost working
This commit is contained in:
parent
97b7291001
commit
5524487f80
@ -301,5 +301,6 @@ set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
|
|||||||
# end ENTITY(SummerCart64)
|
# end ENTITY(SummerCart64)
|
||||||
# ------------------------
|
# ------------------------
|
||||||
set_global_assignment -name QIP_FILE rtl/intel/gpio/intel_gpio_ddro.qip
|
set_global_assignment -name QIP_FILE rtl/intel/gpio/intel_gpio_ddro.qip
|
||||||
|
|
||||||
set_global_assignment -name SLD_FILE db/stp_auto_stripped.stp
|
set_global_assignment -name SLD_FILE db/stp_auto_stripped.stp
|
||||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
@ -7,7 +7,7 @@ volatile int counter = 0;
|
|||||||
|
|
||||||
void print (const char *text) {
|
void print (const char *text) {
|
||||||
while (*text != '\0') {
|
while (*text != '\0') {
|
||||||
while (!(UART_SR & UART_SR_TXE));
|
while (!(UART_SCR & UART_SCR_TXE));
|
||||||
UART_DR = *text++;
|
UART_DR = *text++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,38 +50,147 @@ void print_nice_date(uint8_t *date) {
|
|||||||
print_02hex(date[0]);
|
print_02hex(date[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char CMD[3] = {'C', 'M', 'D'};
|
||||||
|
const char CMD_R = 'R';
|
||||||
|
const char CMD_W = 'W';
|
||||||
|
|
||||||
|
const char CMP[3] = {'C', 'M', 'P'};
|
||||||
|
|
||||||
__NAKED__ int main (void) {
|
__NAKED__ int main (void) {
|
||||||
uint8_t rtc_data[7];
|
uint8_t data;
|
||||||
uint8_t rtc_new_data[7];
|
uint8_t cmd = '-';
|
||||||
int index = 0;
|
uint32_t arg1, arg2;
|
||||||
|
char tmp[2];
|
||||||
|
|
||||||
|
tmp[1] = 0;
|
||||||
|
|
||||||
GPIO_OE = (1 << 0);
|
GPIO_OE = (1 << 0);
|
||||||
GPIO_O = (1 << 0);
|
GPIO_O = (1 << 0);
|
||||||
|
|
||||||
rtc_init();
|
DMA_SCR = DMA_SCR_STOP;
|
||||||
|
USB_SCR = USB_SCR_FLUSH_TX | USB_SCR_FLUSH_TX;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
GPIO_O = (1 << 0);
|
arg1 = 0;
|
||||||
|
arg2 = 0;
|
||||||
|
|
||||||
print("\033[2J\033[H\r\n --- Hello --- \r\n\r\n");
|
print("\r\nLoop start\r\n");
|
||||||
print(" RTC Data:\r\n\r\n ");
|
|
||||||
|
|
||||||
rtc_get_time(rtc_data);
|
for (int i = 0; i < 4; i++) {
|
||||||
|
while (!(USB_SCR & USB_SCR_RXNE));
|
||||||
print_nice_date(rtc_data);
|
data = USB_DR;
|
||||||
|
if (i < 3 && data != CMD[i]) {
|
||||||
print("\r\n");
|
i = 0;
|
||||||
GPIO_O = 0x00;
|
print("Wrong data ");
|
||||||
|
print_02hex(data);
|
||||||
while (counter++ < 0x0003FFFF);
|
print("\r\n");
|
||||||
counter = 0;
|
} else {
|
||||||
|
cmd = data;
|
||||||
if (USB_SR & USB_SR_RXNE) {
|
|
||||||
rtc_new_data[index++] = USB_DR;
|
|
||||||
if (index == 7) {
|
|
||||||
index = 0;
|
|
||||||
rtc_set_time(rtc_new_data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print("Received CMD");
|
||||||
|
tmp[0] = cmd;
|
||||||
|
print(tmp);
|
||||||
|
print("\r\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
while (!(USB_SCR & USB_SCR_RXNE));
|
||||||
|
arg1 = (arg1 << 8) | USB_DR;
|
||||||
|
}
|
||||||
|
|
||||||
|
print("Received ARG_1 0x");
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
print_02hex((uint8_t) (arg1 >> ((3 - i) * 8)));
|
||||||
|
}
|
||||||
|
print("\r\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
while (!(USB_SCR & USB_SCR_RXNE));
|
||||||
|
arg2 = (arg2 << 8) | USB_DR;
|
||||||
|
}
|
||||||
|
|
||||||
|
print("Received ARG_2 0x");
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
print_02hex((uint8_t) (arg2 >> ((3 - i) * 8)));
|
||||||
|
}
|
||||||
|
print("\r\n");
|
||||||
|
|
||||||
|
DMA_MADDR = arg1;
|
||||||
|
DMA_ID_LEN = arg2;
|
||||||
|
DMA_SCR = (cmd == CMD_W ? DMA_SCR_DIR : 0) | DMA_SCR_START;
|
||||||
|
|
||||||
|
print("Started DMA\r\n");
|
||||||
|
|
||||||
|
while (DMA_SCR & DMA_SCR_BUSY);
|
||||||
|
|
||||||
|
// for (int i = 0; i < arg2; i++) {
|
||||||
|
// while (!(USB_SCR & USB_SCR_RXNE));
|
||||||
|
// data = USB_DR;
|
||||||
|
// }
|
||||||
|
|
||||||
|
print("Finished DMA\r\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
while (!(USB_SCR & USB_SCR_TXE));
|
||||||
|
if (i < 3) {
|
||||||
|
USB_DR = CMP[i];
|
||||||
|
} else {
|
||||||
|
USB_DR = cmd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print("Sent response ");
|
||||||
|
tmp[0] = cmd;
|
||||||
|
print(tmp);
|
||||||
|
print("\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// __NAKED__ int main (void) {
|
||||||
|
// uint8_t rtc_data[7];
|
||||||
|
// uint8_t rtc_new_data[7];
|
||||||
|
// int index = 0;
|
||||||
|
|
||||||
|
// GPIO_OE = (1 << 0);
|
||||||
|
// GPIO_O = (1 << 0);
|
||||||
|
|
||||||
|
// rtc_init();
|
||||||
|
|
||||||
|
// while (!(USB_SR & USB_SR_TXE));
|
||||||
|
// USB_DR = 0x55;
|
||||||
|
// USB_DR = 0xAA;
|
||||||
|
// USB_DR = 0x00;
|
||||||
|
// USB_DR = 'D';
|
||||||
|
// USB_DR = 'E';
|
||||||
|
// USB_DR = 'A';
|
||||||
|
// USB_DR = 'D';
|
||||||
|
// USB_DR = 0xFF;
|
||||||
|
// USB_DR = 0xAA;
|
||||||
|
// USB_DR = 0x55;
|
||||||
|
|
||||||
|
// while (1) {
|
||||||
|
// GPIO_O = (1 << 0);
|
||||||
|
|
||||||
|
// print("\033[2J\033[H\r\n --- Hello --- \r\n\r\n");
|
||||||
|
// print(" RTC Data:\r\n\r\n ");
|
||||||
|
|
||||||
|
// rtc_get_time(rtc_data);
|
||||||
|
|
||||||
|
// print_nice_date(rtc_data);
|
||||||
|
|
||||||
|
// print("\r\n");
|
||||||
|
// GPIO_O = 0x00;
|
||||||
|
|
||||||
|
// while (counter++ < 0x0003FFFF);
|
||||||
|
// counter = 0;
|
||||||
|
|
||||||
|
// if (USB_SR & USB_SR_RXNE) {
|
||||||
|
// rtc_new_data[index++] = USB_DR;
|
||||||
|
// if (index == 7) {
|
||||||
|
// index = 0;
|
||||||
|
// rtc_set_time(rtc_new_data);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
@ -11,16 +11,22 @@
|
|||||||
typedef volatile uint8_t * io8_t;
|
typedef volatile uint8_t * io8_t;
|
||||||
typedef volatile uint32_t * io32_t;
|
typedef volatile uint32_t * io32_t;
|
||||||
|
|
||||||
|
#define RAM (*((io32_t) 0x00000000))
|
||||||
|
#define BOOTLOADER (*((io32_t) 0x10000000))
|
||||||
#define GPIO (*((io32_t) 0x20000000))
|
#define GPIO (*((io32_t) 0x20000000))
|
||||||
#define GPIO_O (*((io8_t) 0x20000000))
|
#define GPIO_O (*((io8_t) 0x20000000))
|
||||||
#define GPIO_I (*((io8_t) 0x20000001))
|
#define GPIO_I (*((io8_t) 0x20000001))
|
||||||
#define GPIO_OE (*((io8_t) 0x20000002))
|
#define GPIO_OE (*((io8_t) 0x20000002))
|
||||||
#define I2C_SR (*((io8_t) 0x30000000))
|
#define I2C_SR (*((io8_t) 0x30000000))
|
||||||
#define I2C_DR (*((io8_t) 0x30000004))
|
#define I2C_DR (*((io8_t) 0x30000004))
|
||||||
#define USB_SR (*((io8_t) 0x40000000))
|
#define USB_SCR (*((io8_t) 0x40000000))
|
||||||
#define USB_DR (*((io8_t) 0x40000004))
|
#define USB_DR (*((io8_t) 0x40000004))
|
||||||
#define UART_SR (*((io8_t) 0x50000000))
|
#define UART_SCR (*((io8_t) 0x50000000))
|
||||||
#define UART_DR (*((io8_t) 0x50000004))
|
#define UART_DR (*((io8_t) 0x50000004))
|
||||||
|
#define DMA_SCR (*((io8_t) 0x60000000))
|
||||||
|
#define DMA_MADDR (*((io32_t) 0x60000004))
|
||||||
|
#define DMA_ID_LEN (*((io32_t) 0x60000008))
|
||||||
|
#define SDRAM (*((io32_t) 0x68000000))
|
||||||
|
|
||||||
#define I2C_SR_START (1 << 0)
|
#define I2C_SR_START (1 << 0)
|
||||||
#define I2C_SR_STOP (1 << 1)
|
#define I2C_SR_STOP (1 << 1)
|
||||||
@ -29,11 +35,21 @@ typedef volatile uint32_t * io32_t;
|
|||||||
#define I2C_SR_BUSY (1 << 4)
|
#define I2C_SR_BUSY (1 << 4)
|
||||||
#define I2C_ADDR_READ (1 << 0)
|
#define I2C_ADDR_READ (1 << 0)
|
||||||
|
|
||||||
#define USB_SR_RXNE (1 << 0)
|
#define USB_SCR_RXNE (1 << 0)
|
||||||
#define USB_SR_TXE (1 << 1)
|
#define USB_SCR_TXE (1 << 1)
|
||||||
|
#define USB_SCR_FLUSH_RX (1 << 2)
|
||||||
|
#define USB_SCR_FLUSH_TX (1 << 3)
|
||||||
|
|
||||||
#define UART_SR_RXNE (1 << 0)
|
#define UART_SCR_RXNE (1 << 0)
|
||||||
#define UART_SR_TXE (1 << 1)
|
#define UART_SCR_TXE (1 << 1)
|
||||||
|
|
||||||
|
#define DMA_SCR_START (1 << 0)
|
||||||
|
#define DMA_SCR_STOP (1 << 1)
|
||||||
|
#define DMA_SCR_DIR (1 << 2)
|
||||||
|
#define DMA_SCR_BUSY (1 << 3)
|
||||||
|
|
||||||
|
#define DMA_ID_USB (0)
|
||||||
|
#define DMA_ID_SD (1)
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
interface if_dma ();
|
interface if_dma ();
|
||||||
|
|
||||||
|
localparam [1:0] NUM_DEVICES = sc64::__ID_DMA_END;
|
||||||
|
|
||||||
|
sc64::e_dma_id id;
|
||||||
|
|
||||||
|
logic rx_empty;
|
||||||
|
logic rx_read;
|
||||||
|
logic [7:0] rx_rdata;
|
||||||
|
logic tx_full;
|
||||||
|
logic tx_write;
|
||||||
|
logic [7:0] tx_wdata;
|
||||||
|
|
||||||
logic request;
|
logic request;
|
||||||
logic ack;
|
logic ack;
|
||||||
logic write;
|
logic write;
|
||||||
@ -7,7 +18,16 @@ interface if_dma ();
|
|||||||
logic [15:0] rdata;
|
logic [15:0] rdata;
|
||||||
logic [15:0] wdata;
|
logic [15:0] wdata;
|
||||||
|
|
||||||
modport cpu (
|
modport controller (
|
||||||
|
output id,
|
||||||
|
|
||||||
|
input rx_empty,
|
||||||
|
output rx_read,
|
||||||
|
input rx_rdata,
|
||||||
|
input tx_full,
|
||||||
|
output tx_write,
|
||||||
|
output tx_wdata,
|
||||||
|
|
||||||
output request,
|
output request,
|
||||||
input ack,
|
input ack,
|
||||||
output write,
|
output write,
|
||||||
@ -25,4 +45,136 @@ interface if_dma ();
|
|||||||
input wdata
|
input wdata
|
||||||
);
|
);
|
||||||
|
|
||||||
|
logic [7:0] device_rx_rdata [(NUM_DEVICES - 1):0];
|
||||||
|
logic device_rx_empty [(NUM_DEVICES - 1):0];
|
||||||
|
logic device_tx_full [(NUM_DEVICES - 1):0];
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
rx_rdata = 8'd0;
|
||||||
|
|
||||||
|
for (integer i = 0; i < NUM_DEVICES; i++) begin
|
||||||
|
rx_rdata = rx_rdata | device_rx_rdata[i];
|
||||||
|
rx_empty = rx_empty | (device_rx_empty[i] && id == i[1:0]);
|
||||||
|
tx_full = tx_full | (device_tx_full[i] && id == i[1:0]);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
genvar n;
|
||||||
|
generate
|
||||||
|
for (n = 0; n < NUM_DEVICES; n++) begin : at
|
||||||
|
logic device_selected;
|
||||||
|
logic device_rx_read;
|
||||||
|
logic device_tx_write;
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
device_selected = id == n[1:0];
|
||||||
|
device_rx_read = device_selected && rx_read;
|
||||||
|
device_tx_write = device_selected && tx_write;
|
||||||
|
end
|
||||||
|
|
||||||
|
modport device (
|
||||||
|
output .rx_empty(device_rx_empty[n]),
|
||||||
|
input .rx_read(device_rx_read),
|
||||||
|
output .rx_rdata(device_rx_rdata[n]),
|
||||||
|
output .tx_full(device_tx_full[n]),
|
||||||
|
input .tx_write(device_tx_write),
|
||||||
|
input .tx_wdata(tx_wdata)
|
||||||
|
);
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
endinterface
|
endinterface
|
||||||
|
|
||||||
|
|
||||||
|
module cpu_dma (
|
||||||
|
if_system.sys sys,
|
||||||
|
if_cpu_bus bus,
|
||||||
|
if_dma.controller dma
|
||||||
|
);
|
||||||
|
|
||||||
|
always_ff @(posedge sys.clk) begin
|
||||||
|
bus.ack <= 1'b0;
|
||||||
|
if (bus.request) begin
|
||||||
|
bus.ack <= 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
bus.rdata = 32'd0;
|
||||||
|
// if (bus.ack) begin
|
||||||
|
// case (bus.address[2:2])
|
||||||
|
// 0: bus.rdata = {30'd0, ~tx_full, ~rx_empty};
|
||||||
|
// 1: bus.rdata = {24'd0, rx_rdata};
|
||||||
|
// default: bus.rdata = 32'd0;
|
||||||
|
// endcase
|
||||||
|
// end
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(posedge sys.clk) begin
|
||||||
|
// rx_flush <= 1'b0;
|
||||||
|
// cpu_rx_read <= 1'b0;
|
||||||
|
|
||||||
|
// tx_flush <= 1'b0;
|
||||||
|
// cpu_tx_write <= 1'b0;
|
||||||
|
|
||||||
|
// if (bus.request) begin
|
||||||
|
// case (bus.address[2:2])
|
||||||
|
// 2'd0: begin
|
||||||
|
// if (bus.wmask[0]) begin
|
||||||
|
// {tx_flush, rx_flush} <= bus.wdata[3:2];
|
||||||
|
// end
|
||||||
|
// end
|
||||||
|
|
||||||
|
// 2'd1: begin
|
||||||
|
// if (bus.wmask[0]) begin
|
||||||
|
// cpu_tx_write <= 1'b1;
|
||||||
|
// end else begin
|
||||||
|
// cpu_rx_read <= 1'b1;
|
||||||
|
// end
|
||||||
|
// end
|
||||||
|
// endcase
|
||||||
|
// end
|
||||||
|
end
|
||||||
|
// typedef enum bit [0:0] {
|
||||||
|
// S_IDLE,
|
||||||
|
// S_WAIT
|
||||||
|
// } e_state;
|
||||||
|
|
||||||
|
// e_state state;
|
||||||
|
|
||||||
|
// logic byte_counter;
|
||||||
|
|
||||||
|
// always_ff @(posedge sys.clk) begin
|
||||||
|
// rx_read <= 1'b0;
|
||||||
|
|
||||||
|
// if (sys.reset) begin
|
||||||
|
// dma.request <= 1'b0;
|
||||||
|
// dma.write <= 1'b1;
|
||||||
|
// dma.address <= 32'd0;
|
||||||
|
// state <= S_IDLE;
|
||||||
|
// byte_counter <= 1'b0;
|
||||||
|
// end else begin
|
||||||
|
// case (state)
|
||||||
|
// S_IDLE: begin
|
||||||
|
// if (!rx_empty && !rx_read) begin
|
||||||
|
// byte_counter <= ~byte_counter;
|
||||||
|
// rx_read <= 1'b1;
|
||||||
|
// dma.wdata <= {dma.wdata[7:0], rx_rdata};
|
||||||
|
// if (byte_counter) begin
|
||||||
|
// dma.request <= 1'b1;
|
||||||
|
// state <= S_WAIT;
|
||||||
|
// end
|
||||||
|
// end
|
||||||
|
// end
|
||||||
|
|
||||||
|
// S_WAIT: begin
|
||||||
|
// if (dma.ack) begin
|
||||||
|
// dma.address <= dma.address + 2'd2;
|
||||||
|
// dma.request <= 1'b0;
|
||||||
|
// state <= S_IDLE;
|
||||||
|
// end
|
||||||
|
// end
|
||||||
|
// endcase
|
||||||
|
// end
|
||||||
|
// end
|
||||||
|
endmodule
|
||||||
|
@ -61,7 +61,7 @@ module cpu_soc (
|
|||||||
cpu_usb cpu_usb_inst (
|
cpu_usb cpu_usb_inst (
|
||||||
.sys(sys),
|
.sys(sys),
|
||||||
.bus(bus.at[sc64::ID_CPU_USB].device),
|
.bus(bus.at[sc64::ID_CPU_USB].device),
|
||||||
.dma(dma),
|
.dma(dma.at[sc64::ID_DMA_USB].device),
|
||||||
.usb_clk(usb_clk),
|
.usb_clk(usb_clk),
|
||||||
.usb_cs(usb_cs),
|
.usb_cs(usb_cs),
|
||||||
.usb_miso(usb_miso),
|
.usb_miso(usb_miso),
|
||||||
@ -78,4 +78,10 @@ module cpu_soc (
|
|||||||
.uart_rts(uart_rts)
|
.uart_rts(uart_rts)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
cpu_dma cpu_dma_inst (
|
||||||
|
.sys(sys),
|
||||||
|
.bus(bus.at[sc64::ID_CPU_DMA].device),
|
||||||
|
.dma(dma)
|
||||||
|
);
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
module cpu_usb (
|
module cpu_usb (
|
||||||
if_system sys,
|
if_system sys,
|
||||||
if_cpu_bus bus,
|
if_cpu_bus bus,
|
||||||
if_dma.cpu dma,
|
if_dma dma,
|
||||||
|
|
||||||
output usb_clk,
|
output usb_clk,
|
||||||
output usb_cs,
|
output usb_cs,
|
||||||
@ -20,86 +20,57 @@ module cpu_usb (
|
|||||||
logic tx_write;
|
logic tx_write;
|
||||||
logic [7:0] tx_wdata;
|
logic [7:0] tx_wdata;
|
||||||
|
|
||||||
// always_ff @(posedge sys.clk) begin
|
logic cpu_rx_read;
|
||||||
// bus.ack <= 1'b0;
|
logic cpu_tx_write;
|
||||||
// if (bus.request) begin
|
|
||||||
// bus.ack <= 1'b1;
|
|
||||||
// end
|
|
||||||
// end
|
|
||||||
|
|
||||||
// always_comb begin
|
always_comb begin
|
||||||
// bus.rdata = 32'd0;
|
dma.rx_empty = rx_empty;
|
||||||
// if (bus.ack) begin
|
rx_read = cpu_rx_read || dma.rx_read;
|
||||||
// case (bus.address[2:2])
|
dma.rx_rdata = rx_rdata;
|
||||||
// 0: bus.rdata = {30'd0, ~tx_full, ~rx_empty};
|
|
||||||
// 1: bus.rdata = {24'd0, rx_rdata};
|
|
||||||
// default: bus.rdata = 32'd0;
|
|
||||||
// endcase
|
|
||||||
// end
|
|
||||||
// end
|
|
||||||
|
|
||||||
// always_ff @(posedge sys.clk) begin
|
dma.tx_full = tx_full;
|
||||||
// rx_flush <= 1'b0;
|
tx_write = cpu_tx_write || dma.tx_write;
|
||||||
// rx_read <= 1'b0;
|
tx_wdata = dma.tx_write ? dma.tx_wdata : bus.wdata[7:0];
|
||||||
|
end
|
||||||
// tx_flush <= 1'b0;
|
|
||||||
// tx_write <= 1'b0;
|
|
||||||
|
|
||||||
// if (bus.request) begin
|
|
||||||
// case (bus.address[2:2])
|
|
||||||
// 2'd0: if (bus.wmask[0]) begin
|
|
||||||
// {tx_flush, rx_flush} <= bus.wdata[3:2];
|
|
||||||
// end
|
|
||||||
|
|
||||||
// 2'd1: if (bus.wmask[0]) begin
|
|
||||||
// if (!tx_full) begin
|
|
||||||
// tx_write <= 1'b1;
|
|
||||||
// tx_wdata <= bus.wdata[7:0];
|
|
||||||
// end
|
|
||||||
// end else begin
|
|
||||||
// rx_read <= 1'b1;
|
|
||||||
// end
|
|
||||||
// endcase
|
|
||||||
// end
|
|
||||||
// end
|
|
||||||
|
|
||||||
typedef enum bit [0:0] {
|
|
||||||
S_IDLE,
|
|
||||||
S_WAIT
|
|
||||||
} e_state;
|
|
||||||
|
|
||||||
e_state state;
|
|
||||||
|
|
||||||
logic byte_counter;
|
|
||||||
|
|
||||||
always_ff @(posedge sys.clk) begin
|
always_ff @(posedge sys.clk) begin
|
||||||
rx_read <= 1'b0;
|
bus.ack <= 1'b0;
|
||||||
|
if (bus.request) begin
|
||||||
|
bus.ack <= 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if (sys.reset) begin
|
always_comb begin
|
||||||
dma.request <= 1'b0;
|
bus.rdata = 32'd0;
|
||||||
dma.write <= 1'b1;
|
if (bus.ack) begin
|
||||||
dma.address <= 32'd0;
|
case (bus.address[2:2])
|
||||||
state <= S_IDLE;
|
0: bus.rdata = {30'd0, ~tx_full, ~rx_empty};
|
||||||
byte_counter <= 1'b0;
|
1: bus.rdata = {24'd0, rx_rdata};
|
||||||
end else begin
|
default: bus.rdata = 32'd0;
|
||||||
case (state)
|
endcase
|
||||||
S_IDLE: begin
|
end
|
||||||
if (!rx_empty && !rx_read) begin
|
end
|
||||||
byte_counter <= ~byte_counter;
|
|
||||||
rx_read <= 1'b1;
|
always_ff @(posedge sys.clk) begin
|
||||||
dma.wdata <= {dma.wdata[7:0], rx_rdata};
|
rx_flush <= 1'b0;
|
||||||
if (byte_counter) begin
|
cpu_rx_read <= 1'b0;
|
||||||
dma.request <= 1'b1;
|
|
||||||
state <= S_WAIT;
|
tx_flush <= 1'b0;
|
||||||
end
|
cpu_tx_write <= 1'b0;
|
||||||
|
|
||||||
|
if (bus.request) begin
|
||||||
|
case (bus.address[2:2])
|
||||||
|
2'd0: begin
|
||||||
|
if (bus.wmask[0]) begin
|
||||||
|
{tx_flush, rx_flush} <= bus.wdata[3:2];
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
S_WAIT: begin
|
2'd1: begin
|
||||||
if (dma.ack) begin
|
if (bus.wmask[0]) begin
|
||||||
dma.address <= dma.address + 2'd2;
|
cpu_tx_write <= 1'b1;
|
||||||
dma.request <= 1'b0;
|
end else begin
|
||||||
state <= S_IDLE;
|
cpu_rx_read <= 1'b1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
@ -120,10 +91,10 @@ module cpu_usb (
|
|||||||
.rx_read(rx_read),
|
.rx_read(rx_read),
|
||||||
.rx_rdata(rx_rdata),
|
.rx_rdata(rx_rdata),
|
||||||
|
|
||||||
// .tx_flush(tx_flush),
|
.tx_flush(tx_flush),
|
||||||
// .tx_full(tx_full),
|
.tx_full(tx_full),
|
||||||
// .tx_write(tx_write),
|
.tx_write(tx_write),
|
||||||
// .tx_wdata(tx_wdata)
|
.tx_wdata(tx_wdata)
|
||||||
);
|
);
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -4,7 +4,7 @@ module memory_sdram (
|
|||||||
input request,
|
input request,
|
||||||
output ack,
|
output ack,
|
||||||
input write,
|
input write,
|
||||||
input [31:0] address,
|
input [25:0] address,
|
||||||
output [15:0] rdata,
|
output [15:0] rdata,
|
||||||
input [15:0] wdata,
|
input [15:0] wdata,
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ module n64_sdram (
|
|||||||
.request(mem_request),
|
.request(mem_request),
|
||||||
.ack(mem_ack),
|
.ack(mem_ack),
|
||||||
.write(mem_write),
|
.write(mem_write),
|
||||||
.address(mem_address),
|
.address(mem_address[25:0]),
|
||||||
.rdata(mem_rdata),
|
.rdata(mem_rdata),
|
||||||
.wdata(mem_wdata),
|
.wdata(mem_wdata),
|
||||||
|
|
||||||
|
@ -16,13 +16,20 @@ package sc64;
|
|||||||
ID_CPU_I2C,
|
ID_CPU_I2C,
|
||||||
ID_CPU_USB,
|
ID_CPU_USB,
|
||||||
ID_CPU_UART,
|
ID_CPU_UART,
|
||||||
|
ID_CPU_DMA,
|
||||||
__ID_CPU_END
|
__ID_CPU_END
|
||||||
} e_cpu_id;
|
} e_cpu_id;
|
||||||
|
|
||||||
|
typedef enum bit [1:0] {
|
||||||
|
ID_DMA_USB,
|
||||||
|
ID_DMA_SD,
|
||||||
|
__ID_DMA_END
|
||||||
|
} e_dma_id;
|
||||||
|
|
||||||
parameter int CLOCK_FREQUENCY = 32'd100_000_000;
|
parameter int CLOCK_FREQUENCY = 32'd100_000_000;
|
||||||
|
|
||||||
parameter int UART_BAUD_RATE = 32'd1_000_000;
|
parameter int UART_BAUD_RATE = 32'd1_000_000;
|
||||||
|
|
||||||
parameter bit DEBUG_ENABLED = 1'b0;
|
parameter bit DEBUG_ENABLED = 1'b1;
|
||||||
|
|
||||||
endpackage
|
endpackage
|
||||||
|
@ -9,39 +9,34 @@ module usb_ft1248 (
|
|||||||
|
|
||||||
input rx_flush,
|
input rx_flush,
|
||||||
output rx_empty,
|
output rx_empty,
|
||||||
// output rx_almost_empty,
|
|
||||||
input rx_read,
|
input rx_read,
|
||||||
output [7:0] rx_rdata,
|
output [7:0] rx_rdata,
|
||||||
|
|
||||||
input tx_flush,
|
input tx_flush,
|
||||||
output tx_full,
|
output tx_full,
|
||||||
// output tx_almost_full,
|
|
||||||
input tx_write,
|
input tx_write,
|
||||||
input [7:0] tx_wdata
|
input [7:0] tx_wdata
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIFOs
|
// FIFOs
|
||||||
|
|
||||||
wire rx_full;
|
logic rx_full;
|
||||||
wire rx_almost_full;
|
logic rx_write;
|
||||||
reg rx_write;
|
logic [7:0] rx_wdata;
|
||||||
reg [7:0] rx_wdata;
|
|
||||||
|
|
||||||
wire tx_empty;
|
logic tx_empty;
|
||||||
reg tx_read;
|
logic tx_read;
|
||||||
wire [7:0] tx_rdata;
|
logic [7:0] tx_rdata;
|
||||||
|
|
||||||
intel_fifo_8 fifo_8_rx_inst (
|
intel_fifo_8 fifo_8_rx_inst (
|
||||||
.clock(sys.clk),
|
.clock(sys.clk),
|
||||||
.sclr(rx_flush),
|
.sclr(rx_flush),
|
||||||
|
|
||||||
.empty(rx_empty),
|
.empty(rx_empty),
|
||||||
// .almost_empty(rx_almost_empty),
|
|
||||||
.rdreq(rx_read),
|
.rdreq(rx_read),
|
||||||
.q(rx_rdata),
|
.q(rx_rdata),
|
||||||
|
|
||||||
.full(rx_full),
|
.full(rx_full),
|
||||||
// .almost_full(rx_almost_full),
|
|
||||||
.wrreq(rx_write),
|
.wrreq(rx_write),
|
||||||
.data(rx_wdata)
|
.data(rx_wdata)
|
||||||
);
|
);
|
||||||
@ -55,21 +50,18 @@ module usb_ft1248 (
|
|||||||
.q(tx_rdata),
|
.q(tx_rdata),
|
||||||
|
|
||||||
.full(tx_full),
|
.full(tx_full),
|
||||||
// .almost_full(tx_almost_full),
|
|
||||||
.wrreq(tx_write),
|
.wrreq(tx_write),
|
||||||
.data(tx_wdata)
|
.data(tx_wdata)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// FT1248 interface controller
|
// FT1248 interface controller
|
||||||
|
|
||||||
// Constants definition
|
typedef enum bit [1:0] {
|
||||||
|
S_TRY_RX,
|
||||||
typedef enum bit [2:0] {
|
S_TRY_TX,
|
||||||
S_TRY_RX = 3'b000,
|
S_COMMAND,
|
||||||
S_TRY_TX = 3'b001,
|
S_DATA
|
||||||
S_COMMAND = 3'b100,
|
|
||||||
S_DATA = 3'b101,
|
|
||||||
S_END = 3'b111
|
|
||||||
} e_state;
|
} e_state;
|
||||||
|
|
||||||
typedef enum bit [7:0] {
|
typedef enum bit [7:0] {
|
||||||
@ -77,78 +69,103 @@ module usb_ft1248 (
|
|||||||
C_READ = 8'h04
|
C_READ = 8'h04
|
||||||
} e_command;
|
} e_command;
|
||||||
|
|
||||||
// FSM state
|
typedef enum bit [1:0] {
|
||||||
|
P_PRE_RISING,
|
||||||
|
P_RISING,
|
||||||
|
P_PRE_FALLING,
|
||||||
|
P_FALLING
|
||||||
|
} e_clock_phase;
|
||||||
|
|
||||||
e_state state;
|
e_state state;
|
||||||
|
|
||||||
// Clock divider and generator
|
logic [3:0] clock_phase;
|
||||||
|
|
||||||
reg [3:0] clock_divider;
|
logic usb_clk_output;
|
||||||
wire rising_edge = clock_divider[1];
|
logic usb_cs_output;
|
||||||
|
logic [3:0] usb_miosi_input;
|
||||||
|
logic [3:0] usb_miosi_output;
|
||||||
|
logic [3:0] usb_miosi_output_data;
|
||||||
|
logic usb_miosi_output_enable;
|
||||||
|
logic usb_miosi_output_enable_data;
|
||||||
|
logic usb_miso_input;
|
||||||
|
logic usb_pwren_input;
|
||||||
|
|
||||||
|
logic is_cmd_write;
|
||||||
|
logic [1:0] nibble_counter;
|
||||||
|
logic [7:0] tx_buffer;
|
||||||
|
|
||||||
always_ff @(posedge sys.clk) begin
|
always_ff @(posedge sys.clk) begin
|
||||||
if (sys.reset || state == S_TRY_RX || state == S_TRY_TX) begin
|
if (sys.reset || state == S_TRY_RX || state == S_TRY_TX) begin
|
||||||
clock_divider <= 4'b0001;
|
clock_phase <= 4'b0001;
|
||||||
end else begin
|
end else begin
|
||||||
clock_divider <= {clock_divider[2:0], clock_divider[3]};
|
clock_phase <= {clock_phase[2:0], clock_phase[3]};
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
// Output chip select and data register behavior
|
always_ff @(posedge sys.clk) begin
|
||||||
|
usb_clk <= usb_clk_output;
|
||||||
|
usb_cs <= usb_cs_output;
|
||||||
|
|
||||||
reg [1:0] bit_counter;
|
usb_miosi_input <= usb_miosi;
|
||||||
reg [7:0] tx_buffer;
|
usb_miosi_output <= usb_miosi_output_data;
|
||||||
|
usb_miosi_output_enable <= usb_miosi_output_enable_data;
|
||||||
|
|
||||||
wire clk_data;
|
usb_miso_input <= usb_miso;
|
||||||
reg cs_data;
|
usb_pwren_input <= usb_pwren;
|
||||||
wire [3:0] miosi_data;
|
|
||||||
reg miosi_output_enable_data;
|
|
||||||
|
|
||||||
reg clk_output;
|
tx_buffer <= tx_rdata;
|
||||||
reg cs_output;
|
end
|
||||||
reg [3:0] miosi_input;
|
|
||||||
reg [3:0] miosi_output;
|
|
||||||
reg miosi_output_enable;
|
|
||||||
reg miso_input;
|
|
||||||
|
|
||||||
always_comb begin
|
always_comb begin
|
||||||
clk_data = 1'b0;
|
usb_miosi = usb_miosi_output_enable ? usb_miosi_output : 4'bZZZZ;
|
||||||
if (state == S_COMMAND || state == S_DATA) clk_data = (clock_divider[2] | clock_divider[3]);
|
|
||||||
usb_clk = clk_output;
|
|
||||||
usb_cs = cs_output;
|
|
||||||
miosi_data = bit_counter[0] ? tx_buffer[3:0] : tx_buffer[7:4];
|
|
||||||
usb_miosi = miosi_output_enable ? miosi_output : 4'bZZZZ;
|
|
||||||
end
|
end
|
||||||
|
|
||||||
always_ff @(posedge sys.clk) begin
|
always_comb begin
|
||||||
clk_output <= clk_data;
|
case (state)
|
||||||
cs_output <= cs_data;
|
S_COMMAND: begin
|
||||||
miosi_input <= usb_miosi;
|
usb_clk_output = clock_phase[P_PRE_FALLING] || clock_phase[P_FALLING];
|
||||||
miosi_output <= miosi_data;
|
usb_cs_output = 1'b0;
|
||||||
miosi_output_enable <= miosi_output_enable_data;
|
if (is_cmd_write) begin
|
||||||
miso_input <= usb_miso;
|
usb_miosi_output_data = nibble_counter[0] ? C_WRITE[3:0] : C_WRITE[7:4];
|
||||||
|
end else begin
|
||||||
|
usb_miosi_output_data = nibble_counter[0] ? C_READ[3:0] : C_READ[7:4];
|
||||||
|
end
|
||||||
|
usb_miosi_output_enable_data = nibble_counter < 2'd2;
|
||||||
|
end
|
||||||
|
|
||||||
|
S_DATA: begin
|
||||||
|
usb_clk_output = clock_phase[P_PRE_FALLING] || clock_phase[P_FALLING];
|
||||||
|
usb_cs_output = 1'b0;
|
||||||
|
usb_miosi_output_data = nibble_counter[0] ? tx_buffer[7:4] : tx_buffer[3:0];
|
||||||
|
usb_miosi_output_enable_data = is_cmd_write;
|
||||||
|
end
|
||||||
|
|
||||||
|
default: begin
|
||||||
|
usb_clk_output = 1'b0;
|
||||||
|
usb_cs_output = 1'b1;
|
||||||
|
usb_miosi_output_data = 4'hF;
|
||||||
|
usb_miosi_output_enable_data = 1'b0;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
// FSM
|
|
||||||
|
|
||||||
reg is_write;
|
|
||||||
|
|
||||||
always_ff @(posedge sys.clk) begin
|
always_ff @(posedge sys.clk) begin
|
||||||
rx_write <= 1'b0;
|
rx_write <= 1'b0;
|
||||||
tx_read <= 1'b0;
|
tx_read <= 1'b0;
|
||||||
|
|
||||||
|
if (clock_phase[P_RISING]) begin
|
||||||
|
nibble_counter <= nibble_counter + 1'd1;
|
||||||
|
end
|
||||||
|
|
||||||
if (sys.reset) begin
|
if (sys.reset) begin
|
||||||
state <= S_TRY_RX;
|
state <= S_TRY_RX;
|
||||||
cs_data <= 1'b1;
|
|
||||||
miosi_output_enable_data <= 1'b0;
|
|
||||||
end else begin
|
end else begin
|
||||||
case (state)
|
case (state)
|
||||||
S_TRY_RX: begin
|
S_TRY_RX: begin
|
||||||
if (!rx_full) begin
|
if (!rx_full) begin
|
||||||
state <= S_COMMAND;
|
state <= S_COMMAND;
|
||||||
tx_buffer <= C_READ;
|
is_cmd_write <= 1'b0;
|
||||||
bit_counter <= 2'b11;
|
nibble_counter <= 2'b11;
|
||||||
is_write <= 1'b0;
|
|
||||||
end else begin
|
end else begin
|
||||||
state <= S_TRY_TX;
|
state <= S_TRY_TX;
|
||||||
end
|
end
|
||||||
@ -157,71 +174,45 @@ module usb_ft1248 (
|
|||||||
S_TRY_TX: begin
|
S_TRY_TX: begin
|
||||||
if (!tx_empty) begin
|
if (!tx_empty) begin
|
||||||
state <= S_COMMAND;
|
state <= S_COMMAND;
|
||||||
tx_buffer <= C_WRITE;
|
is_cmd_write <= 1'b1;
|
||||||
bit_counter <= 2'b11;
|
nibble_counter <= 2'b11;
|
||||||
is_write <= 1'b1;
|
|
||||||
end else begin
|
end else begin
|
||||||
state <= S_TRY_RX;
|
state <= S_TRY_RX;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
S_COMMAND: begin
|
S_COMMAND: begin
|
||||||
cs_data <= 1'b0;
|
if (clock_phase[P_RISING]) begin
|
||||||
if (rising_edge) begin
|
if (nibble_counter == 2'd2) begin
|
||||||
bit_counter <= bit_counter + 1'd1;
|
if (usb_miso_input) begin
|
||||||
miosi_output_enable_data <= 1'b1;
|
state <= is_cmd_write ? S_TRY_RX : S_TRY_TX;
|
||||||
if (bit_counter == 2'd1) begin
|
|
||||||
miosi_output_enable_data <= 1'b0;
|
|
||||||
end
|
|
||||||
if (bit_counter == 2'd2) begin
|
|
||||||
if (!miso_input) begin
|
|
||||||
state <= S_DATA;
|
|
||||||
bit_counter <= 2'b11;
|
|
||||||
tx_buffer <= tx_rdata;
|
|
||||||
miosi_output_enable_data <= is_write;
|
|
||||||
end else begin
|
end else begin
|
||||||
state <= S_END;
|
state <= S_DATA;
|
||||||
miosi_output_enable_data <= 1'b0;
|
nibble_counter <= 2'd0;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
S_DATA: begin
|
S_DATA: begin
|
||||||
if (rising_edge) begin
|
if (clock_phase[P_FALLING]) begin
|
||||||
bit_counter <= {1'b0, ~bit_counter[0]};
|
if (nibble_counter[0]) begin
|
||||||
miosi_output_enable_data <= is_write;
|
tx_read <= is_cmd_write;
|
||||||
rx_wdata <= {miosi_input, rx_wdata[7:4]};
|
|
||||||
if (bit_counter == 1'd1) begin
|
|
||||||
tx_buffer <= tx_rdata;
|
|
||||||
end
|
end
|
||||||
if (!is_write && (bit_counter[0] == 1'd0)) begin
|
end
|
||||||
rx_write <= 1'b1;
|
if (clock_phase[P_RISING]) begin
|
||||||
|
rx_wdata <= {usb_miosi_input, rx_wdata[7:4]};
|
||||||
|
if (nibble_counter[0]) begin
|
||||||
|
rx_write <= !is_cmd_write;
|
||||||
end
|
end
|
||||||
if (is_write && (bit_counter[0] == 1'd1)) begin
|
if (usb_miso_input || (!is_cmd_write && rx_full) || (is_cmd_write && tx_empty)) begin
|
||||||
tx_read <= 1'b1;
|
state <= is_cmd_write ? S_TRY_RX : S_TRY_TX;
|
||||||
end
|
|
||||||
if (
|
|
||||||
(bit_counter[0] == 1'd1 && miso_input) ||
|
|
||||||
(bit_counter[0] == 1'd0 && (
|
|
||||||
(is_write && tx_empty) ||
|
|
||||||
(!is_write && rx_almost_full)
|
|
||||||
))) begin
|
|
||||||
state <= S_END;
|
|
||||||
miosi_output_enable_data <= 1'b0;
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
S_END: begin
|
|
||||||
cs_data <= 1'b1;
|
|
||||||
state <= is_write ? S_TRY_RX : S_TRY_TX;
|
|
||||||
end
|
|
||||||
|
|
||||||
default: begin
|
default: begin
|
||||||
state <= S_TRY_RX;
|
state <= S_TRY_RX;
|
||||||
cs_data <= 1'b1;
|
|
||||||
miosi_output_enable_data <= 1'b0;
|
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
1605
fw/stp.stp
1605
fw/stp.stp
File diff suppressed because one or more lines are too long
@ -1,91 +0,0 @@
|
|||||||
module device_arbiter #(
|
|
||||||
parameter NUM_CONTROLLERS = 2,
|
|
||||||
parameter ADDRESS_WIDTH = 26,
|
|
||||||
parameter [3:0] DEVICE_BANK = 4'd0,
|
|
||||||
parameter ACK_FIFO_LENGTH = 4
|
|
||||||
) (
|
|
||||||
input i_clk,
|
|
||||||
input i_reset,
|
|
||||||
|
|
||||||
input [(NUM_CONTROLLERS - 1):0] i_request,
|
|
||||||
input [(NUM_CONTROLLERS - 1):0] i_write,
|
|
||||||
output reg [(NUM_CONTROLLERS - 1):0] o_busy,
|
|
||||||
output reg [(NUM_CONTROLLERS - 1):0] o_ack,
|
|
||||||
input [((NUM_CONTROLLERS * 4) - 1):0] i_bank,
|
|
||||||
input [((NUM_CONTROLLERS * ADDRESS_WIDTH) - 1):0] i_address,
|
|
||||||
output reg [((NUM_CONTROLLERS * 32) - 1):0] o_data,
|
|
||||||
input [((NUM_CONTROLLERS * 32) - 1):0] i_data,
|
|
||||||
|
|
||||||
output reg o_device_request,
|
|
||||||
output reg o_device_write,
|
|
||||||
input i_device_busy,
|
|
||||||
input i_device_ack,
|
|
||||||
output reg [(ADDRESS_WIDTH - 1):0] o_device_address,
|
|
||||||
input [31:0] i_device_data,
|
|
||||||
output reg [31:0] o_device_data
|
|
||||||
);
|
|
||||||
|
|
||||||
localparam FIFO_ADDRESS_WIDTH = $clog2(ACK_FIFO_LENGTH);
|
|
||||||
|
|
||||||
reg [(NUM_CONTROLLERS - 1):0] r_request;
|
|
||||||
reg [(NUM_CONTROLLERS - 1):0] r_request_successful;
|
|
||||||
|
|
||||||
reg [(NUM_CONTROLLERS - 1):0] r_ack_fifo_mem [0:(ACK_FIFO_LENGTH - 1)];
|
|
||||||
|
|
||||||
reg [FIFO_ADDRESS_WIDTH:0] r_ack_fifo_wrptr;
|
|
||||||
reg [FIFO_ADDRESS_WIDTH:0] r_ack_fifo_rdptr;
|
|
||||||
|
|
||||||
wire w_ack_fifo_wrreq = |(r_request_successful & ~i_write);
|
|
||||||
wire w_ack_fifo_rdreq = i_device_ack;
|
|
||||||
|
|
||||||
wire w_empty = r_ack_fifo_wrptr[FIFO_ADDRESS_WIDTH] == r_ack_fifo_rdptr[FIFO_ADDRESS_WIDTH];
|
|
||||||
wire w_full_or_empty = r_ack_fifo_wrptr[(FIFO_ADDRESS_WIDTH - 1):0] == r_ack_fifo_rdptr[(FIFO_ADDRESS_WIDTH - 1):0];
|
|
||||||
|
|
||||||
wire w_ack_fifo_full = !w_empty && w_full_or_empty;
|
|
||||||
|
|
||||||
always @(posedge i_clk) begin
|
|
||||||
if (i_reset) begin
|
|
||||||
r_ack_fifo_wrptr <= {(FIFO_ADDRESS_WIDTH + 1){1'b0}};
|
|
||||||
r_ack_fifo_rdptr <= {(FIFO_ADDRESS_WIDTH + 1){1'b0}};
|
|
||||||
end else begin
|
|
||||||
if (w_ack_fifo_wrreq) begin
|
|
||||||
r_ack_fifo_mem[r_ack_fifo_wrptr[(FIFO_ADDRESS_WIDTH - 1):0]] <= r_request_successful & ~i_write;
|
|
||||||
r_ack_fifo_wrptr <= r_ack_fifo_wrptr + 1'd1;
|
|
||||||
end
|
|
||||||
if (w_ack_fifo_rdreq) begin
|
|
||||||
r_ack_fifo_rdptr <= r_ack_fifo_rdptr + 1'd1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
always @(*) begin
|
|
||||||
for (integer i = 0; i < NUM_CONTROLLERS; i = i + 1) begin
|
|
||||||
r_request[i] = i_request[i] && i_bank[(i * 4) +: 4] == DEVICE_BANK;
|
|
||||||
o_busy[i] = r_request[i] && (
|
|
||||||
i_device_busy ||
|
|
||||||
|(r_request & (({{(NUM_CONTROLLERS - 1){1'b0}}, 1'b1} << i) - 1)) ||
|
|
||||||
(!i_write[i] && w_ack_fifo_full)
|
|
||||||
);
|
|
||||||
end
|
|
||||||
|
|
||||||
r_request_successful = r_request & ~o_busy;
|
|
||||||
o_ack = {NUM_CONTROLLERS{i_device_ack}} & r_ack_fifo_mem[r_ack_fifo_rdptr[(FIFO_ADDRESS_WIDTH - 1):0]];
|
|
||||||
o_data = {NUM_CONTROLLERS{i_device_data}};
|
|
||||||
end
|
|
||||||
|
|
||||||
always @(*) begin
|
|
||||||
o_device_request = |r_request;
|
|
||||||
o_device_write = 1'b0;
|
|
||||||
o_device_address = {ADDRESS_WIDTH{1'b0}};
|
|
||||||
o_device_data = 32'h0000_0000;
|
|
||||||
|
|
||||||
for (integer i = (NUM_CONTROLLERS - 1); i >= 0 ; i = i - 1) begin
|
|
||||||
if (r_request[i]) begin
|
|
||||||
o_device_write = i_write[i];
|
|
||||||
o_device_address = i_address[(i * ADDRESS_WIDTH) +: ADDRESS_WIDTH];
|
|
||||||
o_device_data = i_data[(i * 32) +: 32];
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
@ -1,4 +0,0 @@
|
|||||||
set_global_assignment -name IP_TOOL_NAME "FIFO"
|
|
||||||
set_global_assignment -name IP_TOOL_VERSION "20.1"
|
|
||||||
set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{MAX 10}"
|
|
||||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "fifo8.v"]
|
|
@ -1,179 +0,0 @@
|
|||||||
// megafunction wizard: %FIFO%
|
|
||||||
// GENERATION: STANDARD
|
|
||||||
// VERSION: WM1.0
|
|
||||||
// MODULE: scfifo
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// File Name: fifo8.v
|
|
||||||
// Megafunction Name(s):
|
|
||||||
// scfifo
|
|
||||||
//
|
|
||||||
// Simulation Library Files(s):
|
|
||||||
// altera_mf
|
|
||||||
// ============================================================
|
|
||||||
// ************************************************************
|
|
||||||
// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
|
|
||||||
//
|
|
||||||
// 20.1.1 Build 720 11/11/2020 SJ Lite Edition
|
|
||||||
// ************************************************************
|
|
||||||
|
|
||||||
|
|
||||||
//Copyright (C) 2020 Intel Corporation. All rights reserved.
|
|
||||||
//Your use of Intel Corporation's design tools, logic functions
|
|
||||||
//and other software and tools, and any partner logic
|
|
||||||
//functions, and any output files from any of the foregoing
|
|
||||||
//(including device programming or simulation files), and any
|
|
||||||
//associated documentation or information are expressly subject
|
|
||||||
//to the terms and conditions of the Intel Program License
|
|
||||||
//Subscription Agreement, the Intel Quartus Prime License Agreement,
|
|
||||||
//the Intel FPGA IP License Agreement, or other applicable license
|
|
||||||
//agreement, including, without limitation, that your use is for
|
|
||||||
//the sole purpose of programming logic devices manufactured by
|
|
||||||
//Intel and sold by Intel or its authorized distributors. Please
|
|
||||||
//refer to the applicable agreement for further details, at
|
|
||||||
//https://fpgasoftware.intel.com/eula.
|
|
||||||
|
|
||||||
|
|
||||||
// synopsys translate_off
|
|
||||||
`timescale 1 ps / 1 ps
|
|
||||||
// synopsys translate_on
|
|
||||||
module fifo8 (
|
|
||||||
clock,
|
|
||||||
data,
|
|
||||||
rdreq,
|
|
||||||
sclr,
|
|
||||||
wrreq,
|
|
||||||
almost_empty,
|
|
||||||
almost_full,
|
|
||||||
empty,
|
|
||||||
full,
|
|
||||||
q);
|
|
||||||
|
|
||||||
input clock;
|
|
||||||
input [7:0] data;
|
|
||||||
input rdreq;
|
|
||||||
input sclr;
|
|
||||||
input wrreq;
|
|
||||||
output almost_empty;
|
|
||||||
output almost_full;
|
|
||||||
output empty;
|
|
||||||
output full;
|
|
||||||
output [7:0] q;
|
|
||||||
|
|
||||||
wire sub_wire0;
|
|
||||||
wire sub_wire1;
|
|
||||||
wire sub_wire2;
|
|
||||||
wire sub_wire3;
|
|
||||||
wire [7:0] sub_wire4;
|
|
||||||
wire almost_empty = sub_wire0;
|
|
||||||
wire almost_full = sub_wire1;
|
|
||||||
wire empty = sub_wire2;
|
|
||||||
wire full = sub_wire3;
|
|
||||||
wire [7:0] q = sub_wire4[7:0];
|
|
||||||
|
|
||||||
scfifo scfifo_component (
|
|
||||||
.clock (clock),
|
|
||||||
.data (data),
|
|
||||||
.rdreq (rdreq),
|
|
||||||
.sclr (sclr),
|
|
||||||
.wrreq (wrreq),
|
|
||||||
.almost_empty (sub_wire0),
|
|
||||||
.almost_full (sub_wire1),
|
|
||||||
.empty (sub_wire2),
|
|
||||||
.full (sub_wire3),
|
|
||||||
.q (sub_wire4),
|
|
||||||
.aclr (),
|
|
||||||
.eccstatus (),
|
|
||||||
.usedw ());
|
|
||||||
defparam
|
|
||||||
scfifo_component.add_ram_output_register = "ON",
|
|
||||||
scfifo_component.almost_empty_value = 2,
|
|
||||||
scfifo_component.almost_full_value = 1023,
|
|
||||||
scfifo_component.intended_device_family = "MAX 10",
|
|
||||||
scfifo_component.lpm_numwords = 1024,
|
|
||||||
scfifo_component.lpm_showahead = "ON",
|
|
||||||
scfifo_component.lpm_type = "scfifo",
|
|
||||||
scfifo_component.lpm_width = 8,
|
|
||||||
scfifo_component.lpm_widthu = 10,
|
|
||||||
scfifo_component.overflow_checking = "ON",
|
|
||||||
scfifo_component.underflow_checking = "ON",
|
|
||||||
scfifo_component.use_eab = "ON";
|
|
||||||
|
|
||||||
|
|
||||||
endmodule
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// CNX file retrieval info
|
|
||||||
// ============================================================
|
|
||||||
// Retrieval info: PRIVATE: AlmostEmpty NUMERIC "1"
|
|
||||||
// Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "2"
|
|
||||||
// Retrieval info: PRIVATE: AlmostFull NUMERIC "1"
|
|
||||||
// Retrieval info: PRIVATE: AlmostFullThr NUMERIC "1023"
|
|
||||||
// Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "1"
|
|
||||||
// Retrieval info: PRIVATE: Clock NUMERIC "0"
|
|
||||||
// Retrieval info: PRIVATE: Depth NUMERIC "1024"
|
|
||||||
// Retrieval info: PRIVATE: Empty NUMERIC "1"
|
|
||||||
// Retrieval info: PRIVATE: Full NUMERIC "1"
|
|
||||||
// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "MAX 10"
|
|
||||||
// Retrieval info: PRIVATE: LE_BasedFIFO NUMERIC "0"
|
|
||||||
// Retrieval info: PRIVATE: LegacyRREQ NUMERIC "0"
|
|
||||||
// Retrieval info: PRIVATE: MAX_DEPTH_BY_9 NUMERIC "0"
|
|
||||||
// Retrieval info: PRIVATE: OVERFLOW_CHECKING NUMERIC "0"
|
|
||||||
// Retrieval info: PRIVATE: Optimize NUMERIC "1"
|
|
||||||
// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0"
|
|
||||||
// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
|
|
||||||
// Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0"
|
|
||||||
// Retrieval info: PRIVATE: UsedW NUMERIC "0"
|
|
||||||
// Retrieval info: PRIVATE: Width NUMERIC "8"
|
|
||||||
// Retrieval info: PRIVATE: dc_aclr NUMERIC "0"
|
|
||||||
// Retrieval info: PRIVATE: diff_widths NUMERIC "0"
|
|
||||||
// Retrieval info: PRIVATE: msb_usedw NUMERIC "0"
|
|
||||||
// Retrieval info: PRIVATE: output_width NUMERIC "8"
|
|
||||||
// Retrieval info: PRIVATE: rsEmpty NUMERIC "1"
|
|
||||||
// Retrieval info: PRIVATE: rsFull NUMERIC "0"
|
|
||||||
// Retrieval info: PRIVATE: rsUsedW NUMERIC "0"
|
|
||||||
// Retrieval info: PRIVATE: sc_aclr NUMERIC "0"
|
|
||||||
// Retrieval info: PRIVATE: sc_sclr NUMERIC "1"
|
|
||||||
// Retrieval info: PRIVATE: wsEmpty NUMERIC "0"
|
|
||||||
// Retrieval info: PRIVATE: wsFull NUMERIC "1"
|
|
||||||
// Retrieval info: PRIVATE: wsUsedW NUMERIC "0"
|
|
||||||
// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
|
|
||||||
// Retrieval info: CONSTANT: ADD_RAM_OUTPUT_REGISTER STRING "ON"
|
|
||||||
// Retrieval info: CONSTANT: ALMOST_EMPTY_VALUE NUMERIC "2"
|
|
||||||
// Retrieval info: CONSTANT: ALMOST_FULL_VALUE NUMERIC "1023"
|
|
||||||
// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "MAX 10"
|
|
||||||
// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "1024"
|
|
||||||
// Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "ON"
|
|
||||||
// Retrieval info: CONSTANT: LPM_TYPE STRING "scfifo"
|
|
||||||
// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "8"
|
|
||||||
// Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "10"
|
|
||||||
// Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON"
|
|
||||||
// Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON"
|
|
||||||
// Retrieval info: CONSTANT: USE_EAB STRING "ON"
|
|
||||||
// Retrieval info: USED_PORT: almost_empty 0 0 0 0 OUTPUT NODEFVAL "almost_empty"
|
|
||||||
// Retrieval info: USED_PORT: almost_full 0 0 0 0 OUTPUT NODEFVAL "almost_full"
|
|
||||||
// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL "clock"
|
|
||||||
// Retrieval info: USED_PORT: data 0 0 8 0 INPUT NODEFVAL "data[7..0]"
|
|
||||||
// Retrieval info: USED_PORT: empty 0 0 0 0 OUTPUT NODEFVAL "empty"
|
|
||||||
// Retrieval info: USED_PORT: full 0 0 0 0 OUTPUT NODEFVAL "full"
|
|
||||||
// Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL "q[7..0]"
|
|
||||||
// Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL "rdreq"
|
|
||||||
// Retrieval info: USED_PORT: sclr 0 0 0 0 INPUT NODEFVAL "sclr"
|
|
||||||
// Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL "wrreq"
|
|
||||||
// Retrieval info: CONNECT: @clock 0 0 0 0 clock 0 0 0 0
|
|
||||||
// Retrieval info: CONNECT: @data 0 0 8 0 data 0 0 8 0
|
|
||||||
// Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0
|
|
||||||
// Retrieval info: CONNECT: @sclr 0 0 0 0 sclr 0 0 0 0
|
|
||||||
// Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0
|
|
||||||
// Retrieval info: CONNECT: almost_empty 0 0 0 0 @almost_empty 0 0 0 0
|
|
||||||
// Retrieval info: CONNECT: almost_full 0 0 0 0 @almost_full 0 0 0 0
|
|
||||||
// Retrieval info: CONNECT: empty 0 0 0 0 @empty 0 0 0 0
|
|
||||||
// Retrieval info: CONNECT: full 0 0 0 0 @full 0 0 0 0
|
|
||||||
// Retrieval info: CONNECT: q 0 0 8 0 @q 0 0 8 0
|
|
||||||
// Retrieval info: GEN_FILE: TYPE_NORMAL fifo8.v TRUE
|
|
||||||
// Retrieval info: GEN_FILE: TYPE_NORMAL fifo8.inc FALSE
|
|
||||||
// Retrieval info: GEN_FILE: TYPE_NORMAL fifo8.cmp FALSE
|
|
||||||
// Retrieval info: GEN_FILE: TYPE_NORMAL fifo8.bsf FALSE
|
|
||||||
// Retrieval info: GEN_FILE: TYPE_NORMAL fifo8_inst.v FALSE
|
|
||||||
// Retrieval info: GEN_FILE: TYPE_NORMAL fifo8_bb.v FALSE
|
|
||||||
// Retrieval info: LIB_FILE: altera_mf
|
|
@ -1,445 +0,0 @@
|
|||||||
-- __ __ __ __ __ __
|
|
||||||
-- /\ "-.\ \ /\ \/\ \ /\ \ /\ \
|
|
||||||
-- \ \ \-. \ \ \ \_\ \ \ \ \____ \ \ \____
|
|
||||||
-- \ \_\\"\_\ \ \_____\ \ \_____\ \ \_____\
|
|
||||||
-- \/_/ \/_/ \/_____/ \/_____/ \/_____/
|
|
||||||
-- ______ ______ __ ______ ______ ______
|
|
||||||
-- /\ __ \ /\ == \ /\ \ /\ ___\ /\ ___\ /\__ _\
|
|
||||||
-- \ \ \/\ \ \ \ __< _\_\ \ \ \ __\ \ \ \____ \/_/\ \/
|
|
||||||
-- \ \_____\ \ \_____\ /\_____\ \ \_____\ \ \_____\ \ \_\
|
|
||||||
-- \/_____/ \/_____/ \/_____/ \/_____/ \/_____/ \/_/
|
|
||||||
--
|
|
||||||
-- https://joshbassett.info
|
|
||||||
-- https://twitter.com/nullobject
|
|
||||||
-- https://github.com/nullobject
|
|
||||||
--
|
|
||||||
-- Copyright (c) 2020 Josh Bassett
|
|
||||||
--
|
|
||||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
-- of this software and associated documentation files (the "Software"), to deal
|
|
||||||
-- in the Software without restriction, including without limitation the rights
|
|
||||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
-- copies of the Software, and to permit persons to whom the Software is
|
|
||||||
-- furnished to do so, subject to the following conditions:
|
|
||||||
--
|
|
||||||
-- The above copyright notice and this permission notice shall be included in all
|
|
||||||
-- copies or substantial portions of the Software.
|
|
||||||
--
|
|
||||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
-- SOFTWARE.
|
|
||||||
|
|
||||||
library ieee;
|
|
||||||
use ieee.std_logic_1164.all;
|
|
||||||
use ieee.numeric_std.all;
|
|
||||||
use ieee.math_real.all;
|
|
||||||
|
|
||||||
-- This SDRAM controller provides a symmetric 32-bit synchronous read/write
|
|
||||||
-- interface for a 16Mx16-bit SDRAM chip (e.g. AS4C16M16SA-6TCN, IS42S16400F,
|
|
||||||
-- etc.).
|
|
||||||
entity sdram is
|
|
||||||
generic (
|
|
||||||
-- clock frequency (in MHz)
|
|
||||||
--
|
|
||||||
-- This value must be provided, as it is used to calculate the number of
|
|
||||||
-- clock cycles required for the other timing values.
|
|
||||||
CLK_FREQ : real := 100.0;
|
|
||||||
|
|
||||||
-- 32-bit controller interface
|
|
||||||
ADDR_WIDTH : natural := 25;
|
|
||||||
DATA_WIDTH : natural := 32;
|
|
||||||
|
|
||||||
-- SDRAM interface
|
|
||||||
SDRAM_ADDR_WIDTH : natural := 13;
|
|
||||||
SDRAM_DATA_WIDTH : natural := 16;
|
|
||||||
SDRAM_COL_WIDTH : natural := 10;
|
|
||||||
SDRAM_ROW_WIDTH : natural := 13;
|
|
||||||
SDRAM_BANK_WIDTH : natural := 2;
|
|
||||||
|
|
||||||
-- The delay in clock cycles, between the start of a read command and the
|
|
||||||
-- availability of the output data.
|
|
||||||
CAS_LATENCY : natural := 2; -- 2=below 133MHz, 3=above 133MHz
|
|
||||||
|
|
||||||
-- The number of 16-bit words to be bursted during a read/write.
|
|
||||||
BURST_LENGTH : natural := 2;
|
|
||||||
|
|
||||||
-- timing values (in nanoseconds)
|
|
||||||
--
|
|
||||||
-- These values can be adjusted to match the exact timing of your SDRAM
|
|
||||||
-- chip (refer to the datasheet).
|
|
||||||
T_DESL : real := 100000.0; -- startup delay
|
|
||||||
T_MRD : real := 14.0; -- mode register cycle time
|
|
||||||
T_RC : real := 60.0; -- row cycle time
|
|
||||||
T_RCD : real := 15.0; -- RAS to CAS delay
|
|
||||||
T_RP : real := 15.0; -- precharge to activate delay
|
|
||||||
T_WR : real := 22.0; -- write recovery time
|
|
||||||
T_REFI : real := 7800.0 -- average refresh interval
|
|
||||||
);
|
|
||||||
port (
|
|
||||||
-- reset
|
|
||||||
reset : in std_logic := '0';
|
|
||||||
|
|
||||||
-- clock
|
|
||||||
clk : in std_logic;
|
|
||||||
|
|
||||||
-- address bus
|
|
||||||
addr : in unsigned(ADDR_WIDTH-1 downto 0);
|
|
||||||
|
|
||||||
-- input data bus
|
|
||||||
data : in std_logic_vector(DATA_WIDTH-1 downto 0);
|
|
||||||
|
|
||||||
-- When the write enable signal is asserted, a write operation will be performed.
|
|
||||||
we : in std_logic;
|
|
||||||
|
|
||||||
-- When the request signal is asserted, an operation will be performed.
|
|
||||||
req : in std_logic;
|
|
||||||
|
|
||||||
-- The acknowledge signal is asserted by the SDRAM controller when
|
|
||||||
-- a request has been accepted.
|
|
||||||
ack : out std_logic;
|
|
||||||
|
|
||||||
-- The valid signal is asserted when there is a valid word on the output
|
|
||||||
-- data bus.
|
|
||||||
valid : out std_logic;
|
|
||||||
|
|
||||||
-- output data bus
|
|
||||||
q : out std_logic_vector(DATA_WIDTH-1 downto 0);
|
|
||||||
|
|
||||||
-- SDRAM interface (e.g. AS4C16M16SA-6TCN, IS42S16400F, etc.)
|
|
||||||
sdram_a : out unsigned(SDRAM_ADDR_WIDTH-1 downto 0);
|
|
||||||
sdram_ba : out unsigned(SDRAM_BANK_WIDTH-1 downto 0);
|
|
||||||
sdram_dq : inout std_logic_vector(SDRAM_DATA_WIDTH-1 downto 0);
|
|
||||||
sdram_cke : out std_logic;
|
|
||||||
sdram_cs_n : out std_logic;
|
|
||||||
sdram_ras_n : out std_logic;
|
|
||||||
sdram_cas_n : out std_logic;
|
|
||||||
sdram_we_n : out std_logic;
|
|
||||||
sdram_dqml : out std_logic;
|
|
||||||
sdram_dqmh : out std_logic
|
|
||||||
);
|
|
||||||
end sdram;
|
|
||||||
|
|
||||||
architecture arch of sdram is
|
|
||||||
function ilog2(n : natural) return natural is
|
|
||||||
begin
|
|
||||||
return natural(ceil(log2(real(n))));
|
|
||||||
end ilog2;
|
|
||||||
|
|
||||||
subtype command_t is std_logic_vector(3 downto 0);
|
|
||||||
|
|
||||||
-- commands
|
|
||||||
constant CMD_DESELECT : command_t := "1---";
|
|
||||||
constant CMD_LOAD_MODE : command_t := "0000";
|
|
||||||
constant CMD_AUTO_REFRESH : command_t := "0001";
|
|
||||||
constant CMD_PRECHARGE : command_t := "0010";
|
|
||||||
constant CMD_ACTIVE : command_t := "0011";
|
|
||||||
constant CMD_WRITE : command_t := "0100";
|
|
||||||
constant CMD_READ : command_t := "0101";
|
|
||||||
constant CMD_STOP : command_t := "0110";
|
|
||||||
constant CMD_NOP : command_t := "0111";
|
|
||||||
|
|
||||||
-- the ordering of the accesses within a burst
|
|
||||||
constant BURST_TYPE : std_logic := '0'; -- 0=sequential, 1=interleaved
|
|
||||||
|
|
||||||
-- the write burst mode enables bursting for write operations
|
|
||||||
constant WRITE_BURST_MODE : std_logic := '0'; -- 0=burst, 1=single
|
|
||||||
|
|
||||||
-- the value written to the mode register to configure the memory
|
|
||||||
constant MODE_REG : unsigned(SDRAM_ADDR_WIDTH-1 downto 0) := (
|
|
||||||
"000" &
|
|
||||||
WRITE_BURST_MODE &
|
|
||||||
"00" &
|
|
||||||
to_unsigned(CAS_LATENCY, 3) &
|
|
||||||
BURST_TYPE &
|
|
||||||
to_unsigned(ilog2(BURST_LENGTH), 3)
|
|
||||||
);
|
|
||||||
|
|
||||||
-- calculate the clock period (in nanoseconds)
|
|
||||||
constant CLK_PERIOD : real := 1.0/CLK_FREQ*1000.0;
|
|
||||||
|
|
||||||
-- the number of clock cycles to wait before initialising the device
|
|
||||||
constant INIT_WAIT : natural := natural(ceil(T_DESL/CLK_PERIOD));
|
|
||||||
|
|
||||||
-- the number of clock cycles to wait while a LOAD MODE command is being
|
|
||||||
-- executed
|
|
||||||
constant LOAD_MODE_WAIT : natural := natural(ceil(T_MRD/CLK_PERIOD));
|
|
||||||
|
|
||||||
-- the number of clock cycles to wait while an ACTIVE command is being
|
|
||||||
-- executed
|
|
||||||
constant ACTIVE_WAIT : natural := natural(ceil(T_RCD/CLK_PERIOD));
|
|
||||||
|
|
||||||
-- the number of clock cycles to wait while a REFRESH command is being
|
|
||||||
-- executed
|
|
||||||
constant REFRESH_WAIT : natural := natural(ceil(T_RC/CLK_PERIOD));
|
|
||||||
|
|
||||||
-- the number of clock cycles to wait while a PRECHARGE command is being
|
|
||||||
-- executed
|
|
||||||
constant PRECHARGE_WAIT : natural := natural(ceil(T_RP/CLK_PERIOD));
|
|
||||||
|
|
||||||
-- the number of clock cycles to wait while a READ command is being executed
|
|
||||||
constant READ_WAIT : natural := CAS_LATENCY+BURST_LENGTH;
|
|
||||||
|
|
||||||
-- the number of clock cycles to wait while a WRITE command is being executed
|
|
||||||
constant WRITE_WAIT : natural := BURST_LENGTH+natural(ceil((T_WR+T_RP)/CLK_PERIOD));
|
|
||||||
|
|
||||||
-- the number of clock cycles before the memory controller needs to refresh
|
|
||||||
-- the SDRAM
|
|
||||||
constant REFRESH_INTERVAL : natural := natural(floor(T_REFI/CLK_PERIOD))-10;
|
|
||||||
|
|
||||||
type state_t is (INIT, MODE, IDLE, ACTIVE, READ, WRITE, REFRESH);
|
|
||||||
|
|
||||||
-- state signals
|
|
||||||
signal state, next_state : state_t;
|
|
||||||
|
|
||||||
-- command signals
|
|
||||||
signal cmd, next_cmd : command_t := CMD_NOP;
|
|
||||||
|
|
||||||
-- control signals
|
|
||||||
signal start : std_logic;
|
|
||||||
signal load_mode_done : std_logic;
|
|
||||||
signal active_done : std_logic;
|
|
||||||
signal refresh_done : std_logic;
|
|
||||||
signal first_word : std_logic;
|
|
||||||
signal read_done : std_logic;
|
|
||||||
signal write_done : std_logic;
|
|
||||||
signal should_refresh : std_logic;
|
|
||||||
|
|
||||||
-- counters
|
|
||||||
signal wait_counter : natural range 0 to 16383;
|
|
||||||
signal refresh_counter : natural range 0 to 1023;
|
|
||||||
|
|
||||||
-- registers
|
|
||||||
signal addr_reg : unsigned(SDRAM_COL_WIDTH+SDRAM_ROW_WIDTH+SDRAM_BANK_WIDTH-1 downto 0);
|
|
||||||
signal data_reg : std_logic_vector(DATA_WIDTH-1 downto 0);
|
|
||||||
signal we_reg : std_logic;
|
|
||||||
signal q_reg : std_logic_vector(DATA_WIDTH-1 downto 0);
|
|
||||||
|
|
||||||
-- aliases to decode the address register
|
|
||||||
alias col : unsigned(SDRAM_COL_WIDTH-1 downto 0) is addr_reg(SDRAM_COL_WIDTH-1 downto 0);
|
|
||||||
alias row : unsigned(SDRAM_ROW_WIDTH-1 downto 0) is addr_reg(SDRAM_COL_WIDTH+SDRAM_ROW_WIDTH-1 downto SDRAM_COL_WIDTH);
|
|
||||||
alias bank : unsigned(SDRAM_BANK_WIDTH-1 downto 0) is addr_reg(SDRAM_COL_WIDTH+SDRAM_ROW_WIDTH+SDRAM_BANK_WIDTH-1 downto SDRAM_COL_WIDTH+SDRAM_ROW_WIDTH);
|
|
||||||
begin
|
|
||||||
-- state machine
|
|
||||||
fsm : process (state, wait_counter, req, we_reg, load_mode_done, active_done, refresh_done, read_done, write_done, should_refresh)
|
|
||||||
begin
|
|
||||||
next_state <= state;
|
|
||||||
|
|
||||||
-- default to a NOP command
|
|
||||||
next_cmd <= CMD_NOP;
|
|
||||||
|
|
||||||
case state is
|
|
||||||
-- execute the initialisation sequence
|
|
||||||
when INIT =>
|
|
||||||
if wait_counter = 0 then
|
|
||||||
next_cmd <= CMD_DESELECT;
|
|
||||||
elsif wait_counter = INIT_WAIT-1 then
|
|
||||||
next_cmd <= CMD_PRECHARGE;
|
|
||||||
elsif wait_counter = INIT_WAIT+PRECHARGE_WAIT-1 then
|
|
||||||
next_cmd <= CMD_AUTO_REFRESH;
|
|
||||||
elsif wait_counter = INIT_WAIT+PRECHARGE_WAIT+REFRESH_WAIT-1 then
|
|
||||||
next_cmd <= CMD_AUTO_REFRESH;
|
|
||||||
elsif wait_counter = INIT_WAIT+PRECHARGE_WAIT+REFRESH_WAIT+REFRESH_WAIT-1 then
|
|
||||||
next_state <= MODE;
|
|
||||||
next_cmd <= CMD_LOAD_MODE;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
-- load the mode register
|
|
||||||
when MODE =>
|
|
||||||
if load_mode_done = '1' then
|
|
||||||
next_state <= IDLE;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
-- wait for a read/write request
|
|
||||||
when IDLE =>
|
|
||||||
if should_refresh = '1' then
|
|
||||||
next_state <= REFRESH;
|
|
||||||
next_cmd <= CMD_AUTO_REFRESH;
|
|
||||||
elsif req = '1' then
|
|
||||||
next_state <= ACTIVE;
|
|
||||||
next_cmd <= CMD_ACTIVE;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
-- activate the row
|
|
||||||
when ACTIVE =>
|
|
||||||
if active_done = '1' then
|
|
||||||
if we_reg = '1' then
|
|
||||||
next_state <= WRITE;
|
|
||||||
next_cmd <= CMD_WRITE;
|
|
||||||
else
|
|
||||||
next_state <= READ;
|
|
||||||
next_cmd <= CMD_READ;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
-- execute a read command
|
|
||||||
when READ =>
|
|
||||||
if read_done = '1' then
|
|
||||||
if should_refresh = '1' then
|
|
||||||
next_state <= REFRESH;
|
|
||||||
next_cmd <= CMD_AUTO_REFRESH;
|
|
||||||
elsif req = '1' then
|
|
||||||
next_state <= ACTIVE;
|
|
||||||
next_cmd <= CMD_ACTIVE;
|
|
||||||
else
|
|
||||||
next_state <= IDLE;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
-- execute a write command
|
|
||||||
when WRITE =>
|
|
||||||
if write_done = '1' then
|
|
||||||
if should_refresh = '1' then
|
|
||||||
next_state <= REFRESH;
|
|
||||||
next_cmd <= CMD_AUTO_REFRESH;
|
|
||||||
elsif req = '1' then
|
|
||||||
next_state <= ACTIVE;
|
|
||||||
next_cmd <= CMD_ACTIVE;
|
|
||||||
else
|
|
||||||
next_state <= IDLE;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
-- execute an auto refresh
|
|
||||||
when REFRESH =>
|
|
||||||
if refresh_done = '1' then
|
|
||||||
if req = '1' then
|
|
||||||
next_state <= ACTIVE;
|
|
||||||
next_cmd <= CMD_ACTIVE;
|
|
||||||
else
|
|
||||||
next_state <= IDLE;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
end case;
|
|
||||||
end process;
|
|
||||||
|
|
||||||
-- latch the next state
|
|
||||||
latch_next_state : process (clk, reset)
|
|
||||||
begin
|
|
||||||
if reset = '1' then
|
|
||||||
state <= INIT;
|
|
||||||
cmd <= CMD_NOP;
|
|
||||||
elsif rising_edge(clk) then
|
|
||||||
state <= next_state;
|
|
||||||
cmd <= next_cmd;
|
|
||||||
end if;
|
|
||||||
end process;
|
|
||||||
|
|
||||||
-- the wait counter is used to hold the current state for a number of clock
|
|
||||||
-- cycles
|
|
||||||
update_wait_counter : process (clk, reset)
|
|
||||||
begin
|
|
||||||
if reset = '1' then
|
|
||||||
wait_counter <= 0;
|
|
||||||
elsif rising_edge(clk) then
|
|
||||||
if state /= next_state then -- state changing
|
|
||||||
wait_counter <= 0;
|
|
||||||
else
|
|
||||||
wait_counter <= wait_counter + 1;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
end process;
|
|
||||||
|
|
||||||
-- the refresh counter is used to periodically trigger a refresh operation
|
|
||||||
update_refresh_counter : process (clk, reset)
|
|
||||||
begin
|
|
||||||
if reset = '1' then
|
|
||||||
refresh_counter <= 0;
|
|
||||||
elsif rising_edge(clk) then
|
|
||||||
if state = REFRESH and wait_counter = 0 then
|
|
||||||
refresh_counter <= 0;
|
|
||||||
else
|
|
||||||
refresh_counter <= refresh_counter + 1;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
end process;
|
|
||||||
|
|
||||||
-- latch the rquest
|
|
||||||
latch_request : process (clk)
|
|
||||||
begin
|
|
||||||
if rising_edge(clk) then
|
|
||||||
if start = '1' then
|
|
||||||
-- we need to multiply the address by two, because we are converting
|
|
||||||
-- from a 32-bit controller address to a 16-bit SDRAM address
|
|
||||||
addr_reg <= shift_left(resize(addr, addr_reg'length), 1);
|
|
||||||
data_reg <= data;
|
|
||||||
we_reg <= we;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
end process;
|
|
||||||
|
|
||||||
-- latch the output data as it's bursted from the SDRAM
|
|
||||||
latch_sdram_data : process (clk)
|
|
||||||
begin
|
|
||||||
if rising_edge(clk) then
|
|
||||||
valid <= '0';
|
|
||||||
|
|
||||||
if state = READ then
|
|
||||||
if first_word = '1' then
|
|
||||||
q_reg(31 downto 16) <= sdram_dq;
|
|
||||||
elsif read_done = '1' then
|
|
||||||
q_reg(15 downto 0) <= sdram_dq;
|
|
||||||
valid <= '1';
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
end process;
|
|
||||||
|
|
||||||
-- set wait signals
|
|
||||||
load_mode_done <= '1' when wait_counter = LOAD_MODE_WAIT-1 else '0';
|
|
||||||
active_done <= '1' when wait_counter = ACTIVE_WAIT-1 else '0';
|
|
||||||
refresh_done <= '1' when wait_counter = REFRESH_WAIT-1 else '0';
|
|
||||||
first_word <= '1' when wait_counter = CAS_LATENCY else '0';
|
|
||||||
read_done <= '1' when wait_counter = READ_WAIT-1 else '0';
|
|
||||||
write_done <= '1' when wait_counter = WRITE_WAIT-1 else '0';
|
|
||||||
|
|
||||||
-- the SDRAM should be refreshed when the refresh interval has elapsed
|
|
||||||
should_refresh <= '1' when refresh_counter >= REFRESH_INTERVAL-1 else '0';
|
|
||||||
|
|
||||||
-- a new request is only allowed at the end of the IDLE, READ, WRITE, and
|
|
||||||
-- REFRESH states
|
|
||||||
start <= '1' when (state = IDLE) or
|
|
||||||
(state = READ and read_done = '1') or
|
|
||||||
(state = WRITE and write_done = '1') or
|
|
||||||
(state = REFRESH and refresh_done = '1') else '0';
|
|
||||||
|
|
||||||
-- assert the acknowledge signal at the beginning of the ACTIVE state
|
|
||||||
ack <= '1' when state = ACTIVE and wait_counter = 0 else '0';
|
|
||||||
|
|
||||||
-- set output data
|
|
||||||
q <= q_reg;
|
|
||||||
|
|
||||||
-- deassert the clock enable at the beginning of the INIT state
|
|
||||||
sdram_cke <= '0' when state = INIT and wait_counter = 0 else '1';
|
|
||||||
|
|
||||||
-- set SDRAM control signals
|
|
||||||
(sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n) <= cmd;
|
|
||||||
|
|
||||||
-- set SDRAM bank
|
|
||||||
with state select
|
|
||||||
sdram_ba <=
|
|
||||||
bank when ACTIVE,
|
|
||||||
bank when READ,
|
|
||||||
bank when WRITE,
|
|
||||||
(others => '0') when others;
|
|
||||||
|
|
||||||
-- set SDRAM address
|
|
||||||
with state select
|
|
||||||
sdram_a <=
|
|
||||||
"0010000000000" when INIT,
|
|
||||||
MODE_REG when MODE,
|
|
||||||
row when ACTIVE,
|
|
||||||
"0010" & col when READ, -- auto precharge
|
|
||||||
"0010" & col when WRITE, -- auto precharge
|
|
||||||
(others => '0') when others;
|
|
||||||
|
|
||||||
-- decode the next 16-bit word from the write buffer
|
|
||||||
sdram_dq <= data_reg((BURST_LENGTH-wait_counter)*SDRAM_DATA_WIDTH-1 downto (BURST_LENGTH-wait_counter-1)*SDRAM_DATA_WIDTH) when state = WRITE else (others => 'Z');
|
|
||||||
|
|
||||||
-- set SDRAM data mask
|
|
||||||
sdram_dqmh <= '0';
|
|
||||||
sdram_dqml <= '0';
|
|
||||||
end architecture arch;
|
|
@ -1,46 +0,0 @@
|
|||||||
module usb_fifo #(
|
|
||||||
parameter FIFO_LENGTH = 1024,
|
|
||||||
parameter FIFO_WIDTH = 8
|
|
||||||
) (
|
|
||||||
if_system.sys system_if,
|
|
||||||
|
|
||||||
input flush,
|
|
||||||
|
|
||||||
output full,
|
|
||||||
input write,
|
|
||||||
input [(FIFO_WIDTH - 1):0] wdata,
|
|
||||||
|
|
||||||
output empty,
|
|
||||||
input read,
|
|
||||||
output reg [(FIFO_WIDTH - 1):0] rdata
|
|
||||||
);
|
|
||||||
|
|
||||||
localparam FIFO_ADDRESS_WIDTH = $clog2(FIFO_LENGTH);
|
|
||||||
|
|
||||||
reg [(FIFO_WIDTH - 1):0] r_fifo_mem [0:(FIFO_LENGTH - 1)];
|
|
||||||
|
|
||||||
reg [FIFO_ADDRESS_WIDTH:0] r_fifo_wrptr;
|
|
||||||
reg [FIFO_ADDRESS_WIDTH:0] r_fifo_rdptr;
|
|
||||||
|
|
||||||
wire w_full_or_empty = r_fifo_wrptr[(FIFO_ADDRESS_WIDTH - 1):0] == r_fifo_rdptr[(FIFO_ADDRESS_WIDTH - 1):0];
|
|
||||||
|
|
||||||
assign empty = r_fifo_wrptr == r_fifo_rdptr;
|
|
||||||
assign full = !empty && w_full_or_empty;
|
|
||||||
|
|
||||||
always_ff @(posedge system_if.clk) begin
|
|
||||||
rdata <= r_fifo_mem[r_fifo_rdptr[(FIFO_ADDRESS_WIDTH - 1):0]];
|
|
||||||
if (system_if.reset || flush) begin
|
|
||||||
r_fifo_wrptr <= {(FIFO_ADDRESS_WIDTH + 1){1'b0}};
|
|
||||||
r_fifo_rdptr <= {(FIFO_ADDRESS_WIDTH + 1){1'b0}};
|
|
||||||
end else begin
|
|
||||||
if (write) begin
|
|
||||||
r_fifo_mem[r_fifo_wrptr[(FIFO_ADDRESS_WIDTH - 1):0]] <= wdata;
|
|
||||||
r_fifo_wrptr <= r_fifo_wrptr + 1'd1;
|
|
||||||
end
|
|
||||||
if (read) begin
|
|
||||||
r_fifo_rdptr <= r_fifo_rdptr + 1'd1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
endmodule
|
|
Loading…
Reference in New Issue
Block a user