Resolve "Organize Project Better"
This commit is contained in:
24
hw/efinix_fpga/src/addr_decode.sv
Normal file
24
hw/efinix_fpga/src/addr_decode.sv
Normal file
@@ -0,0 +1,24 @@
|
||||
module addr_decode
|
||||
(
|
||||
input [15:0] i_addr,
|
||||
|
||||
output o_rom_cs,
|
||||
output o_leds_cs,
|
||||
output o_timer_cs,
|
||||
output o_multiplier_cs,
|
||||
output o_divider_cs,
|
||||
output o_uart_cs,
|
||||
output o_spi_cs,
|
||||
output o_sdram_cs
|
||||
);
|
||||
|
||||
assign o_rom_cs = i_addr >= 16'hf000 && i_addr <= 16'hffff;
|
||||
assign o_timer_cs = i_addr >= 16'heff8 && i_addr <= 16'heffb;
|
||||
assign o_multiplier_cs = i_addr >= 16'heff0 && i_addr <= 16'heff7;
|
||||
assign o_divider_cs = i_addr >= 16'hefe8 && i_addr <= 16'hefef;
|
||||
assign o_uart_cs = i_addr >= 16'hefe6 && i_addr <= 16'hefe7;
|
||||
assign o_spi_cs = i_addr >= 16'hefd8 && i_addr <= 16'hefdb;
|
||||
assign o_leds_cs = i_addr == 16'hefff;
|
||||
assign o_sdram_cs = i_addr < 16'he000;
|
||||
|
||||
endmodule
|
||||
106
hw/efinix_fpga/src/crc7.sv
Normal file
106
hw/efinix_fpga/src/crc7.sv
Normal file
@@ -0,0 +1,106 @@
|
||||
module crc7 #(parameter POLYNOMIAL = 8'h89)
|
||||
(
|
||||
input clk,
|
||||
input rst,
|
||||
|
||||
input load,
|
||||
input [39:0] data_in,
|
||||
|
||||
output logic [6:0] crc_out,
|
||||
output logic valid
|
||||
);
|
||||
|
||||
logic [46:0] data;
|
||||
logic [46:0] next_data;
|
||||
logic [46:0] polyshift;
|
||||
|
||||
typedef enum bit [1:0] {IDLE, WORKING, VALID} macro_t;
|
||||
struct packed {
|
||||
macro_t macro;
|
||||
logic [5:0] count;
|
||||
} state, next_state;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (rst) begin
|
||||
polyshift <= {POLYNOMIAL, 39'b0}; //start all the way at the left
|
||||
data <= '0;
|
||||
state.macro <= IDLE;
|
||||
state.count <= '0;
|
||||
end else begin
|
||||
if (load) begin
|
||||
data <= {data_in, 7'b0};
|
||||
end else begin
|
||||
data <= next_data;
|
||||
end
|
||||
state <= next_state;
|
||||
|
||||
if (state.macro == WORKING) begin
|
||||
polyshift <= polyshift >> 1;
|
||||
end
|
||||
|
||||
if (state.macro == VALID) begin
|
||||
polyshift <= {POLYNOMIAL, 39'b0};
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
next_state = state;
|
||||
|
||||
case (state.macro)
|
||||
IDLE: begin
|
||||
if (load) begin
|
||||
next_state.macro = WORKING;
|
||||
next_state.count = '0;
|
||||
end
|
||||
end
|
||||
|
||||
WORKING: begin
|
||||
if (state.count < 39) begin
|
||||
next_state.count = state.count + 6'b1;
|
||||
end else begin
|
||||
next_state.macro = VALID;
|
||||
next_state.count = '0;
|
||||
end
|
||||
end
|
||||
|
||||
VALID: begin // Same as IDLE, but IDLE is just for reset.
|
||||
if (load) begin
|
||||
next_state.macro = WORKING;
|
||||
next_state.count = '0;
|
||||
end
|
||||
end
|
||||
|
||||
default:;
|
||||
endcase
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
valid = 0;
|
||||
next_data = '0;
|
||||
crc_out = '0;
|
||||
|
||||
case (state.macro)
|
||||
IDLE: begin
|
||||
valid = 0;
|
||||
end
|
||||
|
||||
WORKING: begin
|
||||
if (data[6'd46 - state.count]) begin
|
||||
next_data = data ^ polyshift;
|
||||
end else begin
|
||||
next_data = data;
|
||||
end
|
||||
end
|
||||
|
||||
VALID: begin
|
||||
valid = ~load;
|
||||
next_data = data;
|
||||
crc_out = data[6:0];
|
||||
end
|
||||
|
||||
default:;
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
||||
92
hw/efinix_fpga/src/divider_wrapper.sv
Normal file
92
hw/efinix_fpga/src/divider_wrapper.sv
Normal file
@@ -0,0 +1,92 @@
|
||||
module divider_wrapper(
|
||||
input clk,
|
||||
input divclk,
|
||||
input reset,
|
||||
input [7:0] i_data,
|
||||
output logic [7:0] o_data,
|
||||
input cs,
|
||||
input rwb,
|
||||
input [2:0] addr
|
||||
);
|
||||
|
||||
logic [15:0] numer, denom;
|
||||
logic [15:0] quotient, remain;
|
||||
|
||||
logic [15:0] r_quotient, r_remain;
|
||||
|
||||
logic clken, rfd;
|
||||
|
||||
assign clken = '1;
|
||||
|
||||
|
||||
divider u_divider(
|
||||
.numer ( numer ),
|
||||
.denom ( denom ),
|
||||
.clken ( clken ),
|
||||
.clk ( divclk ),
|
||||
.reset ( reset ),
|
||||
.quotient ( quotient ),
|
||||
.remain ( remain ),
|
||||
.rfd ( rfd )
|
||||
);
|
||||
|
||||
|
||||
always_ff @(negedge clk) begin
|
||||
if (reset) begin
|
||||
numer <= '0;
|
||||
denom <= '0;
|
||||
end
|
||||
|
||||
|
||||
if (cs & ~rwb) begin
|
||||
case (addr)
|
||||
3'h0: begin
|
||||
numer[7:0] <= i_data;
|
||||
end
|
||||
|
||||
3'h1: begin
|
||||
numer[15:8] <= i_data;
|
||||
end
|
||||
|
||||
3'h2: begin
|
||||
denom[7:0] <= i_data;
|
||||
end
|
||||
|
||||
3'h3: begin
|
||||
denom[15:8] <= i_data;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge divclk) begin
|
||||
if (rfd) begin
|
||||
r_quotient <= quotient;
|
||||
r_remain <= remain;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
|
||||
case (addr)
|
||||
3'h4: begin
|
||||
o_data = r_quotient[7:0];
|
||||
end
|
||||
|
||||
3'h5: begin
|
||||
o_data = r_quotient[15:8];
|
||||
end
|
||||
|
||||
3'h6: begin
|
||||
o_data = r_remain[7:0];
|
||||
end
|
||||
|
||||
3'h7: begin
|
||||
o_data = r_remain[15:8];
|
||||
end
|
||||
|
||||
endcase
|
||||
|
||||
end
|
||||
|
||||
endmodule
|
||||
30
hw/efinix_fpga/src/interrupt_controller.sv
Normal file
30
hw/efinix_fpga/src/interrupt_controller.sv
Normal file
@@ -0,0 +1,30 @@
|
||||
module interrupt_controller
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
input [7:0] i_data,
|
||||
output logic [7:0] o_data,
|
||||
input cs,
|
||||
input rwb,
|
||||
|
||||
output logic irqb_master,
|
||||
|
||||
input irqb0, irqb1, irqb2, irqb3,
|
||||
input irqb4, irqb5, irqb6, irqb7
|
||||
);
|
||||
|
||||
|
||||
//All of the inputs are low level triggered.
|
||||
logic [7:0] irqbv;
|
||||
assign irqbv = {irqb0, irqb1, irqb2, irqb3, irqb4, irqb5, irqb6, irqb7};
|
||||
|
||||
always @(posedge clk) begin
|
||||
o_data <= irqbv;
|
||||
irqb_master = &irqbv;
|
||||
|
||||
if (cs & ~rwb) begin
|
||||
o_data <= o_data | i_data;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
24
hw/efinix_fpga/src/leds.sv
Normal file
24
hw/efinix_fpga/src/leds.sv
Normal file
@@ -0,0 +1,24 @@
|
||||
module leds
|
||||
(
|
||||
input clk,
|
||||
input [7:0] i_data,
|
||||
output logic [7:0] o_data,
|
||||
input cs,
|
||||
input rwb,
|
||||
|
||||
output logic [7:0] o_leds
|
||||
);
|
||||
|
||||
logic [7:0] _data;
|
||||
|
||||
assign o_leds = ~_data;
|
||||
|
||||
assign o_data = _data;
|
||||
|
||||
always @(negedge clk) begin
|
||||
if (~rwb & cs) begin
|
||||
_data <= i_data;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
46
hw/efinix_fpga/src/multiplier.sv
Normal file
46
hw/efinix_fpga/src/multiplier.sv
Normal file
@@ -0,0 +1,46 @@
|
||||
module multiplier(
|
||||
input clk,
|
||||
input reset,
|
||||
input [7:0] i_data,
|
||||
output logic [7:0] o_data,
|
||||
input cs,
|
||||
input rwb,
|
||||
input [2:0] addr
|
||||
);
|
||||
|
||||
logic [15:0] a, b;
|
||||
logic [31:0] out;
|
||||
|
||||
always_ff @(negedge clk) begin
|
||||
if (reset) begin
|
||||
a <= '0;
|
||||
b <= '0;
|
||||
end
|
||||
|
||||
|
||||
if (cs & ~rwb) begin
|
||||
case (addr)
|
||||
3'h0: begin
|
||||
a[7:0] <= i_data;
|
||||
end
|
||||
|
||||
3'h1: begin
|
||||
a[15:8] <= i_data;
|
||||
end
|
||||
|
||||
3'h2: begin
|
||||
b[7:0] <= i_data;
|
||||
end
|
||||
|
||||
3'h3: begin
|
||||
b[15:8] <= i_data;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
assign out = a * b;
|
||||
assign o_data = out[((addr-4)*8)+:8];
|
||||
|
||||
|
||||
endmodule
|
||||
49
hw/efinix_fpga/src/rom.sv
Normal file
49
hw/efinix_fpga/src/rom.sv
Normal file
@@ -0,0 +1,49 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2013-2018 Efinix Inc. All rights reserved.
|
||||
//
|
||||
// Single Port ROM
|
||||
//
|
||||
// *******************************
|
||||
// Revisions:
|
||||
// 0.0 Initial rev
|
||||
// 1.0 Finalized RTL macro
|
||||
// *******************************
|
||||
|
||||
module rom
|
||||
#(
|
||||
parameter DATA_WIDTH = 16,
|
||||
parameter ADDR_WIDTH = 8,
|
||||
parameter OUTPUT_REG = "FALSE",
|
||||
parameter RAM_INIT_FILE = "init_hex.mem"
|
||||
)
|
||||
(
|
||||
input [ADDR_WIDTH-1:0] addr,
|
||||
input clk,
|
||||
output [DATA_WIDTH-1:0] data
|
||||
);
|
||||
localparam MEMORY_DEPTH = 2**ADDR_WIDTH;
|
||||
|
||||
reg [DATA_WIDTH-1:0]r_rdata_1P;
|
||||
reg [DATA_WIDTH-1:0]r_rdata_2P;
|
||||
|
||||
reg [DATA_WIDTH-1:0] rom[MEMORY_DEPTH-1:0];
|
||||
|
||||
initial begin
|
||||
$readmemh(RAM_INIT_FILE, rom);
|
||||
end
|
||||
|
||||
always@(posedge clk)
|
||||
begin
|
||||
r_rdata_1P <= rom[addr];
|
||||
r_rdata_2P <= r_rdata_1P;
|
||||
end
|
||||
|
||||
generate
|
||||
if (OUTPUT_REG == "TRUE")
|
||||
assign data = r_rdata_2P;
|
||||
else
|
||||
assign data = r_rdata_1P;
|
||||
endgenerate
|
||||
|
||||
endmodule
|
||||
235
hw/efinix_fpga/src/sd_controller.sv
Normal file
235
hw/efinix_fpga/src/sd_controller.sv
Normal file
@@ -0,0 +1,235 @@
|
||||
module sd_controller(
|
||||
input clk,
|
||||
input sd_clk,
|
||||
input rst,
|
||||
|
||||
input [2:0] addr,
|
||||
input [7:0] data,
|
||||
input cs,
|
||||
input rw,
|
||||
|
||||
input i_sd_cmd,
|
||||
output logic o_sd_cmd,
|
||||
|
||||
input i_sd_data,
|
||||
output logic o_sd_data,
|
||||
|
||||
output logic [7:0] data_out
|
||||
);
|
||||
|
||||
logic [31:0] arg;
|
||||
logic [5:0] cmd;
|
||||
|
||||
logic [47:0] rxcmd_buf;
|
||||
logic [31:0] rx_val;
|
||||
|
||||
logic [7:0] rxdata_buf [512];
|
||||
logic [8:0] data_count;
|
||||
|
||||
logic [15:0] data_crc;
|
||||
|
||||
|
||||
assign rx_val = rxcmd_buf[39:8];
|
||||
|
||||
always_comb begin
|
||||
data_out = 'x;
|
||||
|
||||
if (addr < 4'h4) begin
|
||||
data_out = rx_val[8 * addr +: 8];
|
||||
end else if (addr == 4'h4) begin
|
||||
data_out = {data_flag, read_flag};
|
||||
end else if (addr == 4'h5) begin
|
||||
data_out = rxdata_buf[data_count];
|
||||
end
|
||||
end
|
||||
|
||||
logic read_flag, next_read_flag;
|
||||
logic data_flag, next_data_flag;
|
||||
|
||||
typedef enum bit [2:0] {IDLE, LOAD, CRC, TXCMD, RXCMD, TXDATA, RXDATA, RXDCRC} macro_t;
|
||||
struct packed {
|
||||
macro_t macro;
|
||||
logic [8:0] count;
|
||||
logic [2:0] d_bit_count;
|
||||
} state, next_state;
|
||||
|
||||
always_ff @(negedge clk) begin
|
||||
if (rst) begin
|
||||
state.macro <= IDLE;
|
||||
state.count <= '0;
|
||||
state.d_bit_count <= '1;
|
||||
read_flag <= '0;
|
||||
data_flag <= '0;
|
||||
data_count <= '0;
|
||||
end else begin
|
||||
if (state.macro == TXCMD || state.macro == CRC) begin
|
||||
if (sd_clk) begin
|
||||
state <= next_state;
|
||||
end
|
||||
end else if (state.macro == RXCMD || state.macro == RXDATA || state.macro == RXDCRC) begin
|
||||
if (~sd_clk) begin
|
||||
state <= next_state;
|
||||
end
|
||||
end else begin
|
||||
state <= next_state;
|
||||
end
|
||||
end
|
||||
|
||||
if (sd_clk) begin
|
||||
read_flag <= next_read_flag;
|
||||
data_flag <= next_data_flag;
|
||||
end
|
||||
|
||||
if (cs & ~rw) begin
|
||||
if (addr < 4'h4) begin
|
||||
arg[8 * addr +: 8] <= data;
|
||||
end else if (addr == 4'h4) begin
|
||||
cmd <= data[6:0];
|
||||
end
|
||||
end
|
||||
|
||||
if (cs & addr == 4'h5 && sd_clk) begin
|
||||
data_count <= data_count + 8'b1;
|
||||
end
|
||||
|
||||
if (state.macro == RXCMD) begin
|
||||
rxcmd_buf[6'd46-state.count] <= i_sd_cmd; //we probabily missed bit 47
|
||||
end
|
||||
|
||||
if (state.macro == RXDATA && ~sd_clk) begin
|
||||
rxdata_buf[state.count][state.d_bit_count] <= i_sd_data;
|
||||
end
|
||||
|
||||
if (state.macro == RXDCRC && ~sd_clk) begin
|
||||
data_crc[4'd15-state.count] <= i_sd_data;
|
||||
data_count <= '0;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
logic [6:0] crc;
|
||||
logic load_crc;
|
||||
logic crc_valid;
|
||||
logic [39:0] _packet;
|
||||
assign _packet = {1'b0, 1'b1, cmd, arg};
|
||||
logic [47:0] packet_crc;
|
||||
assign packet_crc = {_packet, crc, 1'b1};
|
||||
|
||||
crc7 u_crc7(
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.load(load_crc),
|
||||
.data_in(_packet),
|
||||
.crc_out(crc),
|
||||
.valid(crc_valid)
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
next_state = state;
|
||||
next_read_flag = read_flag;
|
||||
next_data_flag = data_flag;
|
||||
|
||||
case (state.macro)
|
||||
IDLE: begin
|
||||
if (~i_sd_cmd) begin // receive data if sd pulls cmd low
|
||||
next_state.macro = RXCMD;
|
||||
end
|
||||
|
||||
if (~i_sd_data) begin
|
||||
next_state.d_bit_count = '1;
|
||||
next_state.macro = RXDATA;
|
||||
end
|
||||
|
||||
if (addr == 4'h4 & cs & ~rw) begin // transmit if cpu writes to cmd
|
||||
next_state.macro = LOAD;
|
||||
end
|
||||
|
||||
if (addr == 4'h4 & cs & rw) begin
|
||||
next_read_flag = '0;
|
||||
end
|
||||
|
||||
if (addr == 4'h5 & cs) begin
|
||||
next_data_flag = '0;
|
||||
end
|
||||
end
|
||||
|
||||
LOAD: begin
|
||||
next_state.macro = CRC;
|
||||
end
|
||||
|
||||
CRC: begin
|
||||
next_state.macro = TXCMD;
|
||||
end
|
||||
|
||||
TXCMD: begin
|
||||
if (state.count < 47) begin
|
||||
next_state.count = state.count + 6'b1;
|
||||
end else begin
|
||||
next_state.macro = IDLE;
|
||||
next_state.count = '0;
|
||||
end
|
||||
end
|
||||
|
||||
RXCMD: begin
|
||||
if (state.count < 47) begin
|
||||
next_state.count = state.count + 6'b1;
|
||||
end else begin
|
||||
next_read_flag = '1;
|
||||
next_state.macro = IDLE;
|
||||
next_state.count = '0;
|
||||
end
|
||||
end
|
||||
|
||||
RXDATA: begin
|
||||
if (state.count < 511 || (state.count == 511 && state.d_bit_count > 0)) begin
|
||||
if (state.d_bit_count == 8'h0) begin
|
||||
next_state.count = state.count + 9'b1;
|
||||
end
|
||||
next_state.d_bit_count = state.d_bit_count - 3'h1;
|
||||
end else begin
|
||||
next_data_flag = '1;
|
||||
next_state.macro = RXDCRC;
|
||||
next_state.count = '0;
|
||||
end
|
||||
end
|
||||
|
||||
RXDCRC: begin
|
||||
if (state.count < 16) begin
|
||||
next_state.count = state.count + 9'b1;
|
||||
end else begin
|
||||
next_state.macro = IDLE;
|
||||
next_state.count = '0;
|
||||
end
|
||||
end
|
||||
|
||||
default: begin
|
||||
next_state.macro = IDLE;
|
||||
next_state.count = '0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
o_sd_cmd = '1; //default to 1
|
||||
o_sd_data = '1;
|
||||
|
||||
load_crc = '0;
|
||||
|
||||
case (state.macro)
|
||||
IDLE:;
|
||||
|
||||
CRC: begin
|
||||
load_crc = '1;
|
||||
end
|
||||
|
||||
TXCMD: begin
|
||||
o_sd_cmd = packet_crc[6'd47 - state.count];
|
||||
end
|
||||
|
||||
RXCMD:;
|
||||
|
||||
default:;
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
||||
303
hw/efinix_fpga/src/sdram_adapter.sv
Normal file
303
hw/efinix_fpga/src/sdram_adapter.sv
Normal file
@@ -0,0 +1,303 @@
|
||||
module sdram_adapter(
|
||||
input logic i_cpuclk,
|
||||
input logic i_arst, // Async Reset
|
||||
input logic i_sysclk, // Controller Clock (100MHz)
|
||||
input logic i_sdrclk, // t_su and t_wd clock (200MHz)
|
||||
input logic i_tACclk, // t_ac clock (200MHz)
|
||||
|
||||
input logic i_cs, // Chip select
|
||||
input logic i_rwb, // Read/Write. Write is low
|
||||
input logic [24:0] i_addr, // Input address. Byte addressed
|
||||
|
||||
input logic [7:0] i_data, // Input Data
|
||||
output logic [7:0] o_data, // Output data
|
||||
|
||||
output o_sdr_init_done,
|
||||
|
||||
output o_wait,
|
||||
|
||||
output o_sdr_CKE,
|
||||
output o_sdr_n_CS,
|
||||
output o_sdr_n_RAS,
|
||||
output o_sdr_n_CAS,
|
||||
output o_sdr_n_WE,
|
||||
output [1:0] o_sdr_BA,
|
||||
output [12:0] o_sdr_ADDR,
|
||||
output [15:0] o_sdr_DATA,
|
||||
output [15:0] o_sdr_DATA_oe,
|
||||
input [15:0] i_sdr_DATA,
|
||||
output [1:0] o_sdr_DQM
|
||||
);
|
||||
|
||||
logic [1:0] w_sdr_CKE;
|
||||
logic [1:0] w_sdr_n_CS;
|
||||
logic [1:0] w_sdr_n_RAS;
|
||||
logic [1:0] w_sdr_n_CAS;
|
||||
logic [1:0] w_sdr_n_WE;
|
||||
logic [3:0] w_sdr_BA;
|
||||
logic [25:0] w_sdr_ADDR;
|
||||
logic [31:0] w_sdr_DATA;
|
||||
logic [31:0] w_sdr_DATA_oe;
|
||||
logic [3:0] w_sdr_DQM;
|
||||
|
||||
assign o_sdr_CKE = w_sdr_CKE[0]; //Using SOFT ddio, ignore second cycle
|
||||
assign o_sdr_n_CS = w_sdr_n_CS[0];
|
||||
assign o_sdr_n_RAS = w_sdr_n_RAS[0];
|
||||
assign o_sdr_n_CAS = w_sdr_n_CAS[0];
|
||||
assign o_sdr_n_WE = w_sdr_n_WE[0];
|
||||
assign o_sdr_BA = w_sdr_BA[0+:2];
|
||||
assign o_sdr_ADDR = w_sdr_ADDR[0+:13];
|
||||
assign o_sdr_DATA = w_sdr_DATA[0+:16];
|
||||
assign o_sdr_DATA_oe = w_sdr_DATA_oe[0+:16];
|
||||
assign o_sdr_DQM = w_sdr_DQM[0+:2];
|
||||
|
||||
// What should happen when the cpu writes something?
|
||||
// 1. Address should already be calculated from the memory mapper, don't need to worry about it
|
||||
// 2. Data byte position needs to be determined. Each write is 32 bits, so the dm bits need to
|
||||
// be set and the byte shifted to the correct position
|
||||
// 3. write enable and last should be set high. Only ever do bursts of 1.
|
||||
// 4. Sample wr_ack and when it goes high, release write_enable and last
|
||||
|
||||
// What should happen when the cpu reads something?
|
||||
// 1. Address should already be calculated from the memory mapper, don't need to worry about it
|
||||
// 2. read_enable and last should be set high. Only ever to bursts of 1.
|
||||
// 3. Sample rd_ack and when it goes high, release read_enable and last
|
||||
// 4. Sample read_valid signal. When it is high, grab the data on the on the bus.
|
||||
// The returned data will be 16 bit, so you need to extract the correct byte. (or will it be 32?)
|
||||
|
||||
// when writing, the write data is only valid on a falling edge.
|
||||
// Really all of this should be done on falling edges.
|
||||
// But basically if we are in access, and cpuclk goes low, go back to wait.
|
||||
// If something actually happened, we would be in one of the read/write states.
|
||||
|
||||
enum bit [1:0] {ACCESS, READ_WAIT, WRITE_WAIT, WAIT} state, next_state;
|
||||
|
||||
logic w_read, w_write, w_last;
|
||||
logic [23:0] w_addr, r_addr;
|
||||
logic [31:0] w_data_i, w_data_o;
|
||||
logic [3:0] w_dm, r_dm;
|
||||
|
||||
logic w_wr_ack, w_rd_ack, w_rd_valid;
|
||||
|
||||
logic [7:0] data, _data;
|
||||
logic w_data_valid;
|
||||
|
||||
logic [31:0] r_write_data;
|
||||
|
||||
logic [1:0] counter, next_counter;
|
||||
|
||||
always @(posedge i_sysclk) begin
|
||||
if (i_arst) begin
|
||||
state <= WAIT;
|
||||
counter <= '0;
|
||||
end else begin
|
||||
state <= next_state;
|
||||
counter <= next_counter;
|
||||
r_write_data <= w_data_i;
|
||||
r_addr <= w_addr;
|
||||
r_dm <= w_dm;
|
||||
end
|
||||
|
||||
if (w_data_valid)
|
||||
o_data <= _data;
|
||||
end
|
||||
|
||||
logic r_wait;
|
||||
logic _r_wait;
|
||||
assign o_wait = r_wait;
|
||||
|
||||
// we need to assert rdy low until a falling edge if a reset happens
|
||||
|
||||
always @(posedge i_sysclk or posedge i_arst) begin
|
||||
if (i_arst == '1) begin
|
||||
r_wait <= '0;
|
||||
_r_wait <= '0;
|
||||
end else begin
|
||||
if (o_dbg_ref_req) begin
|
||||
r_wait <= '1;
|
||||
end else if (i_cpuclk == '1) begin
|
||||
_r_wait <= '1;
|
||||
end
|
||||
|
||||
if (i_cpuclk == '0) begin
|
||||
if (_r_wait) begin
|
||||
_r_wait <= '0;
|
||||
r_wait <= '0;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
//because of timing issues, We really need to trigger
|
||||
//the write on the falling edge of phi2. There is a 2ns
|
||||
//delay between the rising edge of phi2 and data valid
|
||||
//Since the address is valid on the previous falling edge,
|
||||
//Reads can occur on the rising edge I guess.
|
||||
|
||||
|
||||
//so basically cpu clock goes high when cs goes high we go into a priming state
|
||||
//where we wait until cs goes low. when cpu clock is low, do the actual write.
|
||||
|
||||
//in terms of the existing state, the access state needs to only do something
|
||||
//if selected AND cpu_clock is low. If cpu clock is high, we should be in wait,
|
||||
//and after the read/write is complete we should also go back to wait.
|
||||
|
||||
//actually that may only apply to writes, since reads should occur at the rising
|
||||
//edge of i_cpuclk
|
||||
|
||||
//Starts out in state 0 with cpuclk low and cs high.
|
||||
//Then, cpuclk goes high. This is now a valid time to read
|
||||
//After this, cpuclk goes low again, this is now a valid time to write.
|
||||
//so basically if cpuclk goes low when cs is low, go to wait state
|
||||
|
||||
//what I am thinking is basically 2 states like before. wait and access.
|
||||
//we go to access when cpuclk is high and cs is high.
|
||||
//we can read as soon as we want if rwn is high.
|
||||
//BUT if rwb is low then we have to wait untl cpuclk goes low again.
|
||||
|
||||
|
||||
always_comb begin
|
||||
next_state = state;
|
||||
next_counter = counter;
|
||||
|
||||
w_addr = '0;
|
||||
w_dm = '0;
|
||||
w_read = '0;
|
||||
w_write = '0;
|
||||
w_last = '0;
|
||||
w_data_i = '0;
|
||||
w_data_valid = '0;
|
||||
_data = 0;
|
||||
|
||||
unique case (state)
|
||||
WAIT: begin
|
||||
if (i_cs & i_cpuclk)
|
||||
next_state = ACCESS;
|
||||
end
|
||||
|
||||
ACCESS: begin
|
||||
// only do something if selected
|
||||
if (i_cs) begin
|
||||
w_addr = {{i_addr[24:2]}, {1'b0}};; // divide by 2, set last bit to 0
|
||||
|
||||
if (i_rwb) begin //read
|
||||
w_read = '1;
|
||||
w_last = '1;
|
||||
// dm is not needed for reads?
|
||||
if (w_rd_ack) next_state = READ_WAIT;
|
||||
end else begin //write
|
||||
w_data_i = i_data << (8*i_addr[1:0]);
|
||||
//w_data_i = {4{i_data}}; //does anything get through?
|
||||
w_dm = ~(4'b1 << i_addr[1:0]);
|
||||
if (~i_cpuclk) begin
|
||||
w_write = '1;
|
||||
w_last = '1;
|
||||
next_state = WRITE_WAIT;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
WRITE_WAIT: begin
|
||||
// stay in this state until write is acknowledged.
|
||||
w_write = '1;
|
||||
w_last = '1;
|
||||
w_data_i = r_write_data;
|
||||
w_dm = r_dm;
|
||||
w_addr = r_addr;
|
||||
if (w_wr_ack) next_state = WAIT;
|
||||
end
|
||||
|
||||
READ_WAIT: begin
|
||||
if (w_rd_valid) begin
|
||||
w_data_valid = '1;
|
||||
_data = w_data_o[8*i_addr[1:0]+:8];
|
||||
end
|
||||
|
||||
// you must wait until the next cycle!
|
||||
if (~i_cpuclk) begin
|
||||
next_state = WAIT;
|
||||
end
|
||||
end
|
||||
|
||||
endcase
|
||||
end
|
||||
|
||||
//this seems scuffed
|
||||
logic [23:0] addr_mux_out;
|
||||
always_comb begin
|
||||
if (state == ACCESS) begin
|
||||
addr_mux_out = w_addr;
|
||||
end else begin
|
||||
addr_mux_out = r_addr;
|
||||
end
|
||||
end
|
||||
|
||||
logic o_dbg_tRTW_done;
|
||||
logic o_dbg_ref_req;
|
||||
logic o_dbg_wr_ack;
|
||||
logic o_dbg_rd_ack;
|
||||
logic [1:0] o_dbg_n_CS;
|
||||
logic [1:0] o_dbg_n_RAS;
|
||||
logic [1:0] o_dbg_n_CAS;
|
||||
logic [1:0] o_dbg_n_WE;
|
||||
logic [3:0] o_dbg_BA;
|
||||
logic [25:0] o_dbg_ADDR;
|
||||
logic [31:0] o_dbg_DATA_out;
|
||||
logic [31:0] o_dbg_DATA_in;
|
||||
logic o_sdr_init_done;
|
||||
logic [3:0] o_sdr_state;
|
||||
|
||||
assign o_ref_req = o_dbg_ref_req;
|
||||
|
||||
|
||||
sdram_controller u_sdram_controller(
|
||||
.i_arst(i_arst), //Positive Controller Reset
|
||||
.i_sysclk(i_sysclk), //Controller Clock (100MHz)
|
||||
.i_sdrclk(i_sdrclk), //t_su and t_ac clock. Double sysclk (200MHz)
|
||||
.i_tACclk(i_tACclk), //t_ac clock. Also double sysclk, but different pll for tuning
|
||||
.i_pll_locked(1'b1), //There exists a pll locked output from the pll, not sure why they don't use it.
|
||||
|
||||
.i_we(w_write), //Write enable. Can only be de-asserted if i_last is asserted and o_wr_ack is sampled high.
|
||||
.i_re(w_read), //Read enable. Can only be de-asserted if i_last is asserted and o_rd_ack is sampled high.
|
||||
.i_last(w_last), //Set to high to indicate the last transfer of a burst write or read.
|
||||
.i_addr(addr_mux_out), //SDRAM physical address B R C. For half rate, only even addresses.
|
||||
.i_din(r_write_data), //Data to write to SDRAM. Twice normal width when running at half speed (hence the even addresses)
|
||||
.i_dm(r_dm), //dm (r_dm)
|
||||
.o_dout(w_data_o), //Data read from SDRAM, doubled as above.
|
||||
.o_sdr_init_done(o_sdr_init_done), //Indicates that the SDRAM initialization is done.
|
||||
.o_wr_ack(w_wr_ack), //Write acknowledge, handshake with we
|
||||
.o_rd_ack(w_rd_ack), //Read acknowledge, handshake with re
|
||||
.o_rd_valid(w_rd_valid),//Read valid. The data on o_dout is valid
|
||||
|
||||
.o_sdr_CKE(w_sdr_CKE),
|
||||
.o_sdr_n_CS(w_sdr_n_CS),
|
||||
.o_sdr_n_RAS(w_sdr_n_RAS),
|
||||
.o_sdr_n_CAS(w_sdr_n_CAS),
|
||||
.o_sdr_n_WE(w_sdr_n_WE),
|
||||
.o_sdr_BA(w_sdr_BA),
|
||||
.o_sdr_ADDR(w_sdr_ADDR),
|
||||
.o_sdr_DATA(w_sdr_DATA),
|
||||
.o_sdr_DATA_oe(w_sdr_DATA_oe),
|
||||
.i_sdr_DATA({{16'b0}, {i_sdr_DATA}}),
|
||||
.o_sdr_DQM(w_sdr_DQM),
|
||||
|
||||
//Does include debug signals.
|
||||
|
||||
.o_sdr_state(o_sdr_state),
|
||||
|
||||
.o_dbg_tRTW_done ( o_dbg_tRTW_done ),
|
||||
.o_dbg_ref_req ( o_dbg_ref_req ),
|
||||
.o_dbg_wr_ack ( o_dbg_wr_ack ),
|
||||
.o_dbg_rd_ack ( o_dbg_rd_ack ),
|
||||
.o_dbg_n_CS ( o_dbg_n_CS ),
|
||||
.o_dbg_n_RAS ( o_dbg_n_RAS ),
|
||||
.o_dbg_n_CAS ( o_dbg_n_CAS ),
|
||||
.o_dbg_n_WE ( o_dbg_n_WE ),
|
||||
.o_dbg_BA ( o_dbg_BA ),
|
||||
.o_dbg_ADDR ( o_dbg_ADDR ),
|
||||
.o_dbg_DATA_out ( o_dbg_DATA_out ),
|
||||
.o_dbg_DATA_in ( o_dbg_DATA_in )
|
||||
);
|
||||
|
||||
endmodule
|
||||
97
hw/efinix_fpga/src/spi_controller.sv
Normal file
97
hw/efinix_fpga/src/spi_controller.sv
Normal file
@@ -0,0 +1,97 @@
|
||||
module spi_controller(
|
||||
input i_clk,
|
||||
input i_rst,
|
||||
|
||||
input i_cs,
|
||||
input i_rwb,
|
||||
input [1:0] i_addr,
|
||||
input [7:0] i_data,
|
||||
output logic [7:0] o_data,
|
||||
|
||||
output o_spi_cs,
|
||||
output o_spi_clk,
|
||||
output o_spi_mosi,
|
||||
input i_spi_miso
|
||||
);
|
||||
|
||||
|
||||
// We need a speed register
|
||||
// an input data register
|
||||
// and an output data register
|
||||
// and then a control register for cs
|
||||
|
||||
logic [7:0] r_baud_rate;
|
||||
logic [7:0] r_input_data;
|
||||
logic [7:0] r_output_data;
|
||||
logic [7:0] r_control;
|
||||
|
||||
logic [8:0] r_clock_counter;
|
||||
|
||||
logic active;
|
||||
logic [2:0] count;
|
||||
logic spi_clk;
|
||||
|
||||
logic r_spi_mosi;
|
||||
|
||||
assign o_spi_cs = ~r_control[0];
|
||||
assign o_spi_clk = spi_clk;
|
||||
assign o_spi_mosi = r_spi_mosi;
|
||||
|
||||
always @(negedge i_clk) begin
|
||||
if (i_rst) begin
|
||||
r_baud_rate <= 8'h1;
|
||||
r_input_data <= '0;
|
||||
r_output_data <= '0;
|
||||
r_control <= '0;
|
||||
r_clock_counter <= '0;
|
||||
count <= '0;
|
||||
spi_clk <= '0;
|
||||
active <= '0;
|
||||
end else begin
|
||||
if (~i_rwb & i_cs) begin
|
||||
unique case (i_addr)
|
||||
0: r_baud_rate <= i_data;
|
||||
1:;
|
||||
2: begin
|
||||
r_output_data <= i_data;
|
||||
active <= '1;
|
||||
end
|
||||
3: r_control <= i_data;
|
||||
endcase
|
||||
end
|
||||
|
||||
if (active) begin
|
||||
r_spi_mosi <= r_output_data[7];
|
||||
r_clock_counter <= r_clock_counter + 9'b1;
|
||||
if (r_clock_counter >= r_baud_rate) begin
|
||||
r_clock_counter <= '0;
|
||||
spi_clk <= ~spi_clk;
|
||||
// rising edge
|
||||
if (spi_clk == '0) begin
|
||||
r_output_data <= r_output_data << 1;
|
||||
count <= count + 1;
|
||||
end
|
||||
// falling edge
|
||||
if (spi_clk == '1) begin
|
||||
r_input_data <= {r_input_data[6:0], i_spi_miso};
|
||||
if (count == '0) begin
|
||||
active <= '0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
unique case (i_addr)
|
||||
0: o_data = r_baud_rate;
|
||||
1: o_data = r_input_data;
|
||||
2:;
|
||||
3: o_data = {active, r_control[6:0]};
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
endmodule
|
||||
256
hw/efinix_fpga/src/super6502.sv
Normal file
256
hw/efinix_fpga/src/super6502.sv
Normal file
@@ -0,0 +1,256 @@
|
||||
module super6502
|
||||
(
|
||||
input logic i_sysclk, // Controller Clock (100MHz)
|
||||
input logic i_sdrclk, // t_su and t_wd clock (200MHz)
|
||||
input logic i_tACclk, // t_ac clock (200MHz)
|
||||
|
||||
input [7:0] cpu_data_in,
|
||||
input cpu_sync,
|
||||
input cpu_rwb,
|
||||
input pll_in,
|
||||
input button_reset,
|
||||
input pll_cpu_locked,
|
||||
input clk_50,
|
||||
input clk_2,
|
||||
input logic [15:0] cpu_addr,
|
||||
output logic [7:0] cpu_data_out,
|
||||
output logic [7:0] cpu_data_oe,
|
||||
output logic cpu_irqb,
|
||||
output logic cpu_nmib,
|
||||
output logic cpu_rdy,
|
||||
output logic cpu_resb,
|
||||
output logic pll_cpu_reset,
|
||||
output logic cpu_phi2,
|
||||
|
||||
output logic [7:0] leds,
|
||||
|
||||
output logic o_pll_reset,
|
||||
output logic o_sdr_CKE,
|
||||
output logic o_sdr_n_CS,
|
||||
output logic o_sdr_n_WE,
|
||||
output logic o_sdr_n_RAS,
|
||||
output logic o_sdr_n_CAS,
|
||||
output logic [1:0] o_sdr_BA,
|
||||
output logic [12:0] o_sdr_ADDR,
|
||||
input logic [15:0] i_sdr_DATA,
|
||||
output logic [15:0] o_sdr_DATA,
|
||||
output logic [15:0] o_sdr_DATA_oe,
|
||||
output logic [1:0] o_sdr_DQM,
|
||||
|
||||
input uart_rx,
|
||||
output uart_tx,
|
||||
|
||||
output sd_cs,
|
||||
output spi_clk,
|
||||
output spi_mosi,
|
||||
|
||||
input spi_miso
|
||||
);
|
||||
|
||||
assign pll_cpu_reset = '1;
|
||||
assign o_pll_reset = '1;
|
||||
|
||||
assign cpu_data_oe = {8{cpu_rwb}};
|
||||
assign cpu_nmib = '1;
|
||||
|
||||
logic w_wait;
|
||||
assign cpu_rdy = ~w_wait;
|
||||
|
||||
assign cpu_phi2 = clk_2;
|
||||
|
||||
logic w_sdr_init_done;
|
||||
|
||||
always @(posedge clk_2) begin
|
||||
if (button_reset == '0) begin
|
||||
cpu_resb <= '0;
|
||||
end
|
||||
else begin
|
||||
if (cpu_resb == '0 && w_sdr_init_done) begin
|
||||
cpu_resb <= '1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
logic w_rom_cs;
|
||||
logic w_leds_cs;
|
||||
logic w_sdram_cs;
|
||||
logic w_timer_cs;
|
||||
logic w_multiplier_cs;
|
||||
logic w_divider_cs;
|
||||
logic w_uart_cs;
|
||||
logic w_spi_cs;
|
||||
|
||||
addr_decode u_addr_decode(
|
||||
.i_addr(cpu_addr),
|
||||
.o_rom_cs(w_rom_cs),
|
||||
.o_leds_cs(w_leds_cs),
|
||||
.o_timer_cs(w_timer_cs),
|
||||
.o_multiplier_cs(w_multiplier_cs),
|
||||
.o_divider_cs(w_divider_cs),
|
||||
.o_uart_cs(w_uart_cs),
|
||||
.o_spi_cs(w_spi_cs),
|
||||
.o_sdram_cs(w_sdram_cs)
|
||||
);
|
||||
|
||||
logic [7:0] w_rom_data_out;
|
||||
logic [7:0] w_leds_data_out;
|
||||
logic [7:0] w_timer_data_out;
|
||||
logic [7:0] w_multiplier_data_out;
|
||||
logic [7:0] w_divider_data_out;
|
||||
logic [7:0] w_uart_data_out;
|
||||
logic [7:0] w_spi_data_out;
|
||||
logic [7:0] w_sdram_data_out;
|
||||
|
||||
always_comb begin
|
||||
if (w_rom_cs)
|
||||
cpu_data_out = w_rom_data_out;
|
||||
else if (w_leds_cs)
|
||||
cpu_data_out = w_leds_data_out;
|
||||
else if (w_timer_cs)
|
||||
cpu_data_out = w_timer_data_out;
|
||||
else if (w_multiplier_cs)
|
||||
cpu_data_out = w_multiplier_data_out;
|
||||
else if (w_divider_cs)
|
||||
cpu_data_out = w_divider_data_out;
|
||||
else if (w_uart_cs)
|
||||
cpu_data_out = w_uart_data_out;
|
||||
else if (w_spi_cs)
|
||||
cpu_data_out = w_spi_data_out;
|
||||
else if (w_sdram_cs)
|
||||
cpu_data_out = w_sdram_data_out;
|
||||
else
|
||||
cpu_data_out = 'x;
|
||||
end
|
||||
|
||||
rom #(.DATA_WIDTH(8), .ADDR_WIDTH(12)) u_rom(
|
||||
.addr(cpu_addr[11:0]),
|
||||
.clk(clk_2),
|
||||
.data(w_rom_data_out)
|
||||
);
|
||||
|
||||
leds u_leds(
|
||||
.clk(clk_2),
|
||||
.i_data(cpu_data_in),
|
||||
.o_data(w_leds_data_out),
|
||||
.cs(w_leds_cs),
|
||||
.rwb(cpu_rwb),
|
||||
.o_leds(leds)
|
||||
);
|
||||
|
||||
logic w_timer_irqb;
|
||||
|
||||
timer u_timer(
|
||||
.clk(clk_2),
|
||||
.reset(~cpu_resb),
|
||||
.i_data(cpu_data_in),
|
||||
.o_data(w_timer_data_out),
|
||||
.cs(w_timer_cs),
|
||||
.rwb(cpu_rwb),
|
||||
.addr(cpu_addr[1:0]),
|
||||
.irqb(w_timer_irqb)
|
||||
);
|
||||
|
||||
multiplier u_multiplier(
|
||||
.clk(clk_2),
|
||||
.reset(~cpu_resb),
|
||||
.i_data(cpu_data_in),
|
||||
.o_data(w_multiplier_data_out),
|
||||
.cs(w_multiplier_cs),
|
||||
.rwb(cpu_rwb),
|
||||
.addr(cpu_addr[2:0])
|
||||
);
|
||||
|
||||
divider_wrapper u_divider(
|
||||
.clk(clk_2),
|
||||
.divclk(clk_50),
|
||||
.reset(~cpu_resb),
|
||||
.i_data(cpu_data_in),
|
||||
.o_data(w_divider_data_out),
|
||||
.cs(w_divider_cs),
|
||||
.rwb(cpu_rwb),
|
||||
.addr(cpu_addr[2:0])
|
||||
);
|
||||
|
||||
logic w_uart_irqb;
|
||||
|
||||
uart_wrapper u_uart(
|
||||
.clk(clk_2),
|
||||
.clk_50(clk_50),
|
||||
.reset(~cpu_resb),
|
||||
.i_data(cpu_data_in),
|
||||
.o_data(w_uart_data_out),
|
||||
.cs(w_uart_cs),
|
||||
.rwb(cpu_rwb),
|
||||
.addr(cpu_addr[0]),
|
||||
.rx_i(uart_rx),
|
||||
.tx_o(uart_tx),
|
||||
.irqb(w_uart_irqb)
|
||||
);
|
||||
|
||||
spi_controller spi_controller(
|
||||
.i_clk(clk_2),
|
||||
.i_rst(~cpu_resb),
|
||||
.i_cs(w_spi_cs),
|
||||
.i_rwb(cpu_rwb),
|
||||
.i_addr(cpu_addr[1:0]),
|
||||
.i_data(cpu_data_in),
|
||||
.o_data(w_spi_data_out),
|
||||
|
||||
.o_spi_cs(sd_cs),
|
||||
.o_spi_clk(spi_clk),
|
||||
.o_spi_mosi(spi_mosi),
|
||||
.i_spi_miso(spi_miso)
|
||||
);
|
||||
|
||||
|
||||
sdram_adapter u_sdram_adapter(
|
||||
.i_cpuclk(clk_2),
|
||||
.i_arst(~button_reset),
|
||||
.i_sysclk(i_sysclk),
|
||||
.i_sdrclk(i_sdrclk),
|
||||
.i_tACclk(i_tACclk),
|
||||
|
||||
.i_cs(w_sdram_cs),
|
||||
.i_rwb(cpu_rwb),
|
||||
|
||||
.i_addr(cpu_addr),
|
||||
.i_data(cpu_data_in),
|
||||
.o_data(w_sdram_data_out),
|
||||
|
||||
.o_sdr_init_done(w_sdr_init_done),
|
||||
.o_wait(w_wait),
|
||||
|
||||
.o_sdr_CKE(o_sdr_CKE),
|
||||
.o_sdr_n_CS(o_sdr_n_CS),
|
||||
.o_sdr_n_RAS(o_sdr_n_RAS),
|
||||
.o_sdr_n_CAS(o_sdr_n_CAS),
|
||||
.o_sdr_n_WE(o_sdr_n_WE),
|
||||
.o_sdr_BA(o_sdr_BA),
|
||||
.o_sdr_ADDR(o_sdr_ADDR),
|
||||
.o_sdr_DATA(o_sdr_DATA),
|
||||
.o_sdr_DATA_oe(o_sdr_DATA_oe),
|
||||
.i_sdr_DATA(i_sdr_DATA),
|
||||
.o_sdr_DQM(o_sdr_DQM)
|
||||
);
|
||||
|
||||
interrupt_controller u_interrupt_controller(
|
||||
.clk(clk_2),
|
||||
.reset(~cpu_resb),
|
||||
.i_data(cpu_data_in),
|
||||
.o_data(w_irq_data_out),
|
||||
.cs(w_irq_cs),
|
||||
.rwb(cpu_rwb),
|
||||
.irqb_master(cpu_irqb),
|
||||
.irqb0(w_timer_irqb),
|
||||
.irqb1('1),
|
||||
.irqb2('1),
|
||||
.irqb3('1),
|
||||
.irqb4('1),
|
||||
.irqb5('1),
|
||||
.irqb6('1),
|
||||
.irqb7('1)
|
||||
);
|
||||
|
||||
|
||||
endmodule
|
||||
131
hw/efinix_fpga/src/timer.sv
Normal file
131
hw/efinix_fpga/src/timer.sv
Normal file
@@ -0,0 +1,131 @@
|
||||
module timer
|
||||
(
|
||||
input clk,
|
||||
input reset,
|
||||
input [7:0] i_data,
|
||||
output logic [7:0] o_data,
|
||||
input cs,
|
||||
input rwb,
|
||||
input [1:0] addr,
|
||||
output logic irqb
|
||||
);
|
||||
|
||||
//new idea for timer:
|
||||
//it can either be oneshot or repeating
|
||||
//it can either cause an interrupt or not.
|
||||
//if you want it to do both, add another timer.
|
||||
|
||||
/*
|
||||
Addr Read Write
|
||||
0 Counter Low Latch Low
|
||||
1 Counter High Latch High
|
||||
2 Divisor Divisor
|
||||
3 Status Control
|
||||
*/
|
||||
|
||||
logic [15:0] timer_latch, timer_counter;
|
||||
|
||||
//control register
|
||||
// bit 0: Enable interrupts
|
||||
// bit 1: Enable 1 shot mode
|
||||
|
||||
//writing to latch low starts the timer
|
||||
|
||||
logic [7:0] divisor, status, control;
|
||||
|
||||
logic count_en;
|
||||
|
||||
assign status[0] = count_en;
|
||||
|
||||
logic [15:0] pulsecount;
|
||||
|
||||
//I think this should be negedge so that writes go through
|
||||
always @(negedge clk) begin
|
||||
if (reset) begin
|
||||
count_en = '0;
|
||||
timer_counter <= '0;
|
||||
pulsecount <= '0;
|
||||
timer_latch <= '1;
|
||||
divisor <= '0;
|
||||
control <= '0;
|
||||
irqb <= '1;
|
||||
end else begin
|
||||
|
||||
if (count_en) begin
|
||||
if (pulsecount[15:8] == divisor) begin
|
||||
timer_counter <= timer_counter + 16'b1;
|
||||
pulsecount <= '0;
|
||||
end else begin
|
||||
pulsecount <= pulsecount + 16'b1;
|
||||
end
|
||||
end
|
||||
|
||||
if (timer_counter == timer_latch) begin
|
||||
// if interrupts are enabled
|
||||
if (control[0]) begin
|
||||
irqb <= '0;
|
||||
end
|
||||
|
||||
// if oneshot mode is enabled
|
||||
if (control[1]) begin
|
||||
count_en <= '0;
|
||||
end else begin
|
||||
timer_counter <= '0;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if (cs & rwb) begin
|
||||
irqb <= '1;
|
||||
end
|
||||
|
||||
if (cs & ~rwb) begin
|
||||
case (addr)
|
||||
2'h0: begin
|
||||
count_en <= '1;
|
||||
timer_latch[7:0] <= i_data;
|
||||
end
|
||||
|
||||
2'h1: begin
|
||||
timer_latch[15:8] <= i_data;
|
||||
end
|
||||
|
||||
2'h2: begin
|
||||
divisor <= i_data;
|
||||
end
|
||||
|
||||
2'h3: begin
|
||||
control <= i_data;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
o_data = '0;
|
||||
|
||||
unique case (addr)
|
||||
2'h0: begin
|
||||
o_data = timer_counter[7:0];
|
||||
end
|
||||
|
||||
2'h1: begin
|
||||
o_data = timer_counter[15:8];
|
||||
end
|
||||
|
||||
2'h2: begin
|
||||
o_data = divisor;
|
||||
end
|
||||
|
||||
2'h3: begin
|
||||
o_data = status;
|
||||
end
|
||||
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
|
||||
endmodule
|
||||
118
hw/efinix_fpga/src/uart_wrapper.sv
Normal file
118
hw/efinix_fpga/src/uart_wrapper.sv
Normal file
@@ -0,0 +1,118 @@
|
||||
module uart_wrapper(
|
||||
input clk,
|
||||
input clk_50,
|
||||
input reset,
|
||||
input [7:0] i_data,
|
||||
output logic [7:0] o_data,
|
||||
input cs,
|
||||
input rwb,
|
||||
input addr,
|
||||
|
||||
input rx_i,
|
||||
output tx_o,
|
||||
|
||||
output logic irqb
|
||||
);
|
||||
|
||||
logic [7:0] status, control;
|
||||
|
||||
logic tx_busy, rx_busy;
|
||||
|
||||
logic rx_data_valid, rx_error, rx_parity_error;
|
||||
logic baud_x16_ce;
|
||||
|
||||
logic tx_en;
|
||||
|
||||
logic [7:0] tx_data, rx_data;
|
||||
|
||||
uart u_uart(
|
||||
.tx_o ( tx_o ),
|
||||
.rx_i ( rx_i ),
|
||||
.tx_busy ( tx_busy ),
|
||||
.rx_data ( rx_data ),
|
||||
.rx_data_valid ( rx_data_valid ),
|
||||
.rx_error ( rx_error ),
|
||||
.rx_parity_error ( rx_parity_error ),
|
||||
.rx_busy ( rx_busy ),
|
||||
.baud_x16_ce ( baud_x16_ce ),
|
||||
.clk ( clk_50 ),
|
||||
.reset ( reset ),
|
||||
.tx_data ( tx_data ),
|
||||
.baud_rate ( baud_rate ),
|
||||
.tx_en ( tx_en )
|
||||
);
|
||||
|
||||
enum bit [1:0] {READY, WAIT, TRANSMIT} state, next_state;
|
||||
|
||||
always_ff @(posedge clk_50) begin
|
||||
if (reset) begin
|
||||
state = READY;
|
||||
irqb <= '1;
|
||||
end else begin
|
||||
state <= next_state;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(negedge clk) begin
|
||||
status[1] <= tx_busy | tx_en;
|
||||
|
||||
status[0] <= status[0] | rx_data_valid;
|
||||
if (cs & ~addr & rwb) begin
|
||||
status[0] <= 0;
|
||||
end
|
||||
|
||||
if (cs & ~rwb) begin
|
||||
case (addr)
|
||||
1'b0: begin
|
||||
tx_data <= i_data;
|
||||
end
|
||||
|
||||
1'b1: begin
|
||||
control <= i_data;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
case (addr)
|
||||
1'b0: begin
|
||||
o_data = rx_data;
|
||||
end
|
||||
|
||||
1'b1: begin
|
||||
o_data = status;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
next_state = state;
|
||||
|
||||
tx_en = 1'b0;
|
||||
|
||||
case (state)
|
||||
READY: begin
|
||||
if (cs & ~rwb && addr == 1'b0) begin //write to transmit
|
||||
tx_en = 1'b1;
|
||||
next_state = WAIT;
|
||||
end
|
||||
end
|
||||
|
||||
WAIT: begin
|
||||
tx_en = 1'b1;
|
||||
if (tx_busy) begin
|
||||
next_state = TRANSMIT;
|
||||
end
|
||||
end
|
||||
|
||||
TRANSMIT: begin
|
||||
if (~tx_busy) begin
|
||||
next_state = READY;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user