URL
https://opencores.org/ocsvn/s6soc/s6soc/trunk
Subversion Repositories s6soc
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 3 to Rev 4
- ↔ Reverse comparison
Rev 3 → Rev 4
/s6soc/trunk/rtl/wbpwmaudio.v
81,11 → 81,12
// Wishbone interface |
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, |
o_wb_ack, o_wb_stall, o_wb_data, |
o_pwm, o_int); |
parameter DEFAULT_RELOAD = 32'd1814, // about 44.1 kHz @ 80MHz |
o_pwm, o_aux, o_int); |
parameter DEFAULT_RELOAD = 12'd1814, // about 44.1 kHz @ 80MHz |
//DEFAULT_RELOAD = 32'd2268,//about 44.1 kHz @ 100MHz |
NAUX=2, // Dev control values |
VARIABLE_RATE=0; |
VARIABLE_RATE=0, |
TIMING_BITS=12; |
input i_clk; |
input i_wb_cyc, i_wb_stb, i_wb_we; |
input i_wb_addr; |
101,29 → 102,27
// How often shall we create an interrupt? Every reload_value clocks! |
// If VARIABLE_RATE==0, this value will never change and will be kept |
// at the default reload rate (44.1 kHz, for a 100 MHz clock) |
wire [(TIMING_BITS-1):0] w_reload_value; |
generate |
if (VARIABLE_RATE != 0) |
begin |
reg [31:0] r_reload_value; |
reg [(TIMING_BITS-1):0] r_reload_value; |
initial r_reload_value = DEFAULT_RELOAD; |
always @(posedge i_clk) // Data write |
if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr)&&(i_wb_we)) |
reload_value <= i_wb_data; |
wire [31:0] w_reload_value; |
r_reload_value <= i_wb_data[(TIMING_BITS-1):0]; |
assign w_reload_value = r_reload_value; |
end else begin |
wire [31:0] w_reload_value; |
assign w_reload_value = DEFAULT_RELOAD; |
end endgenerate |
|
reg [31:0] reload_value, timer; |
initial reload_value = DEFAULT_RELOAD; |
reg [(TIMING_BITS-1):0] timer; |
initial timer = DEFAULT_RELOAD; |
always @(posedge i_clk) |
if (timer == 0) |
timer <= reload_value; |
timer <= {{(32-TIMING_BITS){1'b0}}, w_reload_value }; |
else |
timer <= timer - 1; |
timer <= timer - {{(TIMING_BITS-1){1'b0}},1'b1}; |
|
reg [15:0] sample_out; |
always @(posedge i_clk) |
176,7 → 175,7
reg [31:0] r_wb_data; |
always @(posedge i_clk) |
if (i_wb_addr) |
r_wb_data <= reload_value; |
r_wb_data <= w_reload_value; |
else |
r_wb_data <= { {(12-NAUX){1'b0}}, o_aux, |
3'h0, o_int, sample_out }; |
/s6soc/trunk/rtl/rtclight.v
52,7 → 52,8
o_interrupt, |
// A once-per-day strobe on the last clock of the day |
o_ppd); |
parameter DEFAULT_SPEED = 32'd2814750; // 100 Mhz |
parameter DEFAULT_SPEED = 32'd2814750, |
CKBITS = 24; // 100 Mhz |
input i_clk; |
input i_wb_cyc, i_wb_stb, i_wb_we; |
input [2:0] i_wb_addr; |
62,7 → 63,8
output wire o_interrupt, o_ppd; |
|
reg [21:0] clock; |
reg [31:0] stopwatch, ckspeed; |
reg [31:0] stopwatch; |
reg [(CKBITS-1):0] ckspeed; |
reg [25:0] timer; |
|
wire ck_sel, tm_sel, sw_sel, sp_sel, al_sel; |
77,7 → 79,8
initial ck_carry = 1'b0; |
initial ck_counter = 40'h00; |
always @(posedge i_clk) |
{ ck_carry, ck_counter } <= ck_counter + { 8'h00, ckspeed }; |
{ ck_carry, ck_counter } <= ck_counter |
+ { {(8+32-CKBITS){1'b0}}, ckspeed }; |
|
wire ck_pps; |
reg ck_prepps, ck_ppm, ck_pph, ck_ppd; |
/s6soc/trunk/rtl/cpu/ziptimer.v
121,7 → 121,7
initial o_int = 1'b0; |
always @(posedge i_clk) |
if (i_ce) |
o_int <= (r_running)&&(r_value == { {(VW-1){1'b0}}, 1'b1 }); |
o_int<=(r_running)&&(r_value == {{(VW-1){1'b0}},1'b1 }); |
else |
o_int <= 1'b0; |
|
130,6 → 130,11
o_wb_ack <= (i_wb_cyc)&&(i_wb_stb); |
assign o_wb_stall = 1'b0; |
|
assign o_wb_data = { r_auto_reload, r_value }; |
generate |
if (VW < BW-1) |
assign o_wb_data = { r_auto_reload, r_value }; |
else |
assign o_wb_data = { r_auto_reload, {(BW-1-VW){1'b0}}, r_value }; |
endgenerate |
|
endmodule |
/s6soc/trunk/rtl/rxuart.v
1,9 → 1,8
///////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// Filename: rxuart.v |
// |
// Project: FPGA library development (Spartan 3E development board) |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: Receive and decode inputs from a single UART line. |
// |
60,20 → 59,32
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
// Copyright: 2015 |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// |
///////////////////////////////////////////////////////////////////////// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This software is the ownership of Gisselquist Technology, LLC, and as |
// such it is proprietary. It is provided without any warrantees, either |
// express or implied, so that it may be tested. Upon completion, I ask |
// that working code be returned and not further distributed beyond those |
// that it is originally offered to. |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// Thank you. |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
|
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// States: (@ baud counter == 0) |
// 0 First bit arrives |
// ..7 Bits arrive |
/s6soc/trunk/rtl/txuart.v
1,9 → 1,8
///////////////////////////////////////////////////////////////////////// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// Filename: txuart.v |
// |
// Project: FPGA library development (Spartan 3E development board) |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: Transmit outputs over a single UART line. |
// |
60,19 → 59,33
// Creator: Dan Gisselquist |
// Gisselquist Technology, LLC |
// |
// Copyright: 2015 |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// |
///////////////////////////////////////////////////////////////////////// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This software is the ownership of Gisselquist Technology, LLC, and as |
// such it is proprietary. It is provided without any warrantees, either |
// express or implied, so that it may be tested. Upon completion, I ask |
// that working code be returned and not further distributed beyond those |
// that it is originally offered to. |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// Thank you. |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
`define TXU_BIT_ZERO 4'h0 |
`define TXU_BIT_ONE 4'h1 |
`define TXU_BIT_TWO 4'h2 |
89,14 → 102,17
// `define TXU_START 4'hd // An unused state |
`define TXU_BREAK 4'he |
`define TXU_IDLE 4'hf |
|
module txuart(i_clk, i_reset, i_setup, i_break, i_wr, i_data, o_uart, o_busy); |
// |
// |
module txuart(i_clk, i_reset, i_setup, i_break, i_wr, i_data, o_uart, i_cts, o_busy); |
input i_clk, i_reset; |
input [29:0] i_setup; |
input i_break; |
input i_wr; |
input [7:0] i_data; |
output reg o_uart, o_busy; |
output reg o_uart; |
input i_cts; |
output wire o_busy; |
|
wire [27:0] clocks_per_baud, break_condition; |
wire [1:0] data_bits; |
114,9 → 130,10
reg [3:0] state; |
reg [7:0] lcl_data; |
reg calc_parity; |
reg r_busy; |
|
initial o_uart = 1'b1; |
initial o_busy = 1'b1; |
initial r_busy = 1'b1; |
initial state = `TXU_IDLE; |
// initial baud_counter = clocks_per_baud; |
always @(posedge i_clk) |
125,7 → 142,7
begin |
baud_counter <= clocks_per_baud; |
o_uart <= 1'b1; |
o_busy <= 1'b1; |
r_busy <= 1'b1; |
state <= `TXU_IDLE; |
lcl_data <= 8'h0; |
calc_parity <= 1'b0; |
135,15 → 152,15
o_uart <= 1'b0; |
state <= `TXU_BREAK; |
calc_parity <= 1'b0; |
o_busy <= 1'b1; |
r_busy <= 1'b1; |
end else if (baud_counter != 0) |
begin // o_busy needs to be set coming into here |
begin // r_busy needs to be set coming into here |
baud_counter <= baud_counter - 28'h01; |
o_busy <= 1'b1; |
r_busy <= 1'b1; |
end else if (state == `TXU_BREAK) |
begin |
state <= `TXU_IDLE; |
o_busy <= 1'b1; |
r_busy <= 1'b1; |
o_uart <= 1'b1; |
calc_parity <= 1'b0; |
// Give us two stop bits before becoming available |
153,10 → 170,10
// baud_counter <= 0; |
r_setup <= i_setup; |
calc_parity <= 1'b0; |
if ((i_wr)&&(~o_busy)) |
if ((i_wr)&&(~r_busy)) |
begin // Immediately start us off with a start bit |
o_uart <= 1'b0; |
o_busy <= 1'b1; |
r_busy <= 1'b1; |
case(data_bits) |
2'b00: state <= `TXU_BIT_ZERO; |
2'b01: state <= `TXU_BIT_ONE; |
167,7 → 184,7
baud_counter <= clocks_per_baud-28'h01; |
end else begin // Stay in idle |
o_uart <= 1'b1; |
o_busy <= 0; |
r_busy <= 0; |
// lcl_data is irrelevant |
// state <= state; |
end |
174,7 → 191,7
end else begin |
// One clock tick in each of these states ... |
baud_counter <= clocks_per_baud - 28'h01; |
o_busy <= 1'b1; |
r_busy <= 1'b1; |
if (state[3] == 0) // First 8 bits |
begin |
o_uart <= lcl_data[0]; |
203,7 → 220,7
begin |
state <= `TXU_IDLE; // Go back to idle |
o_uart <= 1'b1; |
// Still o_busy, since we need to wait |
// Still r_busy, since we need to wait |
// for the baud clock to finish counting |
// out this last bit. |
end |
210,8 → 227,7
end |
end |
|
// assign o_busy = (r_busy)||(~i_cts); |
assign o_busy = (r_busy); |
endmodule |
|
|
|
|
/s6soc/trunk/rtl/toplevel.v
1,8 → 1,59
`timescale 10ns / 100ps |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: toplevel.v |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: This is (supposed to be) the one Xilinx specific file in the |
// project. The idea is that all of the board specific logic, |
// the logic used in simulation, is kept in the busmaster.v file. It's |
// not quite true, since rxuart and txuart modules are instantiated here, |
// but it's mostly true. |
// |
// One thing that makes this module unique is that all of its inputs and |
// outputs must match those on the chip, as specified within the cmod.ucf |
// file (up one directory). |
// |
// Within this file you will find specific I/O for output pins, such as |
// the necessary adjustments to make an I2C port from GPIO pins, as well |
// as the clock management approach. |
// |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
module toplevel(i_clk_8mhz, |
o_qspi_cs_n, o_qspi_sck, io_qspi_dat, |
i_btn, o_led, o_pwm, o_pwm_shutdown_n, o_pwm_gain, |
i_uart, o_uart, |
i_uart, o_uart, i_uart_cts, o_uart_rts, |
i_kp_row, o_kp_col, |
i_gpio, o_gpio, |
io_scl, io_sda); |
21,6 → 72,9
// and our serial port |
input i_uart; |
output wire o_uart; |
// and it's associated control wires |
input i_uart_cts; |
output wire o_uart_rts; |
// Our keypad |
input [3:0] i_kp_row; |
output wire [3:0] o_kp_col; |
30,15 → 84,20
// and our I2C port |
inout io_scl, io_sda; |
|
///// |
wire ck_zero_0, clk_s; // intermediate_clk, intermediate_clk_n; |
|
// Clock frequency = (25 / 2) * 8Mhz |
// Clock period = 10 ns |
// |
// Clock management |
// |
// Generate a usable clock for the rest of the board to run at. |
// |
wire ck_zero_0, clk_s; |
|
// Clock frequency = (20 / 2) * 8Mhz = 80 MHz |
// Clock period = 12.5 ns |
DCM_SP #( |
.CLKDV_DIVIDE(2.0), |
.CLKFX_DIVIDE(2), |
.CLKFX_MULTIPLY(20), |
.CLKFX_DIVIDE(2), // Here's the divide by two |
.CLKFX_MULTIPLY(20), // and here's the multiply by 20 |
.CLKIN_DIVIDE_BY_2("FALSE"), |
.CLKIN_PERIOD(125.0), |
.CLKOUT_PHASE_SHIFT("NONE"), |
52,11 → 111,16
.CLK0(ck_zero_0), |
.CLKFB(ck_zero_0), |
.CLKFX(clk_s), |
// .CLKFX180(intermediate_clk_n), |
.PSEN(1'b0), |
.RST(1'b0)); |
|
// |
// Generate active-high reset. |
// |
// Actually, we don't. Instead, let this board reset through |
// the reconfiguration/power on process and we never use this |
// wire. |
// |
/* |
reg r_reset; |
initial r_reset = 1'b1; |
65,6 → 129,15
*/ |
assign reset_s = 1'b0; |
|
|
// |
// The UART serial interface |
// |
// Perhaps this should be part of our simulation model as well. |
// For historical reasons, internal to Gisselquist Technology, |
// this has remained separate from the simulation, allowing the |
// simulation to bypass whether or not these two functions work. |
// |
wire rx_stb, tx_stb; |
wire [7:0] rx_data, tx_data; |
wire tx_busy; |
72,13 → 145,22
|
wire rx_break, rx_parity_err, rx_frame_err, rx_ck_uart, tx_break; |
assign tx_break = 1'b0; |
rxuart rcvuart(clk_s, reset_s, uart_setup, i_uart, rx_stb, rx_data, |
rxuart rcvuart(clk_s, reset_s, uart_setup, |
i_uart, rx_stb, rx_data, |
rx_break, rx_parity_err, rx_frame_err, rx_ck_uart); |
txuart tcvuart(clk_s, reset_s, uart_setup, tx_break, tx_stb, tx_data, |
o_uart, tx_busy); |
o_uart, i_uart_cts, tx_busy); |
|
|
|
// |
// BUSMASTER |
// |
// Busmaster is so named because it contains the wishbone |
// interconnect that all of the internal devices are hung off of. |
// To reconfigure this device for another purpose, usually |
// the busmaster module (i.e. the interconnect) is all that needs |
// to be changed: either to add more devices, or to remove them. |
// |
wire [3:0] qspi_dat; |
wire [1:0] qspi_bmod; |
wire [15:0] w_gpio; |
85,7 → 167,7
|
busmaster masterbus(clk_s, reset_s, |
// External ... bus control (if enabled) |
rx_stb, rx_data, tx_stb, tx_data, tx_busy, |
rx_stb, rx_data, tx_stb, tx_data, tx_busy, o_uart_rts, |
// SPI/SD-card flash |
o_qspi_cs_n, o_qspi_sck, qspi_dat, io_qspi_dat, qspi_bmod, |
// Board lights and switches |
98,9 → 180,28
{ i_gpio, io_scl, io_sda }, w_gpio |
); |
|
// |
// Quad SPI support |
// |
// Supporting a Quad SPI port requires knowing which direction the |
// wires are going at each instant, whether the device is in full |
// Quad mode in, full quad mode out, or simply the normal SPI |
// port with one wire in and one wire out. This utilizes our |
// control wires (qspi_bmod) to set the output lines appropriately. |
// |
assign io_qspi_dat = (~qspi_bmod[1])?({2'b11,1'bz,qspi_dat[0]}) |
:((qspi_bmod[0])?(4'bzzzz):(qspi_dat[3:0])); |
|
// |
// I2C support |
// |
// Supporting I2C requires a couple quick adjustments to our |
// GPIO lines. Specifically, we'll allow that when the output |
// (i.e. w_gpio) pins are high, then the I2C lines float. They |
// will be (need to be) pulled up by a resistor in order to |
// match the I2C protocol, but this change makes them look/act |
// more like GPIO pins. |
// |
assign io_sda = (w_gpio[0]) ? 1'bz : 1'b0; |
assign io_scl = (w_gpio[1]) ? 1'bz : 1'b0; |
assign o_gpio[15:2] = w_gpio[15:2]; |
/s6soc/trunk/rtl/wbqspiflashp.v
0,0 → 1,1173
/////////////////////////////////////////////////////////////////////////// |
// |
// Filename: wbspiflashp.v |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: This is identical to the wbspiflash.v file, save only that this |
// provides a writable interface to the flash whereas the other |
// is configured to be read only. |
// |
// Creator: Dan Gisselquist |
// Gisselquist Technology, LLC |
// |
/////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
/////////////////////////////////////////////////////////////////////////// |
// |
`define WBQSPI_RESET 0 |
`define WBQSPI_RESET_QUADMODE 1 |
`define WBQSPI_IDLE 2 |
`define WBQSPI_RDIDLE 3 // Idle, but in fast read mode |
`define WBQSPI_WBDECODE 4 |
`define WBQSPI_RD_DUMMY 5 |
`define WBQSPI_QRD_ADDRESS 6 |
`define WBQSPI_QRD_DUMMY 7 |
`define WBQSPI_READ_CMD 8 |
`define WBQSPI_READ_DATA 9 |
`define WBQSPI_WAIT_TIL_RDIDLE 10 |
`define WBQSPI_READ_ID_CMD 11 |
`define WBQSPI_READ_ID 12 |
`define WBQSPI_READ_STATUS 13 |
`define WBQSPI_READ_CONFIG 14 |
`define WBQSPI_WAIT_TIL_IDLE 15 |
// |
// |
`ifndef READ_ONLY |
// |
`define WBQSPI_WAIT_WIP_CLEAR 16 |
`define WBQSPI_CHECK_WIP_CLEAR 17 |
`define WBQSPI_CHECK_WIP_DONE 18 |
`define WBQSPI_WEN 19 |
`define WBQSPI_PP 20 // Program page |
`define WBQSPI_QPP 21 // Program page, 4 bit mode |
`define WBQSPI_WR_DATA 22 |
`define WBQSPI_WR_BUS_CYCLE 23 |
`define WBQSPI_WRITE_STATUS 24 |
`define WBQSPI_WRITE_CONFIG 25 |
`define WBQSPI_ERASE_WEN 26 |
`define WBQSPI_ERASE_CMD 27 |
`define WBQSPI_ERASE_BLOCK 28 |
`define WBQSPI_CLEAR_STATUS 29 |
`define WBQSPI_IDLE_CHECK_WIP 30 |
// |
`endif |
|
module wbqspiflashp(i_clk_100mhz, |
// Internal wishbone connections |
i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we, |
i_wb_addr, i_wb_data, |
// Wishbone return values |
o_wb_ack, o_wb_stall, o_wb_data, |
// Quad Spi connections to the external device |
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat, |
o_interrupt); |
parameter ADDRESS_WIDTH=22; |
input i_clk_100mhz; |
// Wishbone, inputs first |
input i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we; |
input [(ADDRESS_WIDTH-3):0] i_wb_addr; |
input [31:0] i_wb_data; |
// then outputs |
output reg o_wb_ack; |
output reg o_wb_stall; |
output reg [31:0] o_wb_data; |
// Quad SPI control wires |
output wire o_qspi_sck, o_qspi_cs_n; |
output wire [1:0] o_qspi_mod; |
output wire [3:0] o_qspi_dat; |
input [3:0] i_qspi_dat; |
// Interrupt line |
output reg o_interrupt; |
// output wire [31:0] o_debug; |
|
reg spi_wr, spi_hold, spi_spd, spi_dir; |
reg [31:0] spi_in; |
reg [1:0] spi_len; |
wire [31:0] spi_out; |
wire spi_valid, spi_busy; |
wire w_qspi_sck, w_qspi_cs_n; |
wire [3:0] w_qspi_dat; |
wire [1:0] w_qspi_mod; |
// wire [22:0] spi_dbg; |
llqspi lldriver(i_clk_100mhz, |
spi_wr, spi_hold, spi_in, spi_len, spi_spd, spi_dir, |
spi_out, spi_valid, spi_busy, |
w_qspi_sck, w_qspi_cs_n, w_qspi_mod, w_qspi_dat, |
i_qspi_dat); |
|
// Erase status tracking |
reg write_in_progress, write_protect; |
reg [(ADDRESS_WIDTH-17):0] erased_sector; |
reg dirty_sector; |
initial begin |
write_in_progress = 1'b0; |
erased_sector = 0; |
dirty_sector = 1'b1; |
write_protect = 1'b1; |
end |
|
reg [7:0] last_status; |
reg quad_mode_enabled; |
reg spif_cmd, spif_override; |
reg [(ADDRESS_WIDTH-3):0] spif_addr; |
reg [31:0] spif_data; |
reg [5:0] state; |
reg spif_ctrl, spif_req; |
wire [(ADDRESS_WIDTH-17):0] spif_sector; |
assign spif_sector = spif_addr[(ADDRESS_WIDTH-3):14]; |
|
// assign o_debug = { spi_wr, spi_spd, spi_hold, state, spi_dbg }; |
|
initial state = `WBQSPI_RESET; |
initial o_wb_ack = 1'b0; |
initial o_wb_stall = 1'b1; |
initial spi_wr = 1'b0; |
initial spi_len = 2'b00; |
initial quad_mode_enabled = 1'b0; |
initial o_interrupt = 1'b0; |
always @(posedge i_clk_100mhz) |
begin |
spif_override <= 1'b0; |
if (state == `WBQSPI_RESET) |
begin |
// From a reset, we should |
// Enable the Quad I/O mode |
// Disable the Write protection bits in the status register |
// Chip should already be up and running, so we can start |
// immediately .... |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
spi_wr <= 1'b0; |
spi_hold <= 1'b0; |
spi_spd <= 1'b0; |
spi_dir <= 1'b0; |
last_status <= 8'h00; |
state <= `WBQSPI_RESET_QUADMODE; |
spif_req <= 1'b0; |
spif_override <= 1'b1; |
last_status <= 8'hfc; // |
// This guarantees that we aren't starting in quad |
// I/O mode, where the FPGA configuration scripts may |
// have left us. |
end else if (state == `WBQSPI_RESET_QUADMODE) |
begin |
// Okay, so here's the problem: we don't know whether or not |
// the Xilinx loader started us up in Quad Read I/O idle mode. |
// So, thus we need to |
// Not ready to handle the bus yet, so stall any requests |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
|
// Do something ... |
if (last_status == 8'h00) |
begin |
spif_override <= 1'b0; |
state <= `WBQSPI_IDLE; |
end else begin |
last_status <= last_status - 8'h1; |
spif_override <= 1'b1; |
spif_cmd <= last_status[3]; // Toggle CS_n |
spif_ctrl <= last_status[0]; // Toggle clock too |
end |
end else if (state == `WBQSPI_IDLE) |
begin |
o_interrupt <= 1'b0; |
o_wb_stall <= 1'b0; |
o_wb_ack <= 1'b0; |
spif_cmd <= i_wb_we; |
spif_addr <= i_wb_addr; |
spif_data <= i_wb_data; |
spif_ctrl <= (i_wb_ctrl_stb)&&(~i_wb_data_stb); |
spif_req <= (i_wb_ctrl_stb)||(i_wb_data_stb); |
spi_wr <= 1'b0; // Keep the port idle, unless told otherwise |
spi_hold <= 1'b0; |
spi_spd <= 1'b0; |
spi_dir <= 1'b0; // Write (for now, 'cause of cmd) |
// Data register access |
if ((i_wb_data_stb)&&(i_wb_cyc)) |
begin |
|
if (i_wb_we) // Request to write a page |
begin |
`ifdef READ_ONLY |
o_wb_ack <= 1'b1; |
o_wb_stall <= 1'b0; |
end else |
`else |
if((~write_protect)&&(~write_in_progress)) |
begin // 00 |
spi_wr <= 1'b1; |
spi_len <= 2'b00; // 8 bits |
// Send a write enable command |
spi_in <= { 8'h06, 24'h00 }; |
state <= `WBQSPI_WEN; |
|
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
end else if (write_protect) |
begin // whether or not write-in_progress ... |
// Do nothing on a write protect |
// violation |
// |
o_wb_ack <= 1'b1; |
o_wb_stall <= 1'b0; |
end else begin // write is in progress, wait |
// for it to complete |
state <= `WBQSPI_WAIT_WIP_CLEAR; |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
end |
end else if (~write_in_progress) |
`endif |
begin // Read access, normal mode(s) |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
spi_wr <= 1'b1; // Write cmd to device |
if (quad_mode_enabled) |
begin |
spi_in <= { 8'heb, |
{(24-ADDRESS_WIDTH){1'b0}}, |
i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00 }; |
state <= `WBQSPI_QRD_ADDRESS; |
spi_len <= 2'b00; // single byte, cmd only |
end else begin |
spi_in <= { 8'h0b, |
{(24-ADDRESS_WIDTH){1'b0}}, |
i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00 }; |
state <= `WBQSPI_RD_DUMMY; |
spi_len <= 2'b11; // cmd+addr,32bits |
end |
`ifndef READ_ONLY |
end else begin |
// A write is in progress ... need to stall |
// the bus until the write is complete. |
state <= `WBQSPI_WAIT_WIP_CLEAR; |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
`endif |
end |
end else if ((i_wb_cyc)&&(i_wb_ctrl_stb)&&(i_wb_we)) |
begin |
`ifdef READ_ONLY |
o_wb_ack <= 1'b1; |
o_wb_stall <= 1'b0; |
`else |
o_wb_stall <= 1'b1; |
case(i_wb_addr[1:0]) |
2'b00: begin // Erase command register |
write_protect <= ~i_wb_data[28]; |
o_wb_stall <= 1'b0; |
|
if((i_wb_data[31])&&(~write_in_progress)) |
begin |
// Command an erase--ack it immediately |
|
o_wb_ack <= 1'b1; |
o_wb_stall <= 1'b0; |
|
if ((i_wb_data[31])&&(~write_protect)) |
begin |
spi_wr <= 1'b1; |
spi_len <= 2'b00; |
// Send a write enable command |
spi_in <= { 8'h06, 24'h00 }; |
state <= `WBQSPI_ERASE_CMD; |
o_wb_stall <= 1'b1; |
end |
end else if (i_wb_data[31]) |
begin |
state <= `WBQSPI_WAIT_WIP_CLEAR; |
o_wb_ack <= 1'b1; |
o_wb_stall <= 1'b1; |
end else |
o_wb_ack <= 1'b1; |
o_wb_stall <= 1'b0; |
end |
2'b01: begin |
// Write the configuration register |
o_wb_ack <= 1'b1; |
o_wb_stall <= 1'b1; |
|
// Need to send a write enable command first |
spi_wr <= 1'b1; |
spi_len <= 2'b00; // 8 bits |
// Send a write enable command |
spi_in <= { 8'h06, 24'h00 }; |
state <= `WBQSPI_WRITE_CONFIG; |
end |
2'b10: begin |
// Write the status register |
o_wb_ack <= 1'b1; // Ack immediately |
o_wb_stall <= 1'b1; // Stall other cmds |
// Need to send a write enable command first |
spi_wr <= 1'b1; |
spi_len <= 2'b00; // 8 bits |
// Send a write enable command |
spi_in <= { 8'h06, 24'h00 }; |
state <= `WBQSPI_WRITE_STATUS; |
end |
2'b11: begin // Write the ID register??? makes no sense |
o_wb_ack <= 1'b1; |
o_wb_stall <= 1'b0; |
end |
endcase |
`endif |
end else if ((i_wb_cyc)&&(i_wb_ctrl_stb)) // &&(~i_wb_we)) |
begin |
case(i_wb_addr[1:0]) |
2'b00: begin // Read local register |
if (write_in_progress) // Read status |
begin// register, is write still in progress? |
state <= `WBQSPI_READ_STATUS; |
spi_wr <= 1'b1; |
spi_len <= 2'b01;// 8 bits out, 8 bits in |
spi_in <= { 8'h05, 24'h00}; |
|
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
end else begin // Return w/o talking to device |
o_wb_ack <= 1'b1; |
o_wb_stall <= 1'b0; |
o_wb_data <= { write_in_progress, |
dirty_sector, spi_busy, |
~write_protect, |
quad_mode_enabled, |
{(29-ADDRESS_WIDTH){1'b0}}, |
erased_sector, 14'h000 }; |
end end |
2'b01: begin // Read configuration register |
state <= `WBQSPI_READ_CONFIG; |
spi_wr <= 1'b1; |
spi_len <= 2'b01; |
spi_in <= { 8'h35, 24'h00}; |
|
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
end |
2'b10: begin // Read status register |
state <= `WBQSPI_READ_STATUS; |
spi_wr <= 1'b1; |
spi_len <= 2'b01; // 8 bits out, 8 bits in |
spi_in <= { 8'h05, 24'h00}; |
|
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
end |
2'b11: begin // Read ID register |
state <= `WBQSPI_READ_ID_CMD; |
spi_wr <= 1'b1; |
spi_len <= 2'b00; |
spi_in <= { 8'h9f, 24'h00}; |
|
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
end |
endcase |
`ifndef READ_ONLY |
end else if ((~i_wb_cyc)&&(write_in_progress)) |
begin |
state <= `WBQSPI_IDLE_CHECK_WIP; |
spi_wr <= 1'b1; |
spi_len <= 2'b01; // 8 bits out, 8 bits in |
spi_in <= { 8'h05, 24'h00}; |
|
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
`endif |
end |
end else if (state == `WBQSPI_RDIDLE) |
begin |
spi_wr <= 1'b0; |
o_wb_stall <= 1'b0; |
o_wb_ack <= 1'b0; |
spif_cmd <= i_wb_we; |
spif_addr <= i_wb_addr; |
spif_data <= i_wb_data; |
spif_ctrl <= (i_wb_ctrl_stb)&&(~i_wb_data_stb); |
spif_req <= (i_wb_ctrl_stb)||(i_wb_data_stb); |
spi_hold <= 1'b0; |
spi_spd<= 1'b1; |
spi_dir <= 1'b0; // Write (for now) |
if ((i_wb_cyc)&&(i_wb_data_stb)&&(~i_wb_we)) |
begin // Continue our read ... send the new address / mode |
o_wb_stall <= 1'b1; |
spi_wr <= 1'b1; |
spi_len <= 2'b10; // Write address, but not mode byte |
spi_in <= { {(24-ADDRESS_WIDTH){1'b0}}, |
i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00, 8'ha0 }; |
state <= `WBQSPI_QRD_DUMMY; |
end else if((i_wb_cyc)&&(i_wb_ctrl_stb)&&(~i_wb_we)&&(i_wb_addr[1:0] == 2'b00)) |
begin |
// A local read that doesn't touch the device, so leave |
// the device in its current state |
o_wb_stall <= 1'b0; |
o_wb_ack <= 1'b1; |
o_wb_data <= { write_in_progress, |
dirty_sector, spi_busy, |
~write_protect, |
quad_mode_enabled, |
{(29-ADDRESS_WIDTH){1'b0}}, |
erased_sector, 14'h000 }; |
end else if((i_wb_cyc)&&((i_wb_ctrl_stb)||(i_wb_data_stb))) |
begin // Need to release the device from quad mode for all else |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
spi_wr <= 1'b1; |
spi_len <= 2'b11; |
spi_in <= 32'h00; |
state <= `WBQSPI_WBDECODE; |
end |
end else if (state == `WBQSPI_WBDECODE) |
begin |
// We were in quad SPI read mode, and had to get out. |
// Now we've got a command (not data read) to read and |
// execute. Accomplish what we would've done while in the |
// IDLE state here, save only that we don't have to worry |
// about data reads, and we need to operate on a stored |
// version of the bus command |
o_wb_stall <= 1'b1; |
o_wb_ack <= 1'b0; |
spi_wr <= 1'b0; // Keep the port idle, unless told otherwise |
spi_hold <= 1'b0; |
spi_spd <= 1'b0; |
spi_dir <= 1'b0; |
spif_req<= (spif_req) && (i_wb_cyc); |
if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // only in full idle ... |
begin |
// Data register access |
if (~spif_ctrl) |
begin |
if (spif_cmd) // Request to write a page |
begin |
`ifdef READ_ONLY |
o_wb_ack <= spif_req; |
o_wb_stall <= 1'b0; |
state <= `WBQSPI_IDLE; |
`else |
if((~write_protect)&&(~write_in_progress)) |
begin // 00 |
spi_wr <= 1'b1; |
spi_len <= 2'b00; // 8 bits |
// Send a write enable command |
spi_in <= { 8'h06, 24'h00 }; |
state <= `WBQSPI_WEN; |
|
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
end else if (write_protect) |
begin // whether or not write-in_progress ... |
// Do nothing on a write protect |
// violation |
// |
o_wb_ack <= spif_req; |
o_wb_stall <= 1'b0; |
state <= `WBQSPI_IDLE; |
end else begin // write is in progress, wait |
// for it to complete |
state <= `WBQSPI_WAIT_WIP_CLEAR; |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
end |
// end else if (~write_in_progress) // always true |
// but ... we wouldn't get here on a normal read access |
`endif |
end else begin |
// Something's wrong, we should never |
// get here |
// Attempt to go to idle to recover |
state <= `WBQSPI_IDLE; |
end |
end else if ((spif_ctrl)&&(spif_cmd)) |
begin |
`ifdef READ_ONLY |
o_wb_ack <= spif_req; |
o_wb_stall <= 1'b0; |
state <= `WBQSPI_IDLE; |
`else |
o_wb_stall <= 1'b1; |
case(spif_addr[1:0]) |
2'b00: begin // Erase command register |
o_wb_ack <= spif_req; |
o_wb_stall <= 1'b0; |
state <= `WBQSPI_IDLE; |
write_protect <= ~spif_data[28]; |
// Are we commanding an erase? |
// We're in read mode, writes cannot |
// be in progress, so ... |
if (spif_data[31]) // Command an erase |
begin |
// Since we're not going back |
// to IDLE, we must stall the |
// bus here |
o_wb_stall <= 1'b1; |
spi_wr <= 1'b1; |
spi_len <= 2'b00; |
// Send a write enable command |
spi_in <= { 8'h06, 24'h00 }; |
state <= `WBQSPI_ERASE_CMD; |
end end |
2'b01: begin |
// Write the configuration register |
o_wb_ack <= spif_req; |
o_wb_stall <= 1'b1; |
|
// Need to send a write enable command first |
spi_wr <= 1'b1; |
spi_len <= 2'b00; // 8 bits |
// Send a write enable command |
spi_in <= { 8'h06, 24'h00 }; |
state <= `WBQSPI_WRITE_CONFIG; |
end |
2'b10: begin |
// Write the status register |
o_wb_ack <= spif_req; // Ack immediately |
o_wb_stall <= 1'b1; // Stall other cmds |
// Need to send a write enable command first |
spi_wr <= 1'b1; |
spi_len <= 2'b00; // 8 bits |
// Send a write enable command |
spi_in <= { 8'h06, 24'h00 }; |
state <= `WBQSPI_WRITE_STATUS; |
end |
2'b11: begin // Write the ID register??? makes no sense |
o_wb_ack <= spif_req; |
o_wb_stall <= 1'b0; |
state <= `WBQSPI_IDLE; |
end |
endcase |
`endif |
end else begin // on (~spif_we) |
case(spif_addr[1:0]) |
2'b00: begin // Read local register |
// Nonsense case--would've done this |
// already |
state <= `WBQSPI_IDLE; |
o_wb_ack <= spif_req; |
o_wb_stall <= 1'b0; |
end |
2'b01: begin // Read configuration register |
state <= `WBQSPI_READ_CONFIG; |
spi_wr <= 1'b1; |
spi_len <= 2'b01; |
spi_in <= { 8'h35, 24'h00}; |
|
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
end |
2'b10: begin // Read status register |
state <= `WBQSPI_READ_STATUS; |
spi_wr <= 1'b1; |
spi_len <= 2'b01; // 8 bits out, 8 bits in |
spi_in <= { 8'h05, 24'h00}; |
|
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
end |
2'b11: begin // Read ID register |
state <= `WBQSPI_READ_ID_CMD; |
spi_wr <= 1'b1; |
spi_len <= 2'b00; |
spi_in <= { 8'h9f, 24'h00}; |
|
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
end |
endcase |
end |
end |
// |
// |
// READ DATA section: for both data and commands |
// |
end else if (state == `WBQSPI_RD_DUMMY) |
begin |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
|
spi_wr <= 1'b1; // Non-stop |
// Need to read one byte of dummy data, |
// just to consume 8 clocks |
spi_in <= { 8'h00, 24'h00 }; |
spi_len <= 2'b00; // Read 8 bits |
spi_spd <= 1'b0; |
spi_hold <= 1'b0; |
spif_req<= (spif_req) && (i_wb_cyc); |
|
if ((~spi_busy)&&(~o_qspi_cs_n)) |
// Our command was accepted |
state <= `WBQSPI_READ_CMD; |
end else if (state == `WBQSPI_QRD_ADDRESS) |
begin |
// We come in here immediately upon issuing a QRD read |
// command (8-bits), but we have to pause to give the |
// address (24-bits) and mode (8-bits) in quad speed. |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
|
spi_wr <= 1'b1; // Non-stop |
spi_in <= { {(24-ADDRESS_WIDTH){1'b0}}, |
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00, 8'ha0 }; |
spi_len <= 2'b10; // Write address, not mode byte |
spi_spd <= 1'b1; |
spi_dir <= 1'b0; // Still writing |
spi_hold <= 1'b0; |
spif_req<= (spif_req) && (i_wb_cyc); |
|
if ((~spi_busy)&&(spi_spd)) |
// Our command was accepted |
state <= `WBQSPI_QRD_DUMMY; |
end else if (state == `WBQSPI_QRD_DUMMY) |
begin |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
|
spi_wr <= 1'b1; // Non-stop |
spi_in <= { 8'ha0, 24'h00 }; // Mode byte, then 2 bytes dummy |
spi_len <= 2'b10; // Write 8 bits |
spi_spd <= 1'b1; |
spi_dir <= 1'b0; // Still writing |
spi_hold <= 1'b0; |
spif_req<= (spif_req) && (i_wb_cyc); |
|
if ((~spi_busy)&&(spi_in[31:28] == 4'ha)) |
// Our command was accepted |
state <= `WBQSPI_READ_CMD; |
end else if (state == `WBQSPI_READ_CMD) |
begin // Issue our first command to read 32 bits. |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
|
spi_wr <= 1'b1; |
spi_in <= { 8'hff, 24'h00 }; // Empty |
spi_len <= 2'b11; // Read 32 bits |
spi_dir <= 1'b1; // Now reading |
spi_hold <= 1'b0; |
spif_req<= (spif_req) && (i_wb_cyc); |
if ((spi_valid)&&(spi_len == 2'b11)) |
state <= `WBQSPI_READ_DATA; |
end else if (state == `WBQSPI_READ_DATA) |
begin |
// Pipelined read support |
spi_wr <=((i_wb_cyc)&&(i_wb_data_stb)&&(~i_wb_we)&&(i_wb_addr== (spif_addr+1))); |
spi_in <= 32'h00; |
spi_len <= 2'b11; |
// Don't adjust the speed here, it was set in the setup |
spi_dir <= 1'b1; // Now we get to read |
// Don't let the device go to idle until the bus cycle ends. |
// This actually prevents a *really* nasty race condition, |
// where the strobe comes in after the lower level device |
// has decided to stop waiting. The write is then issued, |
// but no one is listening. By leaving the device open, |
// the device is kept in a state where a valid strobe |
// here will be useful. Of course, we don't accept |
// all commands, just reads. Further, the strobe needs |
// to be high for two clocks cycles without changing |
// anything on the bus--one for us to notice it and pull |
// our head out of the sand, and a second for whoever |
// owns the bus to realize their command went through. |
spi_hold <= 1'b1; |
spif_req<= (spif_req) && (i_wb_cyc); |
if ((spi_valid)&&(~spi_in[31])) |
begin // Single pulse acknowledge and write data out |
o_wb_ack <= spif_req; |
o_wb_stall <= (~spi_wr); |
// adjust endian-ness to match the PC |
o_wb_data <= { spi_out[7:0], spi_out[15:8], |
spi_out[23:16], spi_out[31:24] }; |
state <= (spi_wr)?`WBQSPI_READ_DATA |
: ((spi_spd) ? `WBQSPI_WAIT_TIL_RDIDLE : `WBQSPI_WAIT_TIL_IDLE); |
spif_req <= spi_wr; |
spi_hold <= (~spi_wr); |
if (spi_wr) |
spif_addr <= i_wb_addr; |
end else if (~i_wb_cyc) |
begin // FAIL SAFE: If the bus cycle ends, forget why we're |
// here, just go back to idle |
state <= ((spi_spd) ? `WBQSPI_WAIT_TIL_RDIDLE : `WBQSPI_WAIT_TIL_IDLE); |
spi_hold <= 1'b0; |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
end else begin |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
end |
end else if (state == `WBQSPI_WAIT_TIL_RDIDLE) |
begin // Wait 'til idle, but then go to fast read idle instead of full |
spi_wr <= 1'b0; // idle |
spi_hold <= 1'b0; |
o_wb_stall <= 1'b1; |
o_wb_ack <= 1'b0; |
spif_req <= 1'b0; |
if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // Wait for a full |
begin // clearing of the SPI port before moving on |
state <= `WBQSPI_RDIDLE; |
o_wb_stall <= 1'b0; |
o_wb_ack <= 1'b0;// Shouldn't be acking anything here |
end |
end else if (state == `WBQSPI_READ_ID_CMD) |
begin // We came into here immediately after issuing a 0x9f command |
// Now we need to read 32 bits of data. Result should be |
// 0x0102154d (8'h manufacture ID, 16'h device ID, followed |
// by the number of extended bytes available 8'h4d). |
o_wb_ack <= 1'b0; |
o_wb_stall<= 1'b1; |
|
spi_wr <= 1'b1; // No data to send, but need four bytes, since |
spi_len <= 2'b11; // 32 bits of data are ... useful |
spi_in <= 32'h00; // Irrelevant |
spi_spd <= 1'b0; // Slow speed |
spi_dir <= 1'b1; // Reading |
spi_hold <= 1'b0; |
spif_req <= (spif_req) && (i_wb_cyc); |
if ((~spi_busy)&&(~o_qspi_cs_n)&&(spi_len == 2'b11)) |
// Our command was accepted, now go read the result |
state <= `WBQSPI_READ_ID; |
end else if (state == `WBQSPI_READ_ID) |
begin |
o_wb_ack <= 1'b0; // Assuming we're still waiting |
o_wb_stall <= 1'b1; |
|
spi_wr <= 1'b0; // No more writes, we've already written the cmd |
spi_hold <= 1'b0; |
spif_req <= (spif_req) && (i_wb_cyc); |
|
// Here, we just wait until the result comes back |
// The problem is, the result may be the previous result. |
// So we use spi_len as an indicator |
spi_len <= 2'b00; |
if((spi_valid)&&(spi_len==2'b00)) |
begin // Put the results out as soon as possible |
o_wb_data <= spi_out[31:0]; |
o_wb_ack <= spif_req; |
spif_req <= 1'b0; |
end else if ((~spi_busy)&&(o_qspi_cs_n)) |
begin |
state <= `WBQSPI_IDLE; |
o_wb_stall <= 1'b0; |
end |
end else if (state == `WBQSPI_READ_STATUS) |
begin // We enter after the command has been given, for now just |
// read and return |
spi_wr <= 1'b0; |
o_wb_ack <= 1'b0; |
spi_hold <= 1'b0; |
spif_req <= (spif_req) && (i_wb_cyc); |
if (spi_valid) |
begin |
o_wb_ack <= spif_req; |
o_wb_stall <= 1'b1; |
spif_req <= 1'b0; |
last_status <= spi_out[7:0]; |
write_in_progress <= spi_out[0]; |
if (spif_addr[1:0] == 2'b00) // Local read, checking |
begin // status, 'cause we're writing |
o_wb_data <= { spi_out[0], |
dirty_sector, spi_busy, |
~write_protect, |
quad_mode_enabled, |
{(29-ADDRESS_WIDTH){1'b0}}, |
erased_sector, 14'h000 }; |
end else begin |
o_wb_data <= { 24'h00, spi_out[7:0] }; |
end |
end |
|
if ((~spi_busy)&&(~spi_wr)) |
state <= `WBQSPI_IDLE; |
end else if (state == `WBQSPI_READ_CONFIG) |
begin // We enter after the command has been given, for now just |
// read and return |
spi_wr <= 1'b0; |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
spi_hold <= 1'b0; |
spif_req <= (spif_req) && (i_wb_cyc); |
|
if (spi_valid) |
begin |
o_wb_data <= { 24'h00, spi_out[7:0] }; |
quad_mode_enabled <= spi_out[1]; |
end |
|
if ((~spi_busy)&&(~spi_wr)) |
begin |
state <= `WBQSPI_IDLE; |
o_wb_ack <= spif_req; |
o_wb_stall <= 1'b0; |
spif_req <= 1'b0; |
end |
|
// |
// |
// Write/erase data section |
// |
`ifndef READ_ONLY |
end else if (state == `WBQSPI_WAIT_WIP_CLEAR) |
begin |
o_wb_stall <= 1'b1; |
o_wb_ack <= 1'b0; |
spi_wr <= 1'b0; |
spif_req<= (spif_req) && (i_wb_cyc); |
if (~spi_busy) |
begin |
spi_wr <= 1'b1; |
spi_in <= { 8'h05, 24'h0000 }; |
spi_hold <= 1'b1; |
spi_len <= 2'b01; // 16 bits write, so we can read 8 |
state <= `WBQSPI_CHECK_WIP_CLEAR; |
spi_spd <= 1'b0; // Slow speed |
spi_dir <= 1'b0; |
end |
end else if (state == `WBQSPI_CHECK_WIP_CLEAR) |
begin |
o_wb_stall <= 1'b1; |
o_wb_ack <= 1'b0; |
// Repeat as often as necessary until we are clear |
spi_wr <= 1'b1; |
spi_in <= 32'h0000; // Values here are actually irrelevant |
spi_hold <= 1'b1; |
spi_len <= 2'b00; // One byte at a time |
spi_spd <= 1'b0; // Slow speed |
spi_dir <= 1'b0; |
spif_req<= (spif_req) && (i_wb_cyc); |
if ((spi_valid)&&(~spi_out[0])) |
begin |
state <= `WBQSPI_CHECK_WIP_DONE; |
spi_wr <= 1'b0; |
spi_hold <= 1'b0; |
write_in_progress <= 1'b0; |
last_status <= spi_out[7:0]; |
end |
end else if (state == `WBQSPI_CHECK_WIP_DONE) |
begin |
o_wb_stall <= 1'b1; |
o_wb_ack <= 1'b0; |
// Let's let the SPI port come back to a full idle, |
// and the chip select line go low before continuing |
spi_wr <= 1'b0; |
spi_len <= 2'b00; |
spi_hold <= 1'b0; |
spi_spd <= 1'b0; // Slow speed |
spi_dir <= 1'b0; |
spif_req<= (spif_req) && (i_wb_cyc); |
if ((o_qspi_cs_n)&&(~spi_busy)) // Chip select line is high, we can continue |
begin |
spi_wr <= 1'b0; |
spi_hold <= 1'b0; |
|
casez({ spif_cmd, spif_ctrl, spif_addr[1:0] }) |
4'b00??: begin // Read data from ... somewhere |
spi_wr <= 1'b1; // Write cmd to device |
if (quad_mode_enabled) |
begin |
spi_in <= { 8'heb, |
{(24-ADDRESS_WIDTH){1'b0}}, |
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 }; |
state <= `WBQSPI_QRD_ADDRESS; |
// spi_len <= 2'b00; // single byte, cmd only |
end else begin |
spi_in <= { 8'h0b, |
{(24-ADDRESS_WIDTH){1'b0}}, |
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 }; |
state <= `WBQSPI_RD_DUMMY; |
spi_len <= 2'b11; // Send cmd and addr |
end end |
4'b10??: begin // Write data to ... anywhere |
spi_wr <= 1'b1; |
spi_len <= 2'b00; // 8 bits |
// Send a write enable command |
spi_in <= { 8'h06, 24'h00 }; |
state <= `WBQSPI_WEN; |
end |
4'b0110: begin // Read status register |
state <= `WBQSPI_READ_STATUS; |
spi_wr <= 1'b1; |
spi_len <= 2'b01; // 8 bits out, 8 bits in |
spi_in <= { 8'h05, 24'h00}; |
end |
4'b0111: begin |
state <= `WBQSPI_READ_ID_CMD; |
spi_wr <= 1'b1; |
spi_len <= 2'b00; |
spi_in <= { 8'h9f, 24'h00}; |
end |
default: begin // |
o_wb_stall <= 1'b1; |
o_wb_ack <= spif_req; |
state <= `WBQSPI_WAIT_TIL_IDLE; |
end |
endcase |
// spif_cmd <= i_wb_we; |
// spif_addr <= i_wb_addr; |
// spif_data <= i_wb_data; |
// spif_ctrl <= (i_wb_ctrl_stb)&&(~i_wb_data_stb); |
// spi_wr <= 1'b0; // Keep the port idle, unless told otherwise |
end |
end else if (state == `WBQSPI_WEN) |
begin // We came here after issuing a write enable command |
spi_wr <= 1'b0; |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
spif_req<= (spif_req) && (i_wb_cyc); |
if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // Let's come to a full stop |
state <= (quad_mode_enabled)?`WBQSPI_QPP:`WBQSPI_PP; |
// state <= `WBQSPI_PP; |
end else if (state == `WBQSPI_PP) |
begin // We come here under a full stop / full port idle mode |
// Issue our command immediately |
spi_wr <= 1'b1; |
spi_in <= { 8'h02, |
{(24-ADDRESS_WIDTH){1'b0}}, |
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 }; |
spi_len <= 2'b11; |
spi_hold <= 1'b1; |
spi_spd <= 1'b0; |
spi_dir <= 1'b0; // Writing |
spif_req<= (spif_req) && (i_wb_cyc); |
|
// Once we get busy, move on |
if (spi_busy) |
state <= `WBQSPI_WR_DATA; |
if (spif_sector == erased_sector) |
dirty_sector <= 1'b1; |
end else if (state == `WBQSPI_QPP) |
begin // We come here under a full stop / full port idle mode |
// Issue our command immediately |
spi_wr <= 1'b1; |
spi_in <= { 8'h32, |
{(24-ADDRESS_WIDTH){1'b0}}, |
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 }; |
spi_len <= 2'b11; |
spi_hold <= 1'b1; |
spi_spd <= 1'b0; |
spi_dir <= 1'b0; // Writing |
spif_req<= (spif_req) && (i_wb_cyc); |
|
// Once we get busy, move on |
if (spi_busy) |
begin |
// spi_wr is irrelevant here ... |
// Set the speed value once, but wait til we get busy |
// to do so. |
spi_spd <= 1'b1; |
state <= `WBQSPI_WR_DATA; |
end |
if (spif_sector == erased_sector) |
dirty_sector <= 1'b1; |
end else if (state == `WBQSPI_WR_DATA) |
begin |
o_wb_stall <= 1'b1; |
o_wb_ack <= 1'b0; |
spi_wr <= 1'b1; // write without waiting |
spi_in <= { |
spif_data[ 7: 0], |
spif_data[15: 8], |
spif_data[23:16], |
spif_data[31:24] }; |
spi_len <= 2'b11; // Write 4 bytes |
spi_hold <= 1'b1; |
if (~spi_busy) |
begin |
o_wb_ack <= spif_req; // Ack when command given |
state <= `WBQSPI_WR_BUS_CYCLE; |
end |
spif_req<= (spif_req) && (i_wb_cyc); |
end else if (state == `WBQSPI_WR_BUS_CYCLE) |
begin |
o_wb_ack <= 1'b0; // Turn off our ack and stall flags |
o_wb_stall <= 1'b1; |
spi_wr <= 1'b0; |
spi_hold <= 1'b1; |
write_in_progress <= 1'b1; |
spif_req<= (spif_req) && (i_wb_cyc); |
if (~i_wb_cyc) |
begin |
state <= `WBQSPI_WAIT_TIL_IDLE; |
spi_hold <= 1'b0; |
end else if (spi_wr) |
begin // Give the SPI a chance to get busy on the last write |
// Do nothing here. |
end else if ((i_wb_data_stb)&&(i_wb_we) |
&&(i_wb_addr == (spif_addr+1)) |
&&(i_wb_addr[(ADDRESS_WIDTH-3):6]==spif_addr[(ADDRESS_WIDTH-3):6])) |
begin |
spif_cmd <= 1'b1; |
spif_data <= i_wb_data; |
spif_addr <= i_wb_addr; |
spif_ctrl <= 1'b0; |
spif_req<= 1'b1; |
// We'll keep the bus stalled on this request |
// for a while |
state <= `WBQSPI_WR_DATA; |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b0; |
end else if ((i_wb_data_stb|i_wb_ctrl_stb)&&(~o_wb_ack)) // Writing out of bounds |
begin |
spi_hold <= 1'b0; |
spi_wr <= 1'b0; |
state <= `WBQSPI_WAIT_TIL_IDLE; |
end // Otherwise we stay here |
end else if (state == `WBQSPI_WRITE_CONFIG) |
begin // We enter immediately after commanding a WEN |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
|
spi_len <= 2'b10; |
spi_in <= { 8'h01, last_status, spif_data[7:0], 8'h00 }; |
spi_wr <= 1'b0; |
spi_hold <= 1'b0; |
spif_req <= (spif_req) && (i_wb_cyc); |
if ((~spi_busy)&&(~spi_wr)) |
begin |
spi_wr <= 1'b1; |
state <= `WBQSPI_WAIT_TIL_IDLE; |
write_in_progress <= 1'b1; |
quad_mode_enabled <= spif_data[1]; |
end |
end else if (state == `WBQSPI_WRITE_STATUS) |
begin // We enter immediately after commanding a WEN |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
|
spi_len <= 2'b01; |
spi_in <= { 8'h01, spif_data[7:0], 16'h00 }; |
// last_status <= i_wb_data[7:0]; // We'll read this in a moment |
spi_wr <= 1'b0; |
spi_hold <= 1'b0; |
spif_req <= (spif_req) && (i_wb_cyc); |
if ((~spi_busy)&&(~spi_wr)) |
begin |
spi_wr <= 1'b1; |
last_status <= spif_data[7:0]; |
write_in_progress <= 1'b1; |
if(((last_status[6])||(last_status[5])) |
&&((~spif_data[6])&&(~spif_data[5]))) |
state <= `WBQSPI_CLEAR_STATUS; |
else |
state <= `WBQSPI_WAIT_TIL_IDLE; |
end |
end else if (state == `WBQSPI_ERASE_CMD) |
begin // Know that WIP is clear on entry, WEN has just been commanded |
spi_wr <= 1'b0; |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
spi_hold <= 1'b0; |
spi_spd <= 1'b0; |
spi_dir <= 1'b0; |
spif_req <= (spif_req) && (i_wb_cyc); |
|
// Here's the erase command |
spi_in <= { 8'hd8, 2'h0, spif_data[19:14], 14'h000, 2'b00 }; |
spi_len <= 2'b11; // 32 bit write |
// together with setting our copy of the WIP bit |
write_in_progress <= 1'b1; |
// keeping track of which sector we just erased |
erased_sector <= spif_data[(ADDRESS_WIDTH-3):14]; |
// and marking this erase sector as no longer dirty |
dirty_sector <= 1'b0; |
|
// Wait for a full stop before issuing this command |
if ((~spi_busy)&&(~spi_wr)&&(o_qspi_cs_n)) |
begin // When our command is accepted, move to the next state |
spi_wr <= 1'b1; |
state <= `WBQSPI_ERASE_BLOCK; |
end |
end else if (state == `WBQSPI_ERASE_BLOCK) |
begin |
spi_wr <= 1'b0; |
spi_hold <= 1'b0; |
o_wb_stall <= 1'b1; |
o_wb_ack <= 1'b0; |
spif_req <= (spif_req) && (i_wb_cyc); |
// When the port clears, we can head back to idle |
if ((~spi_busy)&&(~spi_wr)) |
begin |
o_wb_ack <= spif_req; |
state <= `WBQSPI_IDLE; |
end |
end else if (state == `WBQSPI_CLEAR_STATUS) |
begin // Issue a clear status command |
spi_wr <= 1'b1; |
spi_hold <= 1'b0; |
spi_len <= 2'b00; // 8 bit command |
spi_in <= { 8'h30, 24'h00 }; |
spi_spd <= 1'b0; |
spi_dir <= 1'b0; |
last_status[6:5] <= 2'b00; |
spif_req <= (spif_req) && (i_wb_cyc); |
if ((spi_wr)&&(~spi_busy)) |
state <= `WBQSPI_WAIT_TIL_IDLE; |
end else if (state == `WBQSPI_IDLE_CHECK_WIP) |
begin // We are now in read status register mode |
|
// No bus commands have (yet) been given |
o_wb_stall <= 1'b1; |
o_wb_ack <= 1'b0; |
spif_req <= (spif_req) && (i_wb_cyc); |
|
// Stay in this mode unless/until we get a command, or |
// the write is over |
spi_wr <= (((~i_wb_cyc)||((~i_wb_data_stb)&&(~i_wb_ctrl_stb))) |
&&(write_in_progress)); |
spi_len <= 2'b00; // 8 bit reads |
spi_spd <= 1'b0; // SPI, not quad |
spi_dir <= 1'b1; // Read |
if (spi_valid) |
begin |
write_in_progress <= spi_out[0]; |
if ((~spi_out[0])&&(write_in_progress)) |
o_interrupt <= 1'b1; |
end else |
o_interrupt <= 1'b0; |
|
if ((~spi_wr)&&(~spi_busy)&&(o_qspi_cs_n)) |
begin // We can now go to idle and process a command |
o_wb_stall <= 1'b0; |
o_wb_ack <= 1'b0; |
state <= `WBQSPI_IDLE; |
end |
`endif // !READ_ONLY |
end else // if (state == `WBQSPI_WAIT_TIL_IDLE) or anything else |
begin |
spi_wr <= 1'b0; |
spi_hold <= 1'b0; |
o_wb_stall <= 1'b1; |
o_wb_ack <= 1'b0; |
spif_req <= 1'b0; |
if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // Wait for a full |
begin // clearing of the SPI port before moving on |
state <= `WBQSPI_IDLE; |
o_wb_stall <= 1'b0; |
o_wb_ack <= 1'b0; // Shouldn't be acking anything here |
end |
end |
end |
|
// Command and control during the reset sequence |
assign o_qspi_cs_n = (spif_override)?spif_cmd :w_qspi_cs_n; |
assign o_qspi_sck = (spif_override)?spif_ctrl:w_qspi_sck; |
assign o_qspi_mod = (spif_override)? 2'b01 :w_qspi_mod; |
assign o_qspi_dat = (spif_override)? 4'b00 :w_qspi_dat; |
endmodule |
/s6soc/trunk/rtl/busmaster.v
1,30 → 1,54
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: busmaster.v |
// |
// Filename: busmaster.v |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Project: FPGA library development (S6 development board) |
// Purpose: |
// |
// Purpose: |
// |
// Creator: Dan Gisselquist |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
// Copyright: 2015 |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
`include "builddate.v" |
// |
`define NO_ZIP_WBU_DELAY |
`define INCLUDE_ZIPPY |
`define IMPLEMENT_ONCHIP_RAM |
`define IMPLEMENT_ONCHIP_RAM // 2804 w/o after synthesis |
`ifndef VERILATOR |
`define FANCY_ICAP_ACCESS |
`endif |
`define FLASH_ACCESS |
`define CFG_SCOPE |
`define INCLUDE_RTC // 2017 slice LUTs w/o, 2108 with (!!!) |
// `define CFG_SCOPE // About 204 LUTs, at 2^6 addresses |
`define INCLUDE_RTC // About 90 LUTs |
module busmaster(i_clk, i_rst, |
i_rx_stb, i_rx_data, o_tx_stb, o_tx_data, i_tx_busy, |
o_uart_rts, |
// The SPI Flash lines |
o_qspi_cs_n, o_qspi_sck, o_qspi_dat, i_qspi_dat, o_qspi_mod, |
// The board I/O |
45,6 → 69,7
output reg o_tx_stb; |
output reg [7:0] o_tx_data; |
input i_tx_busy; |
output wire o_uart_rts; |
// SPI flash control |
output wire o_qspi_cs_n, o_qspi_sck; |
output wire [3:0] o_qspi_dat; |
144,7 → 169,7
assign rtc_stall = 1'b0; |
`endif |
wire io_stall, flash_stall, scop_stall, cfg_stall, mem_stall; |
reg io_ack, uart_ack; |
reg io_ack; |
|
wire [31:0] flash_data, scop_data, cfg_data, mem_data, pwm_data, |
spio_data, gpio_data, uart_data; |
152,7 → 177,6
reg [(BAW-1):0] bus_err_addr; |
|
assign wb_ack = (wb_cyc)&&((io_ack)||(scop_ack)||(cfg_ack) |
||(uart_ack) |
`ifdef INCLUDE_RTC |
||(rtc_ack) |
`endif |
176,9 → 200,8
: 32'h00)))); |
*/ |
assign wb_idata = (io_ack|scop_ack)?((io_ack )? io_data : scop_data) |
: ((cfg_ack|uart_ack) ? ((cfg_ack)?cfg_data: uart_data) |
: ((mem_ack|rtc_ack)?((mem_ack)?mem_data:rtc_data) |
: flash_data)); // if (flash_ack) |
: ((cfg_ack) ? cfg_data : flash_data));//if (flash_ack) |
assign wb_err = ((wb_cyc)&&(wb_stb)&&(none_sel || many_sel)) || many_ack; |
|
// Addresses ... |
233,8 → 256,7
wb_err, button_int }; |
|
wire [31:0] pic_data; |
icontrol #(11) pic(i_clk, 1'b0, |
(wb_cyc)&&(wb_stb)&&(io_sel) |
icontrol #(11) pic(i_clk, 1'b0, (wb_stb)&&(io_sel) |
&&(wb_addr[3:0]==4'h0)&&(wb_we), |
wb_data, pic_data, int_vector, w_interrupt); |
|
245,11 → 267,13
|
wire zta_ack, zta_stall, ztb_ack, ztb_stall; |
wire [31:0] timer_a, timer_b; |
ziptimer zipt_a(i_clk, 1'b0, 1'b1, wb_cyc, |
ziptimer #(32,20) |
zipt_a(i_clk, 1'b0, 1'b1, wb_cyc, |
(wb_stb)&&(io_sel)&&(wb_addr[3:0]==4'h2), |
wb_we, wb_data, zta_ack, zta_stall, timer_a, |
tmra_int); |
ziptimer zipt_b(i_clk, 1'b0, 1'b1, wb_cyc, |
ziptimer #(32,20) |
zipt_b(i_clk, 1'b0, 1'b1, wb_cyc, |
(wb_stb)&&(io_sel)&&(wb_addr[3:0]==4'h3), |
wb_we, wb_data, ztb_ack, ztb_stall, timer_b, |
tmrb_int); |
266,7 → 290,7
assign rtc_ack = r_rtc_ack; |
|
rtclight |
#(32'h35afe5) // 80 MHz clock |
#(32'h35afe5,23) // 80 MHz clock |
thetime(i_clk, wb_cyc, |
((wb_stb)&&(rtc_sel)), wb_we, |
{ 1'b0, wb_addr[1:0] }, wb_data, rtc_data, |
333,7 → 357,7
initial o_tx_stb = 1'b0; |
initial o_tx_data = 8'h00; |
always @(posedge i_clk) |
if ((wb_cyc)&&(wb_stb)&&(io_sel)&&(wb_addr[3:0]==4'h7)&&(wb_we)) |
if ((wb_stb)&&(io_sel)&&(wb_addr[3:0]==4'h7)&&(wb_we)) |
begin |
o_tx_data <= wb_data[7:0]; |
o_tx_stb <= 1'b1; |
346,14 → 370,19
r_rx_data <= i_rx_data; |
always @(posedge i_clk) |
begin |
if((wb_cyc)&&(wb_stb)&&(io_sel)&&(wb_addr[3:0]==4'h7)&&(~wb_we)) |
if((wb_stb)&&(io_sel)&&(wb_addr[3:0]==4'h7)&&(~wb_we)) |
rx_rdy <= i_rx_stb; |
else if (i_rx_stb) |
rx_rdy <= (rx_rdy | i_rx_stb); |
end |
assign o_uart_rts = (~rx_rdy); |
assign uart_data = { 23'h0, ~rx_rdy, r_rx_data }; |
always @(posedge i_clk) |
uart_ack<= ((wb_cyc)&&(wb_stb)&&(io_sel)&&(wb_addr[3:0]==4'h7)); |
// |
// uart_ack gets returned as part of io_ack, since that happens when |
// io_sel and wb_stb are defined |
// |
// always @(posedge i_clk) |
// uart_ack<= ((wb_stb)&&(io_sel)&&(wb_addr[3:0]==4'h7)); |
|
|
|
363,7 → 392,7
wire flash_cs_n, flash_sck, flash_mosi; |
wbqspiflash #(24) flashmem(i_clk, |
wb_cyc,(wb_stb&&flash_sel),(wb_stb)&&(flctl_sel),wb_we, |
wb_addr[21:0], wb_data, |
wb_addr[(24-3):0], wb_data, |
flash_ack, flash_stall, flash_data, |
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat, |
flash_interrupt); |
391,8 → 420,17
// |
// ON-CHIP RAM MEMORY ACCESS |
// |
`ifdef IMPLEMENT_ONCHIP_RAM |
memdev #(12) ram(i_clk, wb_cyc, (wb_stb)&&(mem_sel), wb_we, |
wb_addr[11:0], wb_data, mem_ack, mem_stall, mem_data); |
`else |
assign mem_data = 32'h00; |
assign mem_stall = 1'b0; |
reg r_mem_ack; |
always @(posedge i_clk) |
r_mem_ack <= (wb_cyc)&&(wb_stb)&&(mem_sel); |
assign mem_ack = r_mem_ack; |
`endif |
|
// |
// |
406,12 → 444,19
`ifdef CFG_SCOPE |
wire scop_cfg_trigger; |
assign scop_cfg_trigger = (wb_cyc)&&(wb_stb)&&(cfg_sel); |
wbscope #(5'ha) wbcfgscope(i_clk, 1'b1, scop_cfg_trigger, cfg_scope, |
wbscope #(5'h6) wbcfgscope(i_clk, 1'b1, scop_cfg_trigger, cfg_scope, |
// Wishbone interface |
i_clk, wb_cyc, ((wb_stb)&&(scop_sel)&&(wb_addr[2:1]==2'b01)), |
i_clk, wb_cyc, (wb_stb)&&(scop_sel), |
wb_we, wb_addr[0], wb_data, |
scop_cfg_ack, scop_cfg_stall, scop_cfg_data, |
scop_cfg_interrupt); |
`else |
reg r_scop_cfg_ack; |
always @(posedge i_clk) |
r_scop_cfg_ack <= (wb_cyc)&&(wb_stb)&&(scop_sel); |
assign scop_cfg_ack = r_scop_cfg_ack; |
assign scop_cfg_data = 32'h000; |
assign scop_cfg_stall= 1'b0; |
`endif |
|
assign scop_interrupt = scop_cfg_interrupt; |
421,4 → 466,3
|
endmodule |
|
// 0x8684 interrupts ...??? |
/s6soc/trunk/rtl/wbubus.v
0,0 → 1,275
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: wbubus.v |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: This is a test of the Verilog obfuscator routine I put together. |
// The actual code for wbubus.v can be found in the XuLA2-LX25 |
// SoC project. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
module wbubus(i_clk,i_rx_stb,i_rx_data,o_wb_cyc,o_wb_stb,o_wb_we,o_wb_addr, |
o_wb_data,i_wb_ack,i_wb_stall,i_wb_err,i_wb_data,i_interrupt,o_tx_stb,o_tx_data |
,i_tx_busy);parameter LGWATCHDOG=19;input i_clk;input i_rx_stb;input[7:0] |
i_rx_data;output wire o_wb_cyc,o_wb_stb,o_wb_we;output wire[31:0]o_wb_addr, |
o_wb_data;input i_wb_ack,i_wb_stall,i_wb_err;input[31:0]i_wb_data;input |
i_interrupt;output wire o_tx_stb;output wire[7:0]o_tx_data;input i_tx_busy;reg |
PhcDs;wire QhcDs;wire[35:0]RhcDs;ShcDs ThcDs(i_clk,i_rx_stb,i_rx_data,QhcDs, |
RhcDs);wire UhcDs,VhcDs,WhcDs,XhcDs;wire[35:0]YhcDs,ZhcDs; |
`ifdef aicDs |
assign VhcDs=QhcDs;assign YhcDs=RhcDs;assign XhcDs=1'd0; |
`else |
wire bicDs,cicDs;assign VhcDs=(~UhcDs)&&(bicDs);assign XhcDs=PhcDs;dicDs#(36,6 |
)eicDs(i_clk,XhcDs,QhcDs,RhcDs,VhcDs,YhcDs,bicDs,cicDs); |
`endif |
ficDs gicDs(i_clk,PhcDs,VhcDs,YhcDs,UhcDs,o_wb_cyc,o_wb_stb,o_wb_we,o_wb_addr |
,o_wb_data,i_wb_ack,i_wb_stall,i_wb_err,i_wb_data,WhcDs,ZhcDs);wire hicDs;iicDs |
jicDs(i_clk,XhcDs,WhcDs,ZhcDs,o_wb_cyc,i_interrupt,WhcDs,o_tx_stb,o_tx_data, |
i_tx_busy,hicDs);reg[(LGWATCHDOG-1):0]kicDs;initial PhcDs=1'd0;initial kicDs=0 |
;always@(posedge i_clk)if((~o_wb_cyc)||(i_wb_ack))begin kicDs<=0;PhcDs<=1'd0; |
end else if(&kicDs)begin PhcDs<=1'd1;kicDs<=0;end else begin kicDs<=kicDs+{{( |
LGWATCHDOG-1){1'd0}},1'd1};PhcDs<=1'd0;end endmodule |
|
module licDs(i_clk,micDs,nicDs,oicDs,picDs,qicDs,i_tx_busy,ricDs);input i_clk, |
micDs;input[6:0]nicDs;output reg oicDs;output reg[6:0]picDs;input qicDs;input |
i_tx_busy;output wire ricDs;reg sicDs,ticDs;initial sicDs=1'd1;initial ticDs= |
1'd1;always@(posedge i_clk)if((~i_tx_busy)&&(oicDs))sicDs<=(picDs[6]);always@( |
posedge i_clk)if((micDs)&&(~ricDs))ticDs<=(nicDs[6]);reg[6:0]uicDs;initial |
uicDs=7'd0;always@(posedge i_clk)if((~i_tx_busy)&&(oicDs))begin if(picDs[6]) |
uicDs<=0;else uicDs<=uicDs+7'd1;end reg vicDs;initial vicDs=1'd0;always@( |
posedge i_clk)vicDs<=(uicDs>7'd72);initial oicDs=1'd0;always@(posedge i_clk)if |
((micDs)&&(~ricDs))begin oicDs<=(vicDs)||(~nicDs[6]);picDs<=nicDs;end else if( |
~ricDs)begin oicDs<=(~i_tx_busy)&&(~qicDs)&&(~sicDs)&&(ticDs);picDs<=7'd64;end |
else if(~i_tx_busy)oicDs<=1'd0;reg wicDs;initial wicDs=1'd0;always@(posedge |
i_clk)wicDs<=(oicDs);assign ricDs=(wicDs)||(oicDs);endmodule |
|
module xicDs(i_clk,micDs,yicDs,oicDs,zicDs,AicDs);parameter BicDs=32,CicDs=36, |
DicDs=10;input i_clk,micDs;input[(CicDs-1):0]yicDs;output wire oicDs;output |
wire[(CicDs-1):0]zicDs;input AicDs;reg EicDs;reg[35:0]FicDs;wire[31:0]GicDs; |
assign GicDs=yicDs[31:0];always@(posedge i_clk)if((micDs)&&(~EicDs))begin if( |
yicDs[35:32]!=4'd2)begin FicDs<=yicDs;end else if(GicDs[31:6]==26'd0)FicDs<={ |
6'd12,GicDs[5:0],24'd0};else if(GicDs[31:12]==20'd0)FicDs<={6'd13,GicDs[11:0], |
18'd0};else if(GicDs[31:18]==14'd0)FicDs<={6'd14,GicDs[17:0],12'd0};else if( |
GicDs[31:24]==8'd0)FicDs<={6'd15,GicDs[23:0],6'd0};else begin FicDs<=yicDs;end |
end initial EicDs=1'd0;always@(posedge i_clk)if((micDs)&&(~EicDs))EicDs<=micDs |
;else if(~AicDs)EicDs<=1'd0;wire HicDs;assign HicDs=(EicDs)&&(~AicDs);reg IicDs |
;always@(posedge i_clk)IicDs<=EicDs;wire[35:0]JicDs;assign JicDs=FicDs;reg[( |
DicDs-1):0]KicDs;reg LicDs,MicDs;always@(posedge i_clk)if(HicDs)begin if(zicDs |
[35:33]==3'd1)KicDs<=0;else if(zicDs[35:33]==3'd7)KicDs<=KicDs+{{(DicDs-1){1'd0 |
}},1'd1};end always@(posedge i_clk)if((HicDs)&&(zicDs[35:33]==3'd1))MicDs<=1'd0 |
;else if(KicDs==10'd1023)MicDs<=1'd1;reg[31:0]NicDs[0:((1<<DicDs)-1)];always@( |
posedge i_clk)NicDs[KicDs]<={JicDs[32:31],JicDs[29:0]};reg[(DicDs-1):0]OicDs; |
wire[(DicDs-1):0]PicDs;assign PicDs=OicDs-{{(DicDs-1){1'd0}},1'd1};initial |
OicDs=0;always@(posedge i_clk)if((HicDs)||(~EicDs))OicDs<=KicDs+{(DicDs){1'd1} |
};else if((PicDs!=KicDs)&&(~QicDs)&&((~PicDs[DicDs-1])||(MicDs)))OicDs<=PicDs; |
reg[(BicDs-1):0]RicDs;reg[(DicDs-1):0]SicDs;always@(posedge i_clk)begin RicDs |
<=NicDs[OicDs];SicDs<=OicDs;end reg QicDs;reg[9:0]TicDs;always@(posedge i_clk) |
if((HicDs)||(~EicDs)||(~IicDs))QicDs<=1'd0;else if(~QicDs)begin QicDs<=(({1'd0 |
,SicDs}<{MicDs,KicDs}))&&(JicDs[35:33]==3'd7)&&(RicDs=={JicDs[32:31],JicDs[29:0 |
]});TicDs<=KicDs-SicDs;end wire[(DicDs-1):0]UicDs;wire[9:0]VicDs;wire[2:0]WicDs |
;assign UicDs=TicDs;assign WicDs=TicDs[2:0]-3'd2;assign VicDs=TicDs-10'd10; |
initial LicDs=1'd0;reg[(CicDs-1):0]XicDs;always@(posedge i_clk)begin if((~EicDs |
)||(~IicDs)||(HicDs))LicDs<=1'd0;else if(LicDs);else if((QicDs)&&(TicDs<10'd521 |
))begin if(TicDs==10'd1)XicDs[35:30]<={5'd3,JicDs[30]};else if(UicDs<10'd10) |
XicDs[35:30]<={2'd2,WicDs,JicDs[30]};else XicDs[35:24]<={2'd1,VicDs[8:6],JicDs |
[30],VicDs[5:0]};LicDs<=1'd1;end else XicDs<=JicDs;end assign oicDs=EicDs; |
assign zicDs=(LicDs)?(XicDs):(FicDs);endmodule |
|
module YicDs(i_clk,micDs,ZicDs,oicDs,ajcDs);input i_clk,micDs;input[35:0]ZicDs |
;output reg oicDs;output reg[35:0]ajcDs;wire bjcDs=(ZicDs[35:33]==3'd3);reg[7:0 |
]cjcDs;initial cjcDs=8'd0;always@(posedge i_clk)if((micDs)&&(bjcDs))cjcDs<= |
cjcDs+8'd1;reg[31:0]NicDs[0:255];always@(posedge i_clk)if(micDs)NicDs[cjcDs]<= |
{ZicDs[32:31],ZicDs[29:0]};reg[35:0]JicDs;always@(posedge i_clk)if(micDs)JicDs |
<=ZicDs;reg[7:0]djcDs;always@(posedge i_clk)djcDs=cjcDs-{JicDs[32:31],JicDs[29 |
:24]};reg[24:0]ejcDs;always@(posedge i_clk)case(JicDs[32:30])3'd0:ejcDs<={19'd0 |
,JicDs[29:24]};3'd2:ejcDs<={13'd0,JicDs[29:18]};3'd4:ejcDs<={7'd0,JicDs[29:12] |
};3'd6:ejcDs<={1'd0,JicDs[29:6]};3'd1:ejcDs<={{(19){JicDs[29]}},JicDs[29:24]}; |
3'd3:ejcDs<={{(13){JicDs[29]}},JicDs[29:18]};3'd5:ejcDs<={{(7){JicDs[29]}}, |
JicDs[29:12]};3'd7:ejcDs<={{(1){JicDs[29]}},JicDs[29:6]};endcase wire[31:0] |
GicDs;assign GicDs={{(7){ejcDs[24]}},ejcDs};reg[9:0]fjcDs;always@(posedge i_clk |
)if(~JicDs[34])fjcDs<=10'd1+{6'd0,JicDs[33:31]};else fjcDs<=10'd8+{1'd0,JicDs[ |
33:31],JicDs[29:24]};reg[31:0]RicDs;always@(posedge i_clk)RicDs<=NicDs[djcDs]; |
reg[2:0]IicDs;initial IicDs=0;always@(posedge i_clk)IicDs<={IicDs[1:0],micDs}; |
always@(posedge i_clk)oicDs<=IicDs[2];always@(posedge i_clk)if(JicDs[35:30]== |
6'd46)ajcDs<=JicDs;else casez(JicDs[35:30])6'b001??0:ajcDs<={4'd0,GicDs[31:0]} |
;6'b001??1:ajcDs<={3'd1,GicDs[31:30],1'd1,GicDs[29:0]};6'b010???:ajcDs<={3'd3, |
RicDs[31:30],JicDs[30],RicDs[29:0]};6'b10????:ajcDs<={5'd24,JicDs[30],20'd0, |
fjcDs};6'b11????:ajcDs<={5'd24,JicDs[30],20'd0,fjcDs};default:ajcDs<=JicDs; |
endcase endmodule |
|
module gjcDs(i_clk,micDs,ZicDs,i_tx_busy,oicDs,picDs,ricDs);input i_clk,micDs; |
input[35:0]ZicDs;input i_tx_busy;output reg oicDs;output reg[6:0]picDs;output |
reg ricDs;wire[2:0]hjcDs;assign hjcDs=(ZicDs[35:33]==3'd0)?3'd1:(ZicDs[35:32] |
==4'd2)?3'd6:(ZicDs[35:32]==4'd3)?(3'd2+{1'd0,ZicDs[31:30]}):(ZicDs[35:34]== |
2'd1)?3'd2:(ZicDs[35:34]==2'd2)?3'd1:3'd6;reg ijcDs;reg[2:0]jjcDs;reg[29:0] |
JicDs;initial oicDs=1'd0;initial ricDs=1'd0;initial ijcDs=1'd0;always@(posedge |
i_clk)if((micDs)&&(~ricDs))begin jjcDs<=hjcDs-3'd1;JicDs<=ZicDs[29:0];oicDs<= |
1'd1;picDs<={1'd0,ZicDs[35:30]};ricDs<=1'd1;ijcDs<=1'd1;end else if((oicDs)&&( |
i_tx_busy))begin ricDs<=1'd1;ijcDs<=1'd1;end else if(oicDs)oicDs<=1'd0;else if |
(jjcDs>0)begin oicDs<=1'd1;picDs<={1'd0,JicDs[29:24]};JicDs[29:6]<=JicDs[23:0] |
;jjcDs<=jjcDs-3'd1;ricDs<=1'd1;ijcDs<=1'd1;end else if(~picDs[6])begin oicDs<= |
1'd1;picDs<=7'd64;ricDs<=1'd1;ijcDs<=1'd1;end else begin ijcDs<=1'd0;ricDs<=( |
ijcDs);end endmodule |
|
module ficDs(i_clk,kjcDs,micDs,yicDs,ricDs,o_wb_cyc,o_wb_stb,o_wb_we,o_wb_addr |
,o_wb_data,i_wb_ack,i_wb_stall,i_wb_err,i_wb_data,oicDs,ljcDs);input i_clk, |
kjcDs;input micDs;input[35:0]yicDs;output reg ricDs;output reg o_wb_cyc, |
o_wb_stb,o_wb_we;output reg[31:0]o_wb_addr,o_wb_data;input i_wb_ack,i_wb_stall |
,i_wb_err;input[31:0]i_wb_data;output reg oicDs;output reg[35:0]ljcDs;wire |
mjcDs,njcDs,ojcDs,pjcDs;assign mjcDs=(micDs)&&(~ricDs);assign ojcDs=(mjcDs)&&( |
yicDs[35:34]==2'd1);assign njcDs=(mjcDs)&&(yicDs[35:30]==6'd46);wire[31:0]qjcDs |
;assign qjcDs={yicDs[32:31],yicDs[29:0]};assign pjcDs=((mjcDs)&&((yicDs[35:33] |
!=3'd3)||(~o_wb_we))&&(yicDs[35:30]!=6'd46));reg[9:0]rjcDs,jjcDs;reg sjcDs, |
tjcDs,ujcDs,vjcDs;initial tjcDs=1'd0;initial ujcDs=1'd1;always@(posedge i_clk) |
if(kjcDs)begin oicDs<=1'd1;ljcDs<={6'd3,30'd0};tjcDs<=1'd0;o_wb_cyc<=1'd0;end |
else if(o_wb_cyc)begin oicDs<=1'd0;if(tjcDs)begin if(njcDs)o_wb_cyc<=1'd0; |
o_wb_stb<=1'd0;end else if((i_wb_err)||(pjcDs))begin o_wb_cyc<=(~ricDs); |
o_wb_stb<=1'd0;tjcDs<=1'd1;oicDs<=1'd1;ljcDs<={6'd5,30'd0};end else if(( |
o_wb_stb)&&(~i_wb_stall))begin if(jjcDs!=0)jjcDs<=jjcDs-10'd1;else o_wb_stb<= |
1'd0;if(o_wb_we)begin oicDs<=1'd1;ljcDs<={6'd2,30'd0};end if(sjcDs)o_wb_addr<= |
o_wb_addr+32'd1;end else if(ojcDs)begin sjcDs<=yicDs[30];o_wb_data<=qjcDs; |
o_wb_stb<=1'd1;end if(njcDs)vjcDs<=1'd1;if((tjcDs)||(i_wb_err)||(pjcDs))ricDs |
<=1'd0;else if((njcDs)||(ojcDs)||(vjcDs))ricDs<=1'd1;else if((o_wb_we)&&( |
o_wb_stb)&&(~i_wb_stall)&&(jjcDs==0))ricDs<=1'd0;else if((o_wb_we)&&(~o_wb_stb |
))ricDs<=1'd0;if((tjcDs)||(i_wb_err))begin end else if(rjcDs!=10'd0)begin if(( |
i_wb_ack)&&(~o_wb_we))begin oicDs<=1'd1;ljcDs<={3'd7,i_wb_data[31:30],sjcDs, |
i_wb_data[29:0]};end if((i_wb_ack)&&(~ojcDs))rjcDs<=rjcDs-10'd1;else if((~ |
i_wb_ack)&&(ojcDs))rjcDs<=rjcDs+10'd1;end else if(rjcDs==10'd0)begin if((~ |
o_wb_we)||(vjcDs)||(njcDs))o_wb_cyc<=1'd0;else if(ojcDs)begin rjcDs<=rjcDs+ |
10'd1;o_wb_data<=qjcDs;end end end else if(micDs)begin oicDs<=1'd0;sjcDs<=yicDs |
[30];o_wb_we<=(~yicDs[35]);tjcDs<=1'd0;ricDs<=1'd0;vjcDs<=1'd0;if(yicDs[35:32] |
==4'd0)begin ujcDs<=1'd1;o_wb_addr<=yicDs[31:0];end else if(yicDs[35:33]==3'd1 |
)begin o_wb_addr<=o_wb_addr+{yicDs[32:31],yicDs[29:0]};ujcDs<=1'd1;end else if |
(yicDs[35:34]==2'd3)begin jjcDs<=yicDs[9:0]-10'd1;o_wb_cyc<=1'd1;o_wb_stb<=1'd1 |
;rjcDs<=yicDs[9:0];ricDs<=1'd1;if(ujcDs)begin oicDs<=1'd1;ljcDs<={4'd2, |
o_wb_addr};ujcDs<=1'd0;end end else if(~yicDs[35])begin o_wb_cyc<=1'd1;o_wb_stb |
<=1'd1;o_wb_data<=qjcDs;ricDs<=1'd1;jjcDs<=10'd0;ujcDs<=1'd1;rjcDs<=10'd1;end |
end else begin tjcDs<=1'd0;ricDs<=1'd0;oicDs<=1'd0;end endmodule |
|
module dicDs(i_clk,kjcDs,wjcDs,xjcDs,yjcDs,zjcDs,AjcDs,BjcDs);parameter CjcDs= |
66,DjcDs=10,EjcDs=(1<<DjcDs);input i_clk,kjcDs;input wjcDs;input[(CjcDs-1):0] |
xjcDs;input yjcDs;output reg[(CjcDs-1):0]zjcDs;output reg AjcDs;output wire |
BjcDs;reg[(CjcDs-1):0]FjcDs[0:(EjcDs-1)];reg[(DjcDs-1):0]GjcDs,HjcDs;initial |
GjcDs=0;always@(posedge i_clk)if(kjcDs)GjcDs<={(DjcDs){1'd0}};else if(wjcDs) |
begin if(GjcDs+1!=HjcDs)GjcDs<=GjcDs+{{(DjcDs-1){1'd0}},1'd1};end always@( |
posedge i_clk)if(wjcDs)FjcDs[GjcDs]<=xjcDs;initial HjcDs=0;always@(posedge |
i_clk)if(kjcDs)HjcDs<={(DjcDs){1'd0}};else if(yjcDs)begin if(GjcDs!=HjcDs)HjcDs |
<=HjcDs+{{(DjcDs-1){1'd0}},1'd1};end always@(posedge i_clk)zjcDs<=FjcDs[(yjcDs |
)?(HjcDs+{{(DjcDs-1){1'd0}},1'd1}):(HjcDs)];wire[(DjcDs-1):0]IjcDs;assign IjcDs |
=GjcDs+{{(DjcDs-1){1'd0}},1'd1};assign BjcDs=((wjcDs)&&(IjcDs==HjcDs))||((yjcDs |
)&&(GjcDs==HjcDs));wire[(DjcDs-1):0]JjcDs;assign JjcDs=HjcDs+{{(DjcDs-1){1'd0} |
},1'd1};always@(posedge i_clk)if(kjcDs)AjcDs<=1'd0;else AjcDs<=(~yjcDs)&&(GjcDs |
!=HjcDs)||(yjcDs)&&(GjcDs!=JjcDs);endmodule |
|
module KjcDs(i_clk,micDs,yicDs,LjcDs,AicDs,MjcDs,oicDs,ljcDs,ricDs,i_tx_busy); |
input i_clk;input micDs;input[35:0]yicDs;input LjcDs,AicDs,MjcDs;output reg |
oicDs;output reg[35:0]ljcDs;output reg ricDs;input i_tx_busy;reg NjcDs,OjcDs; |
initial NjcDs=1'd0;always@(posedge i_clk)if((oicDs)&&(~i_tx_busy)&&(ljcDs[35:30 |
]==6'd4))NjcDs<=MjcDs;else NjcDs<=(NjcDs)||(MjcDs);wire PjcDs;reg QjcDs;reg[35 |
:0]RjcDs;initial RjcDs=36'd0;always@(posedge i_clk)if((micDs)||(oicDs))RjcDs<= |
36'd0;else if(~RjcDs[35])RjcDs<=RjcDs+36'd43;initial QjcDs=1'd0;always@(posedge |
i_clk)if((oicDs)&&(~i_tx_busy)&&(ljcDs[35:31]==5'd0))QjcDs<=1'd1;else if(~RjcDs |
[35])QjcDs<=1'd0;assign PjcDs=(~QjcDs)&&(RjcDs[35]);initial oicDs=1'd0;initial |
ricDs=1'd0;always@(posedge i_clk)if((oicDs)&&(i_tx_busy))begin ricDs<=1'd1;end |
else if(oicDs)begin oicDs<=1'd0;ricDs<=1'd1;end else if(ricDs)ricDs<=1'd0;else |
if(micDs)begin ljcDs<=yicDs;oicDs<=1'd1;ricDs<=1'd1;end else if((NjcDs)&&(~ |
OjcDs))begin oicDs<=1'd1;ljcDs<={6'd4,30'd0};ricDs<=1'd1;end else if(PjcDs) |
begin oicDs<=1'd1;ricDs<=1'd1;if(LjcDs)ljcDs<={6'd1,30'd0};else ljcDs<={6'd0, |
30'd0};end initial OjcDs=1'd0;always@(posedge i_clk)if((NjcDs)&&((~oicDs)&&(~ |
ricDs)&&(~micDs)))OjcDs<=1'd1;else if(~MjcDs)OjcDs<=1'd0;endmodule |
|
module ShcDs(i_clk,micDs,SjcDs,oicDs,ljcDs);input i_clk,micDs;input[7:0]SjcDs; |
output wire oicDs;output wire[35:0]ljcDs;wire TjcDs,UjcDs;wire[5:0]VjcDs;WjcDs |
XjcDs(i_clk,micDs,SjcDs,TjcDs,UjcDs,VjcDs);wire YjcDs;wire[35:0]ZjcDs;akcDs |
bkcDs(i_clk,TjcDs,UjcDs,VjcDs,YjcDs,ZjcDs); |
`ifdef ckcDs |
assign oicDs=YjcDs;assign ljcDs=ZjcDs; |
`else |
YicDs dkcDs(i_clk,YjcDs,ZjcDs,oicDs,ljcDs); |
`endif |
endmodule |
|
module iicDs(i_clk,kjcDs,micDs,yicDs,ekcDs,MjcDs,qicDs,oicDs,fkcDs,i_tx_busy, |
gkcDs);input i_clk,kjcDs;input micDs;input[35:0]yicDs;input ekcDs,MjcDs,qicDs; |
output wire oicDs;output wire[7:0]fkcDs;input i_tx_busy;output wire gkcDs;wire |
hkcDs,ikcDs,jkcDs,kkcDs;wire[35:0]lkcDs;wire YjcDs,mkcDs,nkcDs,okcDs,pkcDs, |
qkcDs,rkcDs,skcDs;wire[35:0]tkcDs,ukcDs;wire[6:0]vkcDs,wkcDs; |
`ifdef xkcDs |
assign hkcDs=micDs;assign lkcDs=yicDs;assign kkcDs=1'd0; |
`else |
assign hkcDs=(jkcDs)&&(~mkcDs);dicDs#(36,10)ykcDs(i_clk,kjcDs,micDs,yicDs, |
hkcDs,lkcDs,jkcDs,kkcDs); |
`endif |
assign gkcDs=kkcDs;KjcDs zkcDs(i_clk,hkcDs,lkcDs,ekcDs,qicDs,MjcDs,YjcDs,tkcDs |
,mkcDs,rkcDs); |
`ifdef AkcDs |
assign nkcDs=YjcDs;assign ukcDs=tkcDs;assign rkcDs=ikcDs; |
`else |
assign rkcDs=nkcDs;xicDs BkcDs(i_clk,YjcDs,tkcDs,nkcDs,ukcDs,ikcDs); |
`endif |
gjcDs CkcDs(i_clk,nkcDs,ukcDs,qkcDs,okcDs,vkcDs,ikcDs);licDs DkcDs(i_clk,okcDs |
,vkcDs,pkcDs,wkcDs,(ekcDs||qicDs||jkcDs||mkcDs),skcDs,qkcDs);EkcDs FkcDs(i_clk |
,pkcDs,wkcDs,oicDs,fkcDs,skcDs,i_tx_busy);endmodule |
|
module akcDs(i_clk,micDs,GkcDs,HkcDs,oicDs,ljcDs);input i_clk,micDs,GkcDs;input |
[5:0]HkcDs;output reg oicDs;output reg[35:0]ljcDs;reg[2:0]jjcDs,IkcDs;wire |
JkcDs;assign JkcDs=((jjcDs==IkcDs)&&(IkcDs!=0))||((micDs)&&(~GkcDs)&&(KkcDs== |
2'd1));initial jjcDs=3'd0;always@(posedge i_clk)if((micDs)&&(~GkcDs))jjcDs<=0; |
else if(JkcDs)jjcDs<=(micDs)?3'd1:3'd0;else if(micDs)jjcDs<=jjcDs+3'd1;reg[35:0 |
]LkcDs;always@(posedge i_clk)if(JkcDs)LkcDs[35:30]<=HkcDs;else if(micDs)case( |
jjcDs)3'd0:LkcDs[35:30]<=HkcDs;3'd1:LkcDs[29:24]<=HkcDs;3'd2:LkcDs[23:18]<= |
HkcDs;3'd3:LkcDs[17:12]<=HkcDs;3'd4:LkcDs[11:6]<=HkcDs;3'd5:LkcDs[5:0]<=HkcDs; |
default:begin end endcase reg[1:0]KkcDs;always@(posedge i_clk)if(oicDs)KkcDs<= |
ljcDs[35:34];always@(posedge i_clk)if((micDs)&&(~GkcDs)&&(KkcDs==2'd1))ljcDs[35 |
:30]<=6'd46;else ljcDs<=LkcDs;initial IkcDs=3'd0;always@(posedge i_clk)if(( |
micDs)&&(~GkcDs))IkcDs<=0;else if((micDs)&&((IkcDs==0)||(JkcDs)))begin if(HkcDs |
[5:4]==2'd3)IkcDs<=3'd2;else if(HkcDs[5:4]==2'd2)IkcDs<=3'd1;else if(HkcDs[5:3 |
]==3'd2)IkcDs<=3'd2;else if(HkcDs[5:3]==3'd1)IkcDs<=3'd2+{1'd0,HkcDs[2:1]};else |
IkcDs<=3'd6;end else if(JkcDs)IkcDs<=0;always@(posedge i_clk)oicDs<=JkcDs; |
endmodule |
|
module EkcDs(i_clk,micDs,MkcDs,oicDs,fkcDs,ricDs,AicDs);input i_clk;input micDs |
;input[6:0]MkcDs;output reg oicDs;output reg[7:0]fkcDs;output wire ricDs;input |
AicDs;initial fkcDs=8'd0;always@(posedge i_clk)if((micDs)&&(~ricDs))begin if( |
MkcDs[6])fkcDs<=8'd10;else if(MkcDs[5:0]<=6'd9)fkcDs<=8'd48+{4'd0,MkcDs[3:0]}; |
else if(MkcDs[5:0]<=6'd35)fkcDs<=8'd65+{2'd0,MkcDs[5:0]}-8'd10;else if(MkcDs[5 |
:0]<=6'd61)fkcDs<=8'd97+{2'd0,MkcDs[5:0]}-8'd36;else if(MkcDs[5:0]==6'd62)fkcDs |
<=8'd64;else fkcDs<=8'd37;end always@(posedge i_clk)if((oicDs)&&(~AicDs))oicDs |
<=1'd0;else if((micDs)&&(~oicDs))oicDs<=1'd1;assign ricDs=oicDs;endmodule |
|
module WjcDs(i_clk,micDs,SjcDs,oicDs,NkcDs,OkcDs);input i_clk,micDs;input[7:0] |
SjcDs;output reg oicDs,NkcDs;output reg[5:0]OkcDs;always@(posedge i_clk)oicDs |
<=micDs;always@(posedge i_clk)begin NkcDs<=1'd1;OkcDs<=6'd0;if((SjcDs>=8'd48) |
&&(SjcDs<=8'd57))OkcDs<={2'd0,SjcDs[3:0]};else if((SjcDs>=8'd65)&&(SjcDs<=8'd90 |
))OkcDs<=(SjcDs[5:0]-6'd1+6'd10);else if((SjcDs>=8'd97)&&(SjcDs<=8'd122))OkcDs |
<=(SjcDs[5:0]+6'd3);else if(SjcDs==8'd64)OkcDs<=6'd62;else if(SjcDs==8'd37) |
OkcDs<=6'd63;else NkcDs<=1'd0;end endmodule |