almost working

This commit is contained in:
Polprzewodnikowy 2021-08-23 00:35:50 +02:00
parent 97b7291001
commit 5524487f80
16 changed files with 1131 additions and 1928 deletions

View File

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

View File

@ -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);
// }
// }
// }
// }

View File

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

View File

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

View File

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

View File

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

View File

@ -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,

View File

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

View File

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

View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

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

View File

@ -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;

View File

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