OpenCores
URL https://opencores.org/ocsvn/openarty/openarty/trunk

Subversion Repositories openarty

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openarty/trunk
    from Rev 2 to Rev 3
    Reverse comparison

Rev 2 → Rev 3

/rtl/wboled.v
0,0 → 1,162
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wboled.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:
//
// 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 wboled(i_clk, i_cyc, i_stb, i_we, i_addr, i_data,
o_ack, o_stall, o_data,
o_sck, o_cs_n, o_mosi, o_dbit,
o_pwr, o_int);
parameter CBITS=4; // 2^4*2@5ns -> 160ns/clock > 150ns min
input i_clk, i_cyc, i_stb, i_we;
input [1:0] i_addr;
input [31:0] i_data;
output reg o_ack;
output wire o_stall;
output reg [31:0] o_data;
output wire o_sck, o_cs_n, o_mosi, o_dbit;
output reg [2:0] o_pwr;
output wire o_int;
 
reg dev_wr, dev_dbit;
reg [31:0] dev_word;
reg [1:0] dev_len;
wire dev_busy;
lloled #(CBITS)
lwlvl(i_clk, dev_wr, dev_dbit, dev_word, dev_len, dev_busy,
o_sck, o_cs_n, o_mosi, o_dbit);
 
reg r_busy;
reg [3:0] r_len;
reg [31:0] r_a, r_b;
always @(posedge i_clk)
if ((i_stb)&&(i_we))
begin
if (i_addr[1:0]==2'b01)
r_a <= i_data;
if (i_addr[1:0]==2'b10)
r_b <= i_data;
end else if (r_cstb)
begin
r_a <= 32'h00;
r_b <= 32'h00;
end
 
always @(posedge i_clk)
begin
case (i_addr)
2'b00: o_data <= { 13'h00, o_pwr, 8'h00, r_len, 3'h0, r_busy };
2'b01: o_data <= r_a;
2'b10: o_data <= r_b;
2'b11: o_data <= { 13'h00, o_pwr, 8'h00, r_len, 3'h0, r_busy };
endcase
end
 
initial o_ack = 1'b0;
always @(posedge i_clk)
o_ack <= i_stb;
assign o_stall = 1'b0;
 
reg r_cstb, r_dstb, r_pstb;
reg [23:0] r_data;
initial r_cstb = 1'b0;
initial r_dstb = 1'b0;
initial r_pstb = 1'b0;
always @(posedge i_clk)
r_cstb <= (i_stb)&&(i_addr[1:0]==2'b00);
always @(posedge i_clk)
r_dstb <= (i_stb)&&(i_addr[1:0]==2'b11)&&(i_data[22:20]==3'h0);
always @(posedge i_clk)
r_pstb <= (i_stb)&&(i_addr[1:0]==2'b11)&&(i_data[22:20]!=3'h0);
always @(posedge i_clk)
r_data <= i_data[23:0];
 
initial o_pwr = 3'h0;
always @(posedge i_clk)
if (r_pstb)
o_pwr <= ((o_pwr)&(~r_data[22:20]))
|((i_data[18:16])&(r_data[22:20]));
 
reg [3:0] b_len;
always @(posedge i_clk)
casez(i_data[31:28])
4'b000?: b_len <= (i_data[16])? 4'h1:4'h2;
4'b0010: b_len <= 4'h3;
4'b0011: b_len <= 4'h4;
4'b0100: b_len <= 4'h5;
4'b0101: b_len <= 4'h6;
4'b0110: b_len <= 4'h7;
4'b0111: b_len <= 4'h8;
4'b1000: b_len <= 4'h9;
4'b1001: b_len <= 4'ha;
4'b1010: b_len <= 4'hb;
default: b_len <= 4'h0;
endcase
 
reg [87:0] r_sreg;
initial r_busy = 1'b0;
always @(posedge i_clk)
if ((~r_busy)&&(r_cstb))
begin
dev_wr <= 1'b0;
dev_dbit <= 1'b0;
r_sreg <= { r_data[23:0], r_a, r_b };
r_len <= b_len;
r_busy <= (b_len != 4'h0);
if (b_len == 4'h1)
r_sreg[87:72] <= { r_data[7:0], r_data[7:0] };
else if (b_len == 4'h2)
r_sreg[87:72] <= r_data[15:0];
else
r_sreg[87:72] <= r_data[23:8];
end else if ((~dev_busy)&&(r_dstb))
begin
dev_wr <= 1'b0;
dev_dbit <= 1'b1;
r_sreg <= { r_data[15:0], 72'h00 };
r_len <= 4'h2;
r_busy <= 1'b1;
end else if ((r_busy)&&(~dev_busy))
begin
dev_word <= r_sreg[87:56];
r_sreg <= { r_sreg[55:0], 32'h00 };
dev_len <= (r_len > 4'h4)? 2'b11:(r_len[1:0]+2'b11);
r_len <= (r_len > 4'h4) ? (r_len-4'h4):0;
end else if (r_busy)
r_busy <= (r_len != 4'h0);
 
assign o_int = (~r_busy);
 
endmodule
/rtl/memdev.v
0,0 → 1,73
///////////////////////////////////////////////////////////////////////////
//
// Filename: memdev.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: This file is really simple: it creates an on-chip memory,
// accessible via the wishbone bus, that can be used in this
// project. The memory has single cycle pipeline access, although the
// memory pipeline here still costs a cycle and there may be other cycles
// lost between the ZipCPU (or whatever is the master of the bus) and this,
// thus costing more cycles in access. Either way, operations can be
// pipelined for single cycle access on subsequent transactions.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
//
module memdev(i_clk, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
o_wb_ack, o_wb_stall, o_wb_data);
parameter AW=15, DW=32;
input i_clk, i_wb_cyc, i_wb_stb, i_wb_we;
input [(AW-1):0] i_wb_addr;
input [(DW-1):0] i_wb_data;
output reg o_wb_ack;
output wire o_wb_stall;
output reg [(DW-1):0] o_wb_data;
 
reg last_wstb, last_stb;
always @(posedge i_clk)
last_wstb <= (i_wb_stb)&&(i_wb_we);
always @(posedge i_clk)
last_stb <= (i_wb_stb);
 
reg [(DW-1):0] last_data;
reg [(AW-1):0] last_addr;
always @(posedge i_clk)
last_data <= i_wb_data;
always @(posedge i_clk)
last_addr <= i_wb_addr;
 
reg [(DW-1):0] mem [0:((1<<AW)-1)];
always @(posedge i_clk)
o_wb_data <= mem[last_addr];
always @(posedge i_clk)
if (last_wstb)
mem[last_addr] <= last_data;
always @(posedge i_clk)
o_wb_ack <= (last_stb);
assign o_wb_stall = 1'b0;
 
endmodule
/rtl/wbuinput.v
0,0 → 1,62
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wbuinput.v
//
// Project: FPGA library
//
// Purpose: Coordinates the receiption of bytes, which are then translated
// into codewords describing postential bus transactions. This
// includes turning the human readable bytes into more compact bits,
// forming those bits into codewords, and decompressing any that reference
// addresses within a compression table.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
module wbuinput(i_clk, i_stb, i_byte, o_stb, o_codword);
input i_clk, i_stb;
input [7:0] i_byte;
output wire o_stb;
output wire [35:0] o_codword;
 
wire hx_stb, hx_valid;
wire [5:0] hx_hexbits;
wbutohex tobits(i_clk, i_stb, i_byte,
hx_stb, hx_valid, hx_hexbits);
 
wire cw_stb;
wire [35:0] cw_word;
wbureadcw formcw(i_clk, hx_stb, hx_valid, hx_hexbits,
cw_stb, cw_word);
 
// `define DEBUGGING
`ifdef DEBUGGING
assign o_stb = cw_stb;
assign o_codword = cw_word;
`else
wbudecompress unpack(i_clk,cw_stb,cw_word, o_stb, o_codword);
`endif
 
endmodule
/rtl/wbusixchar.v
0,0 → 1,82
///////////////////////////////////////////////////////////////////////////
//
//
// Filename: wbusixchar.v
//
// Project: FPGA library
//
// Purpose: Supports a conversion from a six digit bus to a printable
// ASCII character representing those six bits. The encoding is
// as follows:
//
// 0-9 -> 0-9
// A-Z -> 10-35
// a-z -> 36-61
// @ -> 62
// % -> 63
//
// Note that decoding is stateless, yet requires one clock.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
//
//
module wbusixchar(i_clk, i_stb, i_bits, o_stb, o_char, o_busy, i_busy);
input i_clk;
input i_stb;
input [6:0] i_bits;
output reg o_stb;
output reg [7:0] o_char;
output wire o_busy;
input i_busy;
 
initial o_char = 8'h00;
always @(posedge i_clk)
if ((i_stb)&&(~o_busy))
begin
if (i_bits[6])
o_char <= 8'h0a;
else if (i_bits[5:0] <= 6'h09) // A digit, WORKS
o_char <= "0" + { 4'h0, i_bits[3:0] };
else if (i_bits[5:0] <= 6'd35) // Upper case
o_char <= "A" + { 2'h0, i_bits[5:0] } - 8'd10; // -'A'+10
else if (i_bits[5:0] <= 6'd61)
o_char <= "a" + { 2'h0, i_bits[5:0] } - 8'd36;// -'a'+(10+26)
else if (i_bits[5:0] == 6'd62) // An '@' sign
o_char <= 8'h40;
else // if (i_char == 6'h63) // A '%' sign
o_char <= 8'h25;
end
 
always @(posedge i_clk)
if ((o_stb)&&(~i_busy))
o_stb <= 1'b0;
else if ((i_stb)&&(~o_stb))
o_stb <= 1'b1;
 
assign o_busy = o_stb;
 
endmodule
 
/rtl/sdspi.v
0,0 → 1,1113
////////////////////////////////////////////////////////////////////////////////
//
// Filename: sdspi.v
//
// Project: SD-Card controller, using a shared SPI interface
//
// Purpose:
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 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 SDSPI_CMD_ADDRESS 2'h0
`define SDSPI_DAT_ADDRESS 2'h1
`define SDSPI_FIFO_A_ADDR 2'h2
`define SDSPI_FIFO_B_ADDR 2'h3
//
// `define SDSPI_CMD_ID 3'h0
// `define SDSPI_CMD_A1 3'h1
// `define SDSPI_CMD_A2 3'h2
// `define SDSPI_CMD_A3 3'h3
// `define SDSPI_CMD_A4 3'h4
// `define SDSPI_CMD_CRC 3'h5
// `define SDSPI_CMD_FIFO 3'h6
// `define SDSPI_CMD_WAIT 3'h7
//
`define SDSPI_EXPECT_R1 2'b00
`define SDSPI_EXPECT_R1B 2'b01
`define SDSPI_EXPECT_R3 2'b10
//
`define SDSPI_RSP_NONE 3'h0 // No response yet from device
`define SDSPI_RSP_BSYWAIT 3'h1 // R1b, wait for device to send nonzero
`define SDSPI_RSP_GETWORD 3'h2 // Get 32-bit data word from device
`define SDSPI_RSP_GETTOKEN 3'h4 // Write to device, read from FIFO, wait for completion token
`define SDSPI_RSP_WAIT_WHILE_BUSY 3'h5 // Read from device
`define SDSPI_RSP_RDCOMPLETE 3'h6
`define SDSPI_RSP_WRITING 3'h7 // Read from device, write into FIFO
//
module sdspi(i_clk,
// 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,
// SDCard interface
o_cs_n, o_sck, o_mosi, i_miso,
// Our interrupt
o_int,
// And whether or not we own the bus
i_bus_grant,
// And some wires for debugging it all
o_debug);
parameter LGFIFOLN = 7;
input i_clk;
//
input i_wb_cyc, i_wb_stb, i_wb_we;
input [1:0] i_wb_addr;
input [31:0] i_wb_data;
output reg o_wb_ack;
output wire o_wb_stall;
output reg [31:0] o_wb_data;
//
output wire o_cs_n, o_sck, o_mosi;
input i_miso;
// The interrupt
output reg o_int;
// .. and whether or not we can use the SPI port
input i_bus_grant;
//
output wire [31:0] o_debug;
 
//
// Some WB simplifications:
//
reg r_cmd_busy;
wire wb_stb, write_stb, cmd_stb; // read_stb
assign wb_stb = ((i_wb_cyc)&&(i_wb_stb)&&(~o_wb_stall));
assign write_stb = ((wb_stb)&&( i_wb_we));
// assign read_stb = ((wb_stb)&&(~i_wb_we));
assign cmd_stb = (~r_cmd_busy)&&(write_stb)
&&(i_wb_addr==`SDSPI_CMD_ADDRESS);
 
 
//
// Access to our lower-level SDSPI driver, the one that actually
// uses/sets the SPI ports
//
reg [6:0] r_sdspi_clk;
reg ll_cmd_stb;
reg [7:0] ll_cmd_dat;
wire ll_out_stb, ll_idle;
wire [7:0] ll_out_dat;
llsdspi lowlevel(i_clk, r_sdspi_clk, r_cmd_busy, ll_cmd_stb, ll_cmd_dat,
o_cs_n, o_sck, o_mosi, i_miso,
ll_out_stb, ll_out_dat, ll_idle,
i_bus_grant);
 
 
// CRC
reg r_cmd_crc_stb;
wire [7:0] cmd_crc;
// State machine
reg [2:0] r_cmd_state, r_rsp_state;
// Current status, beyond state
reg r_have_resp, r_use_fifo, r_fifo_wr,
ll_fifo_rd_complete, ll_fifo_wr_complete,
r_fifo_id,
ll_fifo_wr, ll_fifo_rd,
r_have_data_response_token,
r_have_start_token;
reg [7:0] fifo_byte;
reg [7:0] r_last_r_one;
//
reg [31:0] r_data_reg;
reg [1:0] r_data_fil, r_cmd_resp;
//
//
wire need_reset;
reg r_cmd_err;
reg r_cmd_sent;
reg [31:0] fifo_a_reg, fifo_b_reg;
//
reg q_busy;
//
reg [7:0] fifo_a_mem_0[0:((1<<LGFIFOLN)-1)],
fifo_a_mem_1[0:((1<<LGFIFOLN)-1)],
fifo_a_mem_2[0:((1<<LGFIFOLN)-1)],
fifo_a_mem_3[0:((1<<LGFIFOLN)-1)],
fifo_b_mem_0[0:((1<<LGFIFOLN)-1)],
fifo_b_mem_1[0:((1<<LGFIFOLN)-1)],
fifo_b_mem_2[0:((1<<LGFIFOLN)-1)],
fifo_b_mem_3[0:((1<<LGFIFOLN)-1)];
reg [(LGFIFOLN-1):0] fifo_wb_addr;
reg [(LGFIFOLN+1):0] rd_fifo_sd_addr;
reg [(LGFIFOLN+1):0] wr_fifo_sd_addr;
//
reg [(LGFIFOLN+1):0] ll_fifo_addr;
//
reg fifo_crc_err;
reg [1:0] ll_fifo_wr_state;
reg [7:0] fifo_a_byte, fifo_b_byte;
//
reg [2:0] ll_fifo_pkt_state;
reg fifo_rd_crc_stb, fifo_wr_crc_stb;
//
reg [3:0] fifo_rd_crc_count, fifo_wr_crc_count;
reg [15:0] fifo_rd_crc_reg, fifo_wr_crc_reg;
//
reg [3:0] r_cmd_crc_cnt;
reg [7:0] r_cmd_crc;
//
reg r_cmd_crc_ff;
//
reg [3:0] r_lgblklen;
wire [3:0] max_lgblklen;
assign max_lgblklen = LGFIFOLN;
//
reg [25:0] r_watchdog;
reg r_watchdog_err;
reg pre_cmd_state;
 
// Relieve some stress from the WB bus timing
reg new_data, new_cmd;
reg [31:0] r_wb_data;
always @(posedge i_clk)
new_data <= (write_stb)&&(i_wb_addr == `SDSPI_DAT_ADDRESS);
always @(posedge i_clk)
new_cmd <= (~r_cmd_busy)&&(write_stb)
&&(i_wb_addr==`SDSPI_CMD_ADDRESS);
always @(posedge i_clk)
r_wb_data <= i_wb_data;
 
initial r_cmd_busy = 1'b0;
initial r_data_reg = 32'h00;
initial r_last_r_one = 8'hff;
initial ll_cmd_stb = 1'b0;
initial ll_fifo_rd = 1'b0;
initial ll_fifo_wr = 1'b0;
initial r_rsp_state = 3'h0;
initial r_cmd_state = 3'h0;
initial r_use_fifo = 1'b0;
initial r_data_fil = 2'b00;
initial r_lgblklen = LGFIFOLN;
initial r_cmd_err = 1'b0;
always @(posedge i_clk)
begin
if (~ll_cmd_stb)
begin
r_have_resp <= 1'b0;
ll_fifo_wr <= 1'b0;
ll_fifo_rd <= 1'b0;
// r_rsp_state <= 3'h0;
r_cmd_state <= 3'h0;
r_use_fifo <= 1'b0;
r_data_fil <= 2'b00;
r_cmd_resp <= `SDSPI_EXPECT_R1;
end
 
r_cmd_crc_stb <= 1'b0;
if (pre_cmd_state)
begin // While we are actively sending data, and clocking the
// interface, do:
//
// Here we use the transmit command state, or
// r_cmd_state, to determine where we are at in this
// process, and we use (ll_cmd_stb)&&(ll_idle) to
// determine that we have sent a byte. ll_cmd_dat is
// set here as well--it's the byte we wish to transmit.
if (r_cmd_state == 3'h0)
begin
r_cmd_state <= r_cmd_state + 3'h1;
ll_cmd_dat <= r_data_reg[31:24];
r_cmd_crc_stb <= 1'b1;
end else if (r_cmd_state == 3'h1)
begin
r_cmd_state <= r_cmd_state + 3'h1;
ll_cmd_dat <= r_data_reg[23:16];
r_cmd_crc_stb <= 1'b1;
end else if (r_cmd_state == 3'h2)
begin
r_cmd_state <= r_cmd_state + 3'h1;
ll_cmd_dat <= r_data_reg[15:8];
r_cmd_crc_stb <= 1'b1;
end else if (r_cmd_state == 3'h3)
begin
r_cmd_state <= r_cmd_state + 3'h1;
ll_cmd_dat <= r_data_reg[7:0];
r_cmd_crc_stb <= 1'b1;
end else if (r_cmd_state == 3'h4)
begin
r_cmd_state <= r_cmd_state + 3'h1;
ll_cmd_dat <= cmd_crc;
end else if (r_cmd_state == 3'h5)
begin
ll_cmd_dat <= 8'hff;
if (r_have_resp)
begin
if (r_use_fifo)
r_cmd_state <= r_cmd_state + 3'h1;
else
r_cmd_state <= r_cmd_state + 3'h2;
ll_fifo_rd <= (r_use_fifo)&&(r_fifo_wr);
if ((r_use_fifo)&&(r_fifo_wr))
ll_cmd_dat <= 8'hfe;
end
end else if (r_cmd_state == 3'h6)
begin
ll_cmd_dat <= 8'hff;
if (ll_fifo_rd_complete)
begin // If we've finished reading from the
// FIFO, then move on
r_cmd_state <= r_cmd_state + 3'h1;
ll_fifo_rd <= 1'b0;
end else if (ll_fifo_rd)
ll_cmd_dat <= fifo_byte;
end else // if (r_cmd_state == 7)
ll_cmd_dat <= 8'hff;
 
 
// Here we handle the receive portion of the interface.
// Note that the IF begins with an if of ll_out_stb.
// That is, if a byte is ready from the lower level.
//
// Here we depend upon r_cmd_resp, the response we are
// expecting from the SDCard, and r_rsp_state, the
// state machine for where we are at receive what we
// are expecting.
if (pre_rsp_state)
begin
if (r_rsp_state == `SDSPI_RSP_NONE)
begin // Waiting on R1
if (~ll_out_dat[7])
begin
r_last_r_one <= ll_out_dat;
if (r_cmd_resp == `SDSPI_EXPECT_R1)
begin // Expecting R1 alone
r_have_resp <= 1'b1;
ll_cmd_stb <= (r_use_fifo);
r_data_reg <= 32'hffffffff;
ll_fifo_wr<=(r_use_fifo)&&(~r_fifo_wr);
end else if (r_cmd_resp == `SDSPI_EXPECT_R1B)
begin // Go wait on R1b
r_data_reg <= 32'hffffffff;
end // else wait on 32-bit rsp
end
end else if (r_rsp_state == `SDSPI_RSP_BSYWAIT)
begin // Waiting on R1b, have R1
if (nonzero_out)
r_have_resp <= 1'b1;
ll_cmd_stb <= (r_use_fifo);
end else if (r_rsp_state == `SDSPI_RSP_GETWORD)
begin // Have R1, waiting on all of R2/R3/R7
r_data_reg <= { r_data_reg[23:0], ll_out_dat };
r_data_fil <= r_data_fil+2'b01;
if (r_data_fil == 2'b11)
begin
ll_cmd_stb <= (r_use_fifo);
// r_rsp_state <= 3'h3;
end
end else if (r_rsp_state == `SDSPI_RSP_WAIT_WHILE_BUSY)
begin // Wait while device is busy writing
// if (nonzero_out)
// begin
// r_data_reg[31:8] <= 24'h00;
// r_data_reg[7:0] <= ll_out_dat;
// // r_rsp_state <= 3'h6;
// end
;
end else if (r_rsp_state == `SDSPI_RSP_RDCOMPLETE)
begin // Block write command has completed
ll_cmd_stb <= 1'b0;
end else if (r_rsp_state == `SDSPI_RSP_WRITING)
begin // We are reading from the device into
// our FIFO
if ((ll_fifo_wr_complete)
// Or ... we receive an error
||((~r_have_start_token)
&&(~ll_out_dat[4])
&&(ll_out_dat[0])))
begin
ll_fifo_wr <= 1'b0;
ll_cmd_stb <= 1'b0;
end
end
end
 
if (r_watchdog_err)
ll_cmd_stb <= 1'b0;
r_cmd_err<= (r_cmd_err)|(fifo_crc_err)|(r_watchdog_err);
end else if (r_cmd_busy)
begin
r_cmd_busy <= (ll_cmd_stb)||(~ll_idle);
end else if (new_cmd)
begin // Command write
// Clear the error on any write, whether a commanding
// one or not. -- provided the user requests clearing
// it (by setting the bit high)
r_cmd_err <= (r_cmd_err)&&(~r_wb_data[15]);
// In a similar fashion, we can switch fifos even if
// not in the middle of a command
r_fifo_id <= r_wb_data[12];
//
// Doesn't matter what this is set to as long as we
// aren't busy, so we can set it irrelevantly here.
ll_cmd_dat <= r_wb_data[7:0];
//
// Note that we only issue a write upon receiving a
// valid command. Such a command is 8 bits, and must
// start with its high order bits set to zero and one.
// Hence ... we test for that here.
if (r_wb_data[7:6] == 2'b01)
begin // Issue a command
//
r_cmd_busy <= 1'b1;
//
ll_cmd_stb <= 1'b1;
r_cmd_resp <= r_wb_data[9:8];
//
r_cmd_crc_stb <= 1'b1;
//
r_fifo_wr <= r_wb_data[10];
r_use_fifo <= r_wb_data[11];
//
end else if (r_wb_data[7])
// If, on the other hand, the command was invalid,
// then it must have been an attempt to read our
// internal configuration. So we'll place that on
// our data register.
r_data_reg <= { 8'h00,
4'h0, max_lgblklen,
4'h0, r_lgblklen, 1'b0, r_sdspi_clk };
end else if (new_data) // Data write
r_data_reg <= r_wb_data;
end
 
 
always @(posedge i_clk)
pre_cmd_state <= (ll_cmd_stb)&&(ll_idle);
 
reg ready_for_response_token;
always @(posedge i_clk)
if (~r_cmd_busy)
ready_for_response_token <= 1'b0;
else if (ll_fifo_rd)
ready_for_response_token <= 1'b1;
always @(posedge i_clk)
if (~r_cmd_busy)
r_have_data_response_token <= 1'b0;
else if ((ll_out_stb)&&(ready_for_response_token)&&(~ll_out_dat[4]))
r_have_data_response_token <= 1'b1;
 
reg [2:0] second_rsp_state;
always @(posedge i_clk)
if((r_cmd_resp == `SDSPI_EXPECT_R1)&&(r_use_fifo)&&(r_fifo_wr))
second_rsp_state <= `SDSPI_RSP_GETTOKEN;
else if (r_cmd_resp == `SDSPI_EXPECT_R1)
second_rsp_state <= `SDSPI_RSP_WRITING;
else if (r_cmd_resp == `SDSPI_EXPECT_R1B)
second_rsp_state <= `SDSPI_RSP_BSYWAIT;
else
second_rsp_state <= `SDSPI_RSP_GETWORD;
 
reg pre_rsp_state, nonzero_out;
always @(posedge i_clk)
if (ll_out_stb)
nonzero_out <= (|ll_out_dat);
always @(posedge i_clk)
pre_rsp_state <= (ll_out_stb)&&(r_cmd_sent);
 
// Each bit depends upon 8 bits of input
initial r_rsp_state = 3'h0;
always @(posedge i_clk)
if (~r_cmd_sent)
r_rsp_state <= 3'h0;
else if (pre_rsp_state)
begin
if ((r_rsp_state == `SDSPI_RSP_NONE)&&(~ll_out_dat[7]))
begin
r_rsp_state <= second_rsp_state;
end else if (r_rsp_state == `SDSPI_RSP_BSYWAIT)
begin // Waiting on R1b, have R1
// R1b never uses the FIFO
if (nonzero_out)
r_rsp_state <= 3'h6;
end else if (r_rsp_state == `SDSPI_RSP_GETWORD)
begin // Have R1, waiting on all of R2/R3/R7
if (r_data_fil == 2'b11)
r_rsp_state <= `SDSPI_RSP_RDCOMPLETE;
end else if (r_rsp_state == `SDSPI_RSP_GETTOKEN)
begin // Wait on data token response
if (r_have_data_response_token)
r_rsp_state <= `SDSPI_RSP_WAIT_WHILE_BUSY;
end else if (r_rsp_state == `SDSPI_RSP_WAIT_WHILE_BUSY)
begin // Wait while device is busy writing
if (nonzero_out)
r_rsp_state <= `SDSPI_RSP_RDCOMPLETE;
end
//else if (r_rsp_state == 3'h6)
//begin // Block write command has completed
// // ll_cmd_stb <= 1'b0;
// end else if (r_rsp_state == 3'h7)
// begin // We are reading from the device into
// // our FIFO
// end
end
 
always @(posedge i_clk)
r_cmd_sent <= (ll_cmd_stb)&&(r_cmd_state >= 3'h5);
 
// initial r_sdspi_clk = 6'h3c;
initial r_sdspi_clk = 7'h63;
always @(posedge i_clk)
begin
// Update our internal configuration parameters, unconnected
// with the card. These include the speed of the interface,
// and the size of the block length to expect as part of a FIFO
// command.
if ((new_cmd)&&(r_wb_data[7:6]==2'b11)&&(~r_data_reg[7])
&&(r_data_reg[15:12]==4'h00))
begin
if (|r_data_reg[6:0])
r_sdspi_clk <= r_data_reg[6:0];
if (|r_data_reg[11:8])
r_lgblklen <= r_data_reg[11:8];
end if (r_lgblklen > max_lgblklen)
r_lgblklen <= max_lgblklen;
end
 
assign need_reset = 1'b0;
always @(posedge i_clk)
case(i_wb_addr)
`SDSPI_CMD_ADDRESS:
o_wb_data <= { need_reset, 11'h00,
3'h0, fifo_crc_err,
r_cmd_err, r_cmd_busy, 1'b0, r_fifo_id,
r_use_fifo, r_fifo_wr, r_cmd_resp,
r_last_r_one };
`SDSPI_DAT_ADDRESS:
o_wb_data <= r_data_reg;
`SDSPI_FIFO_A_ADDR:
o_wb_data <= fifo_a_reg;
`SDSPI_FIFO_B_ADDR:
o_wb_data <= fifo_b_reg;
endcase
 
always @(posedge i_clk)
o_wb_ack <= wb_stb;
 
initial q_busy = 1'b1;
always @(posedge i_clk)
q_busy <= r_cmd_busy;
always @(posedge i_clk)
o_int <= (~r_cmd_busy)&&(q_busy);
 
assign o_wb_stall = 1'b0;
 
//
// Let's work with our FIFO memory here ...
//
//
always @(posedge i_clk)
begin
if ((write_stb)&&(i_wb_addr == `SDSPI_CMD_ADDRESS))
begin // Command write
// Clear the read/write address
fifo_wb_addr <= {(LGFIFOLN){1'b0}};
end else if ((wb_stb)&&(i_wb_addr[1]))
begin // On read or write, of either FIFO,
// we increase our pointer
fifo_wb_addr <= fifo_wb_addr + 1;
// And let ourselves know we need to update ourselves
// on the next clock
end
end
 
// Prepare reading of the FIFO for the WB bus read
// Memory read #1
always @(posedge i_clk)
begin
fifo_a_reg <= {
fifo_a_mem_0[ fifo_wb_addr ],
fifo_a_mem_1[ fifo_wb_addr ],
fifo_a_mem_2[ fifo_wb_addr ],
fifo_a_mem_3[ fifo_wb_addr ] };
fifo_b_reg <= {
fifo_b_mem_0[ fifo_wb_addr ],
fifo_b_mem_1[ fifo_wb_addr ],
fifo_b_mem_2[ fifo_wb_addr ],
fifo_b_mem_3[ fifo_wb_addr ] };
end
 
// Okay, now ... writing our FIFO ...
reg pre_fifo_addr_inc_rd;
reg pre_fifo_addr_inc_wr;
initial pre_fifo_addr_inc_rd = 1'b0;
initial pre_fifo_addr_inc_wr = 1'b0;
always @(posedge i_clk)
pre_fifo_addr_inc_wr <= ((ll_fifo_wr)&&(ll_out_stb)&&(r_have_start_token));
always @(posedge i_clk)
pre_fifo_addr_inc_rd <= ((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle));//&&(ll_fifo_pkt_state[2:0]!=3'b000));
always @(posedge i_clk)
begin
// if ((write_stb)&&(i_wb_addr == `SDSPI_CMD_ADDRESS)&&(i_wb_data[11]))
// ll_fifo_addr <= {(LGFIFOLN+2){1'b0}};
if (~r_cmd_busy)
ll_fifo_addr <= {(LGFIFOLN+2){1'b0}};
else if ((pre_fifo_addr_inc_wr)||(pre_fifo_addr_inc_rd))
ll_fifo_addr <= ll_fifo_addr + 1;
end
 
// Look for that start token
always @(posedge i_clk)
if (~r_cmd_busy)
r_have_start_token <= 1'b0;
else if ((ll_fifo_wr)&&(ll_out_stb)&&(ll_out_dat==8'hfe))
r_have_start_token <= 1'b1;
 
reg last_fifo_byte;
initial last_fifo_byte = 1'b0;
always @(posedge i_clk)
if (ll_fifo_wr)
last_fifo_byte <= (ll_fifo_addr == w_blklimit);
else
last_fifo_byte <= 1'b0;
 
// This is the one (and only allowed) write to the FIFO memory always
// block.
//
// If ll_fifo_wr is true, we'll be writing to the FIFO, and we'll do
// that here. This is different from r_fifo_wr, which specifies that
// we will be writing to the SDCard from the FIFO, and hence READING
// from the FIFO.
//
reg pre_fifo_a_wr, pre_fifo_b_wr, pre_fifo_crc_a, pre_fifo_crc_b,
clear_fifo_crc;
always @(posedge i_clk)
begin
pre_fifo_a_wr <= (ll_fifo_wr)&&(ll_out_stb)&&(~r_fifo_id)&&(ll_fifo_wr_state == 2'b00);
pre_fifo_b_wr <= (ll_fifo_wr)&&(ll_out_stb)&&( r_fifo_id)&&(ll_fifo_wr_state == 2'b00);
fifo_wr_crc_stb <= (ll_fifo_wr)&&(ll_out_stb)&&(ll_fifo_wr_state == 2'b00)&&(r_have_start_token);
pre_fifo_crc_a<= (ll_fifo_wr)&&(ll_out_stb)&&(ll_fifo_wr_state == 2'b01);
pre_fifo_crc_b<= (ll_fifo_wr)&&(ll_out_stb)&&(ll_fifo_wr_state == 2'b10);
clear_fifo_crc <= (new_cmd)&&(r_wb_data[15]);
end
 
reg fifo_a_wr, fifo_b_wr;
reg [3:0] fifo_a_wr_mask, fifo_b_wr_mask;
reg [(LGFIFOLN-1):0] fifo_a_wr_addr, fifo_b_wr_addr;
reg [31:0] fifo_a_wr_data, fifo_b_wr_data;
 
initial fifo_crc_err = 1'b0;
always @(posedge i_clk)
begin // One and only memory write allowed
fifo_a_wr <= 1'b0;
fifo_a_wr_data <= { ll_out_dat, ll_out_dat, ll_out_dat, ll_out_dat };
if ((write_stb)&&(i_wb_addr[1:0]==2'b10))
begin
fifo_a_wr <= 1'b1;
fifo_a_wr_mask <= 4'b1111;
fifo_a_wr_addr <= fifo_wb_addr;
fifo_a_wr_data <= i_wb_data;
end else if (pre_fifo_a_wr)
begin
fifo_a_wr <= 1'b1;
fifo_a_wr_addr <= ll_fifo_addr[(LGFIFOLN+1):2];
case(ll_fifo_addr[1:0])
2'b00: fifo_a_wr_mask <= 4'b0001;
2'b01: fifo_a_wr_mask <= 4'b0010;
2'b10: fifo_a_wr_mask <= 4'b0100;
2'b11: fifo_a_wr_mask <= 4'b1000;
endcase
end
 
if ((fifo_a_wr)&&(fifo_a_wr_mask[0]))
fifo_a_mem_0[fifo_a_wr_addr] <= fifo_a_wr_data[7:0];
if ((fifo_a_wr)&&(fifo_a_wr_mask[1]))
fifo_a_mem_1[fifo_a_wr_addr] <= fifo_a_wr_data[15:8];
if ((fifo_a_wr)&&(fifo_a_wr_mask[2]))
fifo_a_mem_2[fifo_a_wr_addr] <= fifo_a_wr_data[23:16];
if ((fifo_a_wr)&&(fifo_a_wr_mask[3]))
fifo_a_mem_3[fifo_a_wr_addr] <= fifo_a_wr_data[31:24];
 
fifo_b_wr <= 1'b0;
fifo_b_wr_data <= { ll_out_dat, ll_out_dat, ll_out_dat, ll_out_dat };
if ((write_stb)&&(i_wb_addr[1:0]==2'b11))
begin
fifo_b_wr <= 1'b1;
fifo_b_wr_mask <= 4'b1111;
fifo_b_wr_addr <= fifo_wb_addr;
fifo_b_wr_data <= i_wb_data;
end else if (pre_fifo_b_wr)
begin
fifo_b_wr <= 1'b1;
fifo_b_wr_addr <= ll_fifo_addr[(LGFIFOLN+1):2];
case(ll_fifo_addr[1:0])
2'b00: fifo_b_wr_mask <= 4'b0001;
2'b01: fifo_b_wr_mask <= 4'b0010;
2'b10: fifo_b_wr_mask <= 4'b0100;
2'b11: fifo_b_wr_mask <= 4'b1000;
endcase
end
 
if ((fifo_b_wr)&&(fifo_b_wr_mask[0]))
fifo_b_mem_0[fifo_b_wr_addr] <= fifo_b_wr_data[7:0];
if ((fifo_b_wr)&&(fifo_b_wr_mask[1]))
fifo_b_mem_1[fifo_b_wr_addr] <= fifo_b_wr_data[15:8];
if ((fifo_b_wr)&&(fifo_b_wr_mask[2]))
fifo_b_mem_2[fifo_b_wr_addr] <= fifo_b_wr_data[23:16];
if ((fifo_b_wr)&&(fifo_b_wr_mask[3]))
fifo_b_mem_3[fifo_b_wr_addr] <= fifo_b_wr_data[31:24];
 
if (~r_cmd_busy)
ll_fifo_wr_complete <= 1'b0;
 
if (~r_cmd_busy)
ll_fifo_wr_state <= 2'b00;
else if ((pre_fifo_a_wr)||(pre_fifo_b_wr))
ll_fifo_wr_state <= (last_fifo_byte)? 2'b01:2'b00;
 
if (pre_fifo_crc_a)
begin
fifo_crc_err <= fifo_crc_err | (fifo_wr_crc_reg[15:8]!=ll_out_dat);
ll_fifo_wr_state <= ll_fifo_wr_state + 2'b01;
end if (pre_fifo_crc_b)
begin
fifo_crc_err <= fifo_crc_err | (fifo_wr_crc_reg[7:0]!=ll_out_dat);
ll_fifo_wr_state <= ll_fifo_wr_state + 2'b01;
ll_fifo_wr_complete <= 1'b1;
end else if (clear_fifo_crc)
fifo_crc_err <= 1'b0;
end
 
always @(posedge i_clk)
begin // Second memory read, this time for the FIFO
case(ll_fifo_addr[1:0])
2'b00: begin
fifo_a_byte<=fifo_a_mem_0[ll_fifo_addr[(LGFIFOLN+1):2]];
fifo_b_byte<=fifo_b_mem_0[ll_fifo_addr[(LGFIFOLN+1):2]];
end
2'b01: begin
fifo_a_byte<=fifo_a_mem_1[ll_fifo_addr[(LGFIFOLN+1):2]];
fifo_b_byte<=fifo_b_mem_1[ll_fifo_addr[(LGFIFOLN+1):2]];
end
2'b10: begin
fifo_a_byte<=fifo_a_mem_2[ll_fifo_addr[(LGFIFOLN+1):2]];
fifo_b_byte<=fifo_b_mem_2[ll_fifo_addr[(LGFIFOLN+1):2]];
end
2'b11: begin
fifo_a_byte<=fifo_a_mem_3[ll_fifo_addr[(LGFIFOLN+1):2]];
fifo_b_byte<=fifo_b_mem_3[ll_fifo_addr[(LGFIFOLN+1):2]];
end
endcase
end
 
reg [(LGFIFOLN-1):0] r_blklimit;
wire [(LGFIFOLN+1):0] w_blklimit;
always @(posedge i_clk)
r_blklimit[(LGFIFOLN-1):0] = (1<<r_lgblklen)-1;
assign w_blklimit = { r_blklimit, 2'b11 };
 
// Package the FIFO reads up into a packet
always @(posedge i_clk)
begin
fifo_rd_crc_stb <= 1'b0;
if (r_cmd_busy)
begin
if (ll_fifo_pkt_state[2:0] == 3'b000)
begin
if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
begin
ll_fifo_pkt_state <= ll_fifo_pkt_state + 3'b001;
end
end else if (ll_fifo_pkt_state[2:0] == 3'b001)
begin
if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
begin
ll_fifo_pkt_state <= ll_fifo_pkt_state + 3'b001;
fifo_byte <= (r_fifo_id)
? fifo_b_byte : fifo_a_byte;
fifo_rd_crc_stb <= 1'b1;
end
end else if (ll_fifo_pkt_state[2:0] == 3'b010)
begin
if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
begin
fifo_byte <= (r_fifo_id)
? fifo_b_byte : fifo_a_byte;
fifo_rd_crc_stb <= 1'b1;
end
if (ll_fifo_addr == 0)
ll_fifo_pkt_state <= 3'b011;
end else if (ll_fifo_pkt_state == 3'b011)
begin // 1st CRC byte
if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
begin
fifo_byte <= fifo_rd_crc_reg[15:8];
ll_fifo_pkt_state <= 3'b100;
end
end else if (ll_fifo_pkt_state == 3'b100)
begin // 2nd CRC byte
if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
begin
fifo_byte <= fifo_rd_crc_reg[7:0];
ll_fifo_pkt_state <= 3'b101;
end
end else if((ll_fifo_rd)&&(ll_cmd_stb)&&(ll_idle))
begin
// Idle the channel
ll_fifo_rd_complete <= 1'b1;
fifo_byte <= 8'hff;
end
end else if ((write_stb)&&(i_wb_addr == `SDSPI_CMD_ADDRESS))
begin
ll_fifo_pkt_state <= 3'h0;
ll_fifo_rd_complete <= 1'b0;
fifo_byte <= (i_wb_data[12]) ? fifo_b_byte : fifo_a_byte;
fifo_rd_crc_stb <= 1'b1;
end else begin // Packet state is IDLE (clear the CRC registers)
ll_fifo_pkt_state <= 3'b111;
ll_fifo_rd_complete <= 1'b1;
end
end
 
always @(posedge i_clk)
begin
if (~ll_fifo_wr)
fifo_wr_crc_reg <= 16'h00;
else if (fifo_wr_crc_stb)
begin
fifo_wr_crc_reg[15:8] <=fifo_wr_crc_reg[15:8]^ll_out_dat;
fifo_wr_crc_count <= 4'h8;
end else if (|fifo_wr_crc_count)
begin
fifo_wr_crc_count <= fifo_wr_crc_count - 4'h1;
if (fifo_wr_crc_reg[15])
fifo_wr_crc_reg <= { fifo_wr_crc_reg[14:0], 1'b0 }
^ 16'h1021;
else
fifo_wr_crc_reg <= { fifo_wr_crc_reg[14:0], 1'b0 };
end
end
 
always @(posedge i_clk)
begin
if (~r_cmd_busy)
begin
fifo_rd_crc_reg <= 16'h00;
fifo_rd_crc_count <= 4'h0;
end else if (fifo_rd_crc_stb)
begin
fifo_rd_crc_reg[15:8] <=fifo_rd_crc_reg[15:8]^fifo_byte;
fifo_rd_crc_count <= 4'h8;
end else if (|fifo_rd_crc_count)
begin
fifo_rd_crc_count <= fifo_rd_crc_count - 4'h1;
if (fifo_rd_crc_reg[15])
fifo_rd_crc_reg <= { fifo_rd_crc_reg[14:0], 1'b0 }
^ 16'h1021;
else
fifo_rd_crc_reg <= { fifo_rd_crc_reg[14:0], 1'b0 };
end
end
 
//
// Calculate a CRC for the command section of our output
//
initial r_cmd_crc_ff = 1'b0;
always @(posedge i_clk)
begin
if (~r_cmd_busy)
begin
r_cmd_crc <= 8'h00;
r_cmd_crc_cnt <= 4'hf;
r_cmd_crc_ff <= 1'b0;
end else if (~r_cmd_crc_cnt[3])
begin
r_cmd_crc_cnt <= r_cmd_crc_cnt - 4'h1;
if (r_cmd_crc[7])
r_cmd_crc <= { r_cmd_crc[6:0], 1'b0 } ^ 8'h12;
else
r_cmd_crc <= { r_cmd_crc[6:0], 1'b0 };
r_cmd_crc_ff <= (r_cmd_crc_ff)||(r_cmd_crc_stb);
end else if ((r_cmd_crc_stb)||(r_cmd_crc_ff))
begin
r_cmd_crc <= r_cmd_crc ^ ll_cmd_dat;
r_cmd_crc_cnt <= 4'h7;
r_cmd_crc_ff <= 1'b0;
end
end
assign cmd_crc = { r_cmd_crc[7:1], 1'b1 };
 
//
// Some watchdog logic for us. This way, if we are waiting for the
// card to respond, and something goes wrong, we can timeout the
// transaction and ... figure out what to do about it later. At least
// we'll have an error indication.
//
initial r_watchdog = 26'h3ffffff;
initial r_watchdog_err = 1'b0;
always @(posedge i_clk)
if (~r_cmd_busy)
r_watchdog_err <= 1'b0;
else if (r_watchdog == 0)
r_watchdog_err <= 1'b1;
always @(posedge i_clk)
if (~r_cmd_busy)
r_watchdog <= 26'h3fffff;
else if (|r_watchdog)
r_watchdog <= r_watchdog - 26'h1;
 
assign o_debug = { ((ll_cmd_stb)&&(ll_idle))||(ll_out_stb),
ll_cmd_stb, ll_idle, ll_out_stb, // 4'h
o_cs_n, o_sck, o_mosi, i_miso, // 4'h
r_cmd_state, i_bus_grant, // 4'h
r_rsp_state, r_cmd_busy, // 4'h
ll_cmd_dat, // 8'b
ll_out_dat }; // 8'b
endmodule
 
////////////////////////////////////////////////////////////////////////////////
//
// Filename: llsdspi.v
//
// Project: SD-Card controller, using a shared SPI interface
//
// Purpose: This file implements the "lower-level" interface to the
// SD-Card controller. Specifically, it turns byte-level
// interaction requests into SPI bit-wise interactions. Further, it
// handles the request and grant for the SPI wires (i.e., it requests
// the SPI port by pulling o_cs_n low, and then waits for i_bus_grant
// to be true before continuing.). Finally, the speed/clock rate of the
// communication is adjustable as a division of the current clock rate.
//
// i_speed
// This is the number of clocks (minus one) between SPI clock
// transitions. Hence a '0' (not tested, doesn't work) would
// result in a SPI clock that alternated on every input clock
// equivalently dividing the input clock by two, whereas a '1'
// would divide the input clock by four.
//
// In general, the SPI clock frequency will be given by the
// master clock frequency divided by twice this number plus one.
// In other words,
//
// SPIFREQ=(i_clk FREQ) / (2*(i_speed+1))
//
// i_stb
// True if the master controller is requesting to send a byte.
// This will be ignored unless o_idle is false.
//
// i_byte
// The byte that the master controller wishes to send across the
// interface.
//
// (The external SPI interface)
//
// o_stb
// Only true for one clock--when a byte is valid coming in from the
// interface, this will be true for one clock (a strobe) indicating
// that a valid byte is ready to be read.
//
// o_byte
// The value of the byte coming in.
//
// o_idle
// True if this low-level device handler is ready to accept a
// byte from the incoming interface, false otherwise.
//
// i_bus_grant
// True if the SPI bus has been granted to this interface, false
// otherwise. This has been placed here so that the interface of
// the XuLA2 board may be shared between SPI-Flash and the SPI
// based SDCard. An external arbiter will determine which of the
// two gets to control the clock and mosi outputs given their
// cs_n requests. If control is not granted, i_bus_grant will
// remain low as will the actual cs_n going out of the FPGA.
//
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 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 LLSDSPI_IDLE 4'h0
`define LLSDSPI_HOTIDLE 4'h1
`define LLSDSPI_WAIT 4'h2
`define LLSDSPI_START 4'h3
//
module llsdspi(i_clk, i_speed, i_cs, i_stb, i_byte,
o_cs_n, o_sclk, o_mosi, i_miso,
o_stb, o_byte, o_idle, i_bus_grant);
parameter SPDBITS = 7;
//
input i_clk;
// Parameters/setup
input [(SPDBITS-1):0] i_speed;
// The incoming interface
input i_cs;
input i_stb;
input [7:0] i_byte;
// The actual SPI interface
output reg o_cs_n, o_sclk, o_mosi;
input i_miso;
// The outgoing interface
output reg o_stb;
output reg [7:0] o_byte;
output wire o_idle;
// And whether or not we actually own the interface (yet)
input i_bus_grant;
 
reg r_z_counter;
reg [(SPDBITS-1):0] r_clk_counter;
reg r_idle;
reg [3:0] r_state;
reg [7:0] r_byte, r_ireg;
 
wire byte_accepted;
assign byte_accepted = (i_stb)&&(o_idle);
 
initial r_clk_counter = 7'h0;
always @(posedge i_clk)
begin
if ((~i_cs)||(~i_bus_grant))
r_clk_counter <= 0;
else if (byte_accepted)
r_clk_counter <= i_speed;
else if (~r_z_counter)
r_clk_counter <= (r_clk_counter - {{(SPDBITS-1){1'b0}},1'b1});
else if ((r_state != `LLSDSPI_IDLE)&&(r_state != `LLSDSPI_HOTIDLE))
r_clk_counter <= (i_speed);
// else
// r_clk_counter <= 16'h00;
end
 
initial r_z_counter = 1'b1;
always @(posedge i_clk)
begin
if ((~i_cs)||(~i_bus_grant))
r_z_counter <= 1'b1;
else if (byte_accepted)
r_z_counter <= 1'b0;
else if (~r_z_counter)
r_z_counter <= (r_clk_counter == 1);
else if ((r_state != `LLSDSPI_IDLE)&&(r_state != `LLSDSPI_HOTIDLE))
r_z_counter <= 1'b0;
end
 
initial r_state = `LLSDSPI_IDLE;
always @(posedge i_clk)
begin
o_stb <= 1'b0;
o_cs_n <= ~i_cs;
if (~i_cs)
begin
r_state <= `LLSDSPI_IDLE;
r_idle <= 1'b0;
o_sclk <= 1'b1;
end else if (~r_z_counter)
begin
r_idle <= 1'b0;
if (byte_accepted)
begin // Will only happen within a hot idle state
r_byte <= { i_byte[6:0], 1'b1 };
r_state <= `LLSDSPI_START+1;
o_mosi <= i_byte[7];
end
end else if (r_state == `LLSDSPI_IDLE)
begin
o_sclk <= 1'b1;
if (byte_accepted)
begin
r_byte <= i_byte[7:0];
r_state <= (i_bus_grant)?`LLSDSPI_START:`LLSDSPI_WAIT;
r_idle <= 1'b0;
o_mosi <= i_byte[7];
end else begin
r_idle <= 1'b1;
end
end else if (r_state == `LLSDSPI_WAIT)
begin
r_idle <= 1'b0;
if (i_bus_grant)
r_state <= `LLSDSPI_START;
end else if (r_state == `LLSDSPI_HOTIDLE)
begin
// The clock is low, the bus is granted, we're just
// waiting for the next byte to transmit
o_sclk <= 1'b0;
if (byte_accepted)
begin
r_byte <= i_byte[7:0];
r_state <= `LLSDSPI_START;
r_idle <= 1'b0;
o_mosi <= i_byte[7];
end else
r_idle <= 1'b1;
// end else if (r_state == `LLSDSPI_START)
// begin
// o_sclk <= 1'b0;
// r_state <= r_state + 1;
end else if (o_sclk)
begin
o_mosi <= r_byte[7];
r_byte <= { r_byte[6:0], 1'b1 };
r_state <= r_state + 1;
o_sclk <= 1'b0;
if (r_state >= `LLSDSPI_START+8)
begin
r_state <= `LLSDSPI_HOTIDLE;
r_idle <= 1'b1;
o_stb <= 1'b1;
o_byte <= r_ireg;
end else
r_state <= r_state + 1;
end else begin
r_ireg <= { r_ireg[6:0], i_miso };
o_sclk <= 1'b1;
end
end
 
assign o_idle = (r_idle)&&( (i_cs)&&(i_bus_grant) );
endmodule
 
 
/rtl/wbudecompress.v
0,0 → 1,150
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wbudecompress.v
//
// Project: FPGA library
//
// Purpose: Compression via this interface is simply a lookup table.
// When writing, if requested, rather than writing a new 36-bit
// word, we may be asked to repeat a word that's been written recently.
// That's the goal of this routine: if given a word's (relative) address
// in the write stream, we use that address, else we expect a full 32-bit
// word to come in to be written.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
module wbudecompress(i_clk, i_stb, i_word, o_stb, o_word);
input i_clk, i_stb;
input [35:0] i_word;
output reg o_stb;
output reg [35:0] o_word;
 
 
// Clock zero
// { o_stb, r_stb } = 0
wire cmd_write_not_compressed = (i_word[35:33] == 3'h3);
 
 
// Clock one: { o_stb, r_stb } = 4'h1 when done
reg [7:0] wr_addr;
initial wr_addr = 8'h0;
always @(posedge i_clk)
if ((i_stb)&&(cmd_write_not_compressed))
wr_addr <= wr_addr + 8'h1;
 
reg [31:0] compression_tbl [0:255];
always @(posedge i_clk)
if (i_stb)
compression_tbl[wr_addr] <= { i_word[32:31], i_word[29:0] };
 
reg [35:0] r_word;
always @(posedge i_clk)
if (i_stb)
r_word <= i_word;
 
 
// Clock two, calculate the table address ... 1 is the smallest address
// { o_stb, r_stb } = 4'h2 when done
reg [7:0] cmd_addr;
always @(posedge i_clk)
cmd_addr = wr_addr - { r_word[32:31], r_word[29:24] };
 
// Let's also calculate the address, in case this is a compressed
// address word
reg [24:0] r_addr;
always @(posedge i_clk)
case(r_word[32:30])
3'b000: r_addr <= { 19'h0, r_word[29:24] };
3'b010: r_addr <= { 13'h0, r_word[29:18] };
3'b100: r_addr <= { 7'h0, r_word[29:12] };
3'b110: r_addr <= { 1'h0, r_word[29: 6] };
3'b001: r_addr <= { {(19){ r_word[29]}}, r_word[29:24] };
3'b011: r_addr <= { {(13){ r_word[29]}}, r_word[29:18] };
3'b101: r_addr <= { {( 7){ r_word[29]}}, r_word[29:12] };
3'b111: r_addr <= { {( 1){ r_word[29]}}, r_word[29: 6] };
endcase
wire [31:0] w_addr;
assign w_addr = { {(7){r_addr[24]}}, r_addr };
 
reg [9:0] rd_len;
always @(posedge i_clk)
if (~r_word[34])
rd_len <= 10'h01 + { 6'h00, r_word[33:31] };
else
rd_len <= 10'h09 + { 1'b0, r_word[33:31], r_word[29:24] };
// Clock three, read the table value
// { o_stb, r_stb } = 4'h4 when done
// Maintaining ...
// r_word (clock 1)
// r_addr, rd_len (clock 2)
reg [31:0] cword;
always @(posedge i_clk)
cword <= compression_tbl[cmd_addr];
 
 
// Pipeline the strobe signal to create an output strobe, 3 clocks later
reg [2:0] r_stb;
initial r_stb = 0;
always @(posedge i_clk)
r_stb <= { r_stb[1:0], i_stb };
 
// Clock four, now that the table value is valid, let's set our output
// word.
// { o_stb, r_stb } = 4'h8 when done
always @(posedge i_clk)
o_stb <= r_stb[2];
// Maintaining ...
// r_word (clock 1)
// r_addr, rd_len (clock 2)
// cword (clock 3)
// Any/all of these can be pipelined for faster operation
// However, speed is really limited by the speed of the I/O port. At
// it's fastest, it's 1 bit per clock, 48 clocks per codeword therefore,
// thus ... things will hold still for much longer than just 5 clocks.
always @(posedge i_clk)
if (r_word[35:30] == 6'b101110)
o_word <= r_word;
else casez(r_word[35:30])
// Set address from something compressed ... unsigned
6'b001??0: o_word <= { 4'h0, w_addr[31:0] };
// Set a new address as a signed offset from the last (set) one
// (The last address is kept further down the chain,
// we just mark here that the address is to be set
// relative to it, and by how much.)
6'b001??1: o_word <= { 3'h1, w_addr[31:30], 1'b1, w_addr[29:0]};
// Write a value to the bus, with the value given from our
// codeword table
6'b010???: o_word <=
{ 3'h3, cword[31:30], r_word[30], cword[29:0] };
// Read, highly compressed length (1 word)
6'b10????: o_word <= { 5'b11000, r_word[30], 20'h00, rd_len };
// Read, two word (3+9 bits) length
6'b11????: o_word <= { 5'b11000, r_word[30], 20'h00, rd_len };
default: o_word <= r_word;
endcase
endmodule
 
/rtl/cpu/fastops.v
0,0 → 1,304
///////////////////////////////////////////////////////////////////////////
//
// Filename: fastops.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: This supports the instruction set reordering of operations
// created by the second generation instruction set, as well as
// the new operations of POPC (population count) and BREV (bit reversal).
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
module fastops(i_clk,i_rst, i_ce, i_valid, i_op, i_a, i_b, o_c, o_f, o_valid,
o_illegal, o_busy);
input i_clk, i_rst, i_ce;
input [3:0] i_op;
input [31:0] i_a, i_b;
input i_valid;
output reg [31:0] o_c;
output wire [3:0] o_f;
output wire o_valid;
output wire o_illegal;
output wire o_busy;
 
// Rotate-left logic
wire [63:0] w_rol_tmp;
assign w_rol_tmp = { i_a, i_a } << i_b[4:0];
reg [31:0] r_rol_result;
always @(posedge i_clk)
r_rol_result <= w_rol_tmp[63:32]; // Won't set flags
 
// Shift register logic
reg [32:0] r_lsr_result, r_asr_result, r_lsl_result;
always @(posedge i_clk)
begin
r_asr_result <= (|i_b[31:5])? {(33){i_a[31]}}
: ( $signed({i_a, 1'b0 })>>> (i_b[4:0]) );// ASR
r_lsr_result <= (|i_b[31:5])? 33'h00
: ( { i_a, 1'b0 } >> (i_b[4:0]) );// LSR
r_lsl_result <= (|i_b[31:5])? 33'h00 : {1'b0, i_a } << i_b[4:0]; // LSL
end
 
// Bit reversal pre-logic
wire [31:0] w_brev_result;
reg [31:0] r_brev_result;
genvar k;
generate
for(k=0; k<32; k=k+1)
begin : bit_reversal_cpuop
assign w_brev_result[k] = i_b[31-k];
end endgenerate
always @(posedge i_clk)
r_brev_result <= w_brev_result;
 
// Popcount logic
wire [31:0] w_popc_result;
reg [5:0] r_popc_result;
always @(posedge i_clk)
r_popc_result =
({5'h0,i_b[ 0]}+{5'h0,i_b[ 1]}+{5'h0,i_b[ 2]}+{5'h0,i_b[ 3]})
+({5'h0,i_b[ 4]}+{5'h0,i_b[ 5]}+{5'h0,i_b[ 6]}+{5'h0,i_b[ 7]})
+({5'h0,i_b[ 8]}+{5'h0,i_b[ 9]}+{5'h0,i_b[10]}+{5'h0,i_b[11]})
+({5'h0,i_b[12]}+{5'h0,i_b[13]}+{5'h0,i_b[14]}+{5'h0,i_b[15]})
+({5'h0,i_b[16]}+{5'h0,i_b[17]}+{5'h0,i_b[18]}+{5'h0,i_b[19]})
+({5'h0,i_b[20]}+{5'h0,i_b[21]}+{5'h0,i_b[22]}+{5'h0,i_b[23]})
+({5'h0,i_b[24]}+{5'h0,i_b[25]}+{5'h0,i_b[26]}+{5'h0,i_b[27]})
+({5'h0,i_b[28]}+{5'h0,i_b[29]}+{5'h0,i_b[30]}+{5'h0,i_b[31]});
assign w_popc_result = { 26'h00, r_popc_result };
 
// Prelogic for our flags registers
wire z, n, v;
reg c, pre_sign, set_ovfl;
always @(posedge i_clk)
if (i_ce) // 1 LUT
set_ovfl =(((i_op==4'h0)&&(i_a[31] != i_b[31]))//SUB&CMP
||((i_op==4'h2)&&(i_a[31] == i_b[31])) // ADD
||(i_op == 4'h6) // LSL
||(i_op == 4'h5)); // LSR
 
reg [31:0] r_logical;
always @(posedge i_clk)
r_logical <= (i_op[0]) ? (i_a & i_b) : (i_a | i_b);
 
reg [32:0] r_sum, r_diff;
reg [31:0] r_ldilo, r_bypass, r_xor;
always @(posedge i_clk)
r_sum <= i_a + i_b; // Add
always @(posedge i_clk)
r_diff <= {1'b0, i_a } - { 1'b0, i_b }; // SUB
always @(posedge i_clk)
r_xor <= i_a ^ i_b; // XOR
always @(posedge i_clk)
r_ldilo <= { i_a[31:16], i_b[15:0] }; // LDILO
always @(posedge i_clk)
r_bypass <= i_b; // LOD/MOV,ETC
 
reg mpyhi;
wire mpybusy;
 
//
// Multiply logic
//
reg [63:0] r_mpy_result; // Our final goal
 
// The three clock option
reg [31:0] r_mpy_a_input, r_mpy_b_input;
reg r_mpy_signed;
reg [1:0] mpypipe;
 
wire mpy;
assign mpy = (i_op[3:1] == 3'h5)||(i_op[3:0] != 4'h8);
 
// First clock, latch in the inputs
always @(posedge i_clk)
begin
if (i_op[0]) // i.e. if signed multiply
begin
r_mpy_a_input <= {(~i_a[31]),i_a[30:0]};
r_mpy_b_input <= {(~i_b[31]),i_b[30:0]};
end else begin
r_mpy_a_input <= i_a[31:0];
r_mpy_b_input <= i_b[31:0];
end
// The signed bit really only matters in the case of 64 bit
// multiply. We'll keep track of it, though, and pretend in
// all other cases.
r_mpy_signed <= i_op[0];
 
mpyhi = i_op[1];
end
 
// Second clock, do the multiplies, get the "partial products". Here,
// we break our input up into two halves,
//
// A = (2^16 ah + al)
// B = (2^16 bh + bl)
//
// and use these to compute partial products.
//
// AB = (2^32 ah*bh + 2^16 (ah*bl + al*bh) + (al*bl)
//
// Since we're following the FOIL algorithm to get here,
// we'll name these partial products according to FOIL.
//
// The trick is what happens if A or B is signed. In
// those cases, the real value of A will not be given by
// A = (2^16 ah + al)
// but rather
// A = (2^16 ah[31^] + al) - 2^31
// (where we have flipped the sign bit of A) and so ...
//
// AB= (2^16 ah + al - 2^31) * (2^16 bh + bl - 2^31)
// = 2^32(ah*bh)
// +2^16 (ah*bl+al*bh)
// +(al*bl)
// - 2^31 (2^16 bh+bl + 2^16 ah+al)
// - 2^62
// = 2^32(ah*bh)
// +2^16 (ah*bl+al*bh)
// +(al*bl)
// - 2^31 (2^16 bh+bl + 2^16 ah+al + 2^31)
//
reg [31:0] pp_f, pp_o, pp_i, pp_l; // F, O, I and L from FOIL
reg [32:0] pp_s;
always @(posedge i_clk)
begin
pp_f<=r_mpy_a_input[31:16]*r_mpy_b_input[31:16];
pp_o<=r_mpy_a_input[31:16]*r_mpy_b_input[15: 0];
pp_i<=r_mpy_a_input[15: 0]*r_mpy_b_input[31:16];
pp_l<=r_mpy_a_input[15: 0]*r_mpy_b_input[15: 0];
// And a special one for the sign
if (r_mpy_signed)
pp_s <= 32'h8000_0000-( r_mpy_a_input[31:0]
+ r_mpy_b_input[31:0]);
else
pp_s <= 33'h0;
end
 
// Third clock, add the results and produce a product
// r_mpy_result[63:16] <=
// { 32'h00, pp_l[31:16] }
// + { 16'h00, pp_o }
// + { 16'h00, pp_i }
// + { pp_s, 15'h00 }
// + { pp_f, 16'h00 };
//
// 16'h00 16'h00 pp_l[31:16] ppl[15:]
// 16'h00 pp_o[31:16] pp_o[15:0] 16'h00
// 16'h00 pp_i[31:16] pp_i[15:0] 16'h00
// pp_s[32:17] pp_s[16:1] pp_s[0],15'h0 16'h00
// pp_f[31:16] pp_f[31:16] 16'h00 16'h00
//
// 16'h0 15'h0,lo[32] lo[31:16] lo[15:]
// 15'h0,oi[32] oi[31:16] oi[15:0] 16'h00
// hi[31:0] hi[15:0] 16'h00
//
//
reg [32:0] partial_mpy_oi, partial_mpy_lo;
reg [31:0] partial_mpy_hi;
always @(posedge i_clk)
begin
partial_mpy_lo[30:0]<= pp_l[30:0];
partial_mpy_lo[32:31]<= pp_s[0]+pp_l[31];
partial_mpy_oi[32:0]<= pp_o + pp_i;
partial_mpy_hi[31:0]<= pp_s[32:1] + pp_f;
end
reg partial_mpy_2cl, partial_mpy_2ch;
reg [31:0] partial_mpy_2lo, partial_mpy_2hi;
// Fourth clock -- Finish adding our partial results
always @(posedge i_clk)
begin
partial_mpy_2lo[15:0] <= partial_mpy_lo[15:0];
{ partial_mpy_2cl, partial_mpy_2lo[31:16] }
<= partial_mpy_oi[15:0] + partial_mpy_lo[31:16];
{ partial_mpy_2ch, partial_mpy_2hi[15:0] }
<= partial_mpy_oi[32:16] + partial_mpy_hi[16:0];
partial_mpy_2hi[31:17] <= partial_mpy_2hi[31:17];
end
// Fifth clock -- deal with final carries
always @(posedge i_clk)
begin
r_mpy_result[31:0] <= partial_mpy_2lo[31:0];
r_mpy_result[63:32] <= partial_mpy_2hi+
{ 14'h0,partial_mpy_2ch,15'h0, partial_mpy_2cl};
end
// Fifth clock -- results are available for writeback.
 
//
// The master ALU case statement
//
reg [3:0] r_op;
always @(posedge i_clk)
begin
r_op <= i_op;
pre_sign <= (i_a[31]);
c <= 1'b0;
casez(r_op)
4'b0000:{c,o_c } <= r_diff; // CMP/SUB
4'b00?1: o_c <= r_logical; // BTST/And/Or
4'b0010:{c,o_c } <= r_sum; // Add
4'b0100: o_c <= r_xor; // Xor
4'b0101:{o_c,c } <= r_lsr_result; // LSR
4'b0110:{c,o_c } <= r_lsl_result; // LSL
4'b0111:{o_c,c } <= r_asr_result; // ASR
4'b1000: o_c <= r_mpy_result[31:0]; // MPY
4'b1001: o_c <= r_ldilo; // LODILO
4'b1010: o_c <= r_mpy_result[63:32]; // MPYHU
4'b1011: o_c <= r_mpy_result[63:32]; // MPYHS
4'b1100: o_c <= r_brev_result; // BREV
4'b1101: o_c <= w_popc_result; // POPC
4'b1110: o_c <= r_rol_result; // ROL
default: o_c <= r_bypass; // MOV, LDI
endcase
end
 
// With the multiply implemented (as above), there are no illegal
// results.
assign o_illegal = 1'b0;
 
assign z = (o_c == 32'h0000); // This really costs us a clock ...
assign n = (o_c[31]);
assign v = (set_ovfl)&&(pre_sign != o_c[31]);
 
assign o_f = { v, n, c, z };
 
reg [2:0] alu_pipe;
always @(posedge i_clk)
if (i_rst)
alu_pipe <= 3'h0;
else
alu_pipe <= { alu_pipe[1], (i_ce)&(~mpy)|alu_pipe[0],
(i_ce)&(mpy) };
//
// A longer pipeline would look like:
//
// alu_pipe <= { alu_pipe[2:1], (i_ce)&(~mpy)|alu_pipe[1], alu_pipe[0],
// (i_ce)&mpy;
// o_busy <= (|alu_pipe[1:0])
 
assign o_valid = alu_pipe[2];
assign o_busy = alu_pipe[0];
endmodule
/rtl/cpu/wbarbiter.v
0,0 → 1,185
///////////////////////////////////////////////////////////////////////////
//
// Filename: wbarbiter.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: At some point in time, I might wish to have two masters connect
// to the same wishbone bus. As an example, I might wish to have
// both the instruction fetch and the load/store operators
// of my Zip CPU access the the same bus. How shall they both
// get access to the same resource? This module allows the
// wishbone interfaces from two sources to drive the bus, while
// guaranteeing that only one drives the bus at a time.
//
// The core logic works like this:
//
// 1. If 'A' or 'B' asserts the o_cyc line, a bus cycle will begin,
// with acccess granted to whomever requested it.
// 2. If both 'A' and 'B' assert o_cyc at the same time, only 'A'
// will be granted the bus. (If the alternating parameter
// is set, A and B will alternate who gets the bus in
// this case.)
// 3. The bus will remain owned by whomever the bus was granted to
// until they deassert the o_cyc line.
// 4. At the end of a bus cycle, o_cyc is guaranteed to be
// deasserted (low) for one clock.
// 5. On the next clock, bus arbitration takes place again. If
// 'A' requests the bus, no matter how long 'B' was
// waiting, 'A' will then be granted the bus. (Unless
// again the alternating parameter is set, then the
// access is guaranteed to switch to B.)
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
// `define WBA_ALTERNATING
module wbarbiter(i_clk, i_rst,
// Bus A -- gets priority when not alternating
i_a_adr, i_a_dat, i_a_we, i_a_stb, i_a_cyc, o_a_ack, o_a_stall, o_a_err,
// Bus B
i_b_adr, i_b_dat, i_b_we, i_b_stb, i_b_cyc, o_b_ack, o_b_stall, o_b_err,
// Both buses
o_adr, o_dat, o_we, o_stb, o_cyc, i_ack, i_stall, i_err);
// 18 bits will address one GB, 4 bytes at a time.
// 19 bits will allow the ability to address things other than just
// the 1GB of memory we are expecting.
parameter DW=32, AW=19;
// Wishbone doesn't use an i_ce signal. While it could, they dislike
// what it would (might) do to the synchronous reset signal, i_rst.
input i_clk, i_rst;
input [(AW-1):0] i_a_adr, i_b_adr;
input [(DW-1):0] i_a_dat, i_b_dat;
input i_a_we, i_a_stb, i_a_cyc;
input i_b_we, i_b_stb, i_b_cyc;
output wire o_a_ack, o_b_ack, o_a_stall, o_b_stall,
o_a_err, o_b_err;
output wire [(AW-1):0] o_adr;
output wire [(DW-1):0] o_dat;
output wire o_we, o_stb, o_cyc;
input i_ack, i_stall, i_err;
 
// All the fancy stuff here is done with the three primary signals:
// o_cyc
// w_a_owner
// w_b_owner
// These signals are helped by r_cyc, r_a_owner, and r_b_owner.
// If you understand these signals, all else will fall into place.
 
// r_cyc just keeps track of the last o_cyc value. That way, on
// the next clock we can tell if we've had one non-cycle before
// starting another cycle. Specifically, no new cycles will be
// allowed to begin unless r_cyc=0.
reg r_cyc;
always @(posedge i_clk)
if (i_rst)
r_cyc <= 1'b0;
else
r_cyc <= o_cyc;
 
// Go high immediately (new cycle) if ...
// Previous cycle was low and *someone* is requesting a bus cycle
// Go low immadiately if ...
// We were just high and the owner no longer wants the bus
// WISHBONE Spec recommends no logic between a FF and the o_cyc
// This violates that spec. (Rec 3.15, p35)
assign o_cyc = ((~r_cyc)&&((i_a_cyc)||(i_b_cyc))) || ((r_cyc)&&((w_a_owner)||(w_b_owner)));
 
 
// Register keeping track of the last owner, wire keeping track of the
// current owner allowing us to not lose a clock in arbitrating the
// first clock of the bus cycle
reg r_a_owner, r_b_owner;
wire w_a_owner, w_b_owner;
`ifdef WBA_ALTERNATING
reg r_a_last_owner;
 
`endif
always @(posedge i_clk)
if (i_rst)
begin
r_a_owner <= 1'b0;
r_b_owner <= 1'b0;
end else begin
r_a_owner <= w_a_owner;
r_b_owner <= w_b_owner;
`ifdef WBA_ALTERNATING
if (w_a_owner)
r_a_last_owner <= 1'b1;
else if (w_b_owner)
r_a_last_owner <= 1'b0;
`endif
end
//
// If you are the owner, retain ownership until i_x_cyc is no
// longer asserted. Likewise, you cannot become owner until o_cyc
// is de-asserted for one cycle.
//
// 'A' is given arbitrary priority over 'B'
// 'A' may own the bus only if he wants it. When 'A' drops i_a_cyc,
// o_cyc must drop and so must w_a_owner on the same cycle.
// However, when 'A' asserts i_a_cyc, he can only capture the bus if
// it's had an idle cycle.
// The same is true for 'B' with one exception: if both contend for the
// bus on the same cycle, 'A' arbitrarily wins.
`ifdef WBA_ALTERNATING
assign w_a_owner = (i_a_cyc) // if A requests ownership, and either
&& ((r_a_owner) // A has already been recognized or
|| ((~r_cyc) // the bus is free and
&&((~i_b_cyc) // B has not requested, or if he
||(~r_a_last_owner)) )); // has, it's A's turn
assign w_b_owner = (i_b_cyc)&& ((r_b_owner) || ((~r_cyc)&&((~i_a_cyc)||(r_a_last_owner)) ));
`else
assign w_a_owner = (i_a_cyc)&& ((r_a_owner) || (~r_cyc) );
assign w_b_owner = (i_b_cyc)&& ((r_b_owner) || ((~r_cyc)&&(~i_a_cyc)) );
`endif
 
// Realistically, if neither master owns the bus, the output is a
// don't care. Thus we trigger off whether or not 'A' owns the bus.
// If 'B' owns it all we care is that 'A' does not. Likewise, if
// neither owns the bus than the values on the various lines are
// irrelevant.
assign o_adr = (w_a_owner) ? i_a_adr : i_b_adr;
assign o_dat = (w_a_owner) ? i_a_dat : i_b_dat;
assign o_we = (w_a_owner) ? i_a_we : i_b_we;
assign o_stb = (o_cyc) && ((w_a_owner) ? i_a_stb : i_b_stb);
 
// We cannot allow the return acknowledgement to ever go high if
// the master in question does not own the bus. Hence we force it
// low if the particular master doesn't own the bus.
assign o_a_ack = (w_a_owner) ? i_ack : 1'b0;
assign o_b_ack = (w_b_owner) ? i_ack : 1'b0;
 
// Stall must be asserted on the same cycle the input master asserts
// the bus, if the bus isn't granted to him.
assign o_a_stall = (w_a_owner) ? i_stall : 1'b1;
assign o_b_stall = (w_b_owner) ? i_stall : 1'b1;
 
//
//
assign o_a_err = (w_a_owner) ? i_err : 1'b0;
assign o_b_err = (w_b_owner) ? i_err : 1'b0;
 
endmodule
 
/rtl/cpu/fastcache.v
0,0 → 1,277
////////////////////////////////////////////////////////////////////////////////
//
// Filename: fastcache.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: Keeping our CPU fed with instructions, at one per clock and
// with no stalls. An unusual feature of this cache is the
// requirement that the entire cache may be cleared (if necessary).
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
module fastcache(i_clk, i_rst, i_new_pc, i_clear_cache,
// i_early_branch, i_from_addr,
i_stall_n, i_pc, o_i, o_pc, o_v,
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,
o_illegal);
parameter LGCACHELEN = 8, ADDRESS_WIDTH=24,
CACHELEN=(1<<LGCACHELEN), BUSW=32, AW=ADDRESS_WIDTH,
CW=LGCACHELEN, PW=LGCACHELEN-5;
input i_clk, i_rst, i_new_pc;
input i_clear_cache;
input i_stall_n;
input [(AW-1):0] i_pc;
output wire [(BUSW-1):0] o_i;
output wire [(AW-1):0] o_pc;
output wire o_v;
//
output reg o_wb_cyc, o_wb_stb;
output wire o_wb_we;
output reg [(AW-1):0] o_wb_addr;
output wire [(BUSW-1):0] o_wb_data;
//
input i_wb_ack, i_wb_stall, i_wb_err;
input [(BUSW-1):0] i_wb_data;
//
output reg o_illegal;
 
// Fixed bus outputs: we read from the bus only, never write.
// Thus the output data is ... irrelevant and don't care. We set it
// to zero just to set it to something.
assign o_wb_we = 1'b0;
assign o_wb_data = 0;
 
wire r_v;
reg [(BUSW-1):0] cache [0:((1<<CW)-1)];
reg [(AW-CW-1):0] tags [0:((1<<(CW-PW))-1)];
reg [((1<<(CW-PW))-1):0] vmask;
 
reg [(AW-1):0] lastpc;
reg [(CW-1):0] rdaddr;
reg [(AW-1):CW] tagvalipc, tagvallst;
wire [(AW-1):CW] tagval;
wire [(AW-1):PW] lasttag;
reg illegal_valid;
reg [(AW-1):PW] illegal_cache;
 
// initial o_i = 32'h76_00_00_00; // A NOOP instruction
// initial o_pc = 0;
reg [(BUSW-1):0] r_pc_cache, r_last_cache;
reg [(AW-1):0] r_pc, r_lastpc;
reg isrc;
always @(posedge i_clk)
if (~r_v)
isrc <= 1'b0;
else if ((i_stall_n)||(i_new_pc))
isrc <= 1'b1;
always @(posedge i_clk)
r_pc_cache <= cache[i_pc[(CW-1):0]];
always @(posedge i_clk)
r_last_cache <= cache[lastpc[(CW-1):0]];
always @(posedge i_clk)
r_pc <= i_pc;
always @(posedge i_clk)
r_lastpc <= lastpc;
assign o_pc = (isrc) ? r_pc : r_lastpc;
assign o_i = (isrc) ? r_pc_cache : r_last_cache;
 
reg tagsrc;
always @(posedge i_clk)
// It may be possible to recover a clock once the cache line
// has been filled, but our prior attempt to do so has lead
// to a race condition, so we keep this logic simple.
if (((r_v)&&(i_stall_n))||(i_clear_cache)||(i_new_pc))
tagsrc <= 1'b1;
else
tagsrc <= 1'b0;
initial tagvalipc = 0;
always @(posedge i_clk)
tagvalipc <= tags[i_pc[(CW-1):PW]];
initial tagvallst = 0;
always @(posedge i_clk)
tagvallst <= tags[lastpc[(CW-1):PW]];
assign tagval = (tagsrc)?tagvalipc : tagvallst;
 
// i_pc will only increment when everything else isn't stalled, thus
// we can set it without worrying about that. Doing this enables
// us to work in spite of stalls. For example, if the next address
// isn't valid, but the decoder is stalled, get the next address
// anyway.
initial lastpc = 0;
always @(posedge i_clk)
if (((r_v)&&(i_stall_n))||(i_clear_cache)||(i_new_pc))
lastpc <= i_pc;
 
assign lasttag = lastpc[(AW-1):PW];
// initial lasttag = 0;
// always @(posedge i_clk)
// if (((r_v)&&(i_stall_n))||(i_clear_cache)||(i_new_pc))
// lasttag <= i_pc[(AW-1):PW];
 
wire w_v_from_pc, w_v_from_last;
assign w_v_from_pc = ((i_pc[(AW-1):PW] == lasttag)
&&(tagvalipc == i_pc[(AW-1):CW])
&&(vmask[i_pc[(CW-1):PW]]));
assign w_v_from_last = (
//(lastpc[(AW-1):PW] == lasttag)&&
(tagvallst == lastpc[(AW-1):CW])
&&(vmask[lastpc[(CW-1):PW]]));
 
reg [1:0] delay;
 
initial delay = 2'h3;
reg rvsrc;
always @(posedge i_clk)
if ((i_rst)||(i_clear_cache)||(i_new_pc)||((r_v)&&(i_stall_n)))
begin
// r_v <= r_v_from_pc;
rvsrc <= 1'b1;
delay <= 2'h2;
end else if (~r_v) begin // Otherwise, r_v was true and we were
// stalled, hence only if ~r_v
rvsrc <= 1'b0;
if (o_wb_cyc)
delay <= 2'h2;
else if (delay != 0)
delay <= delay + 2'b11; // i.e. delay -= 1;
end
reg r_v_from_pc, r_v_from_last;
always @(posedge i_clk)
r_v_from_pc <= w_v_from_pc;
always @(posedge i_clk)
r_v_from_last <= w_v_from_last;
 
assign r_v = ((rvsrc)?(r_v_from_pc):(r_v_from_last));
assign o_v = ((rvsrc)?(r_v_from_pc):(r_v_from_last))&&(~i_new_pc);
 
reg last_ack;
initial last_ack <= 1'b0;
always @(posedge i_clk)
last_ack <= (o_wb_cyc)&&(
(rdaddr[(PW-1):1]=={(PW){1'b1}})
&&((rdaddr[0])||(i_wb_ack)));
 
reg needload;
initial needload = 1'b0;
always @(posedge i_clk)
needload <= ((~r_v)&&(delay==0)
&&((tagvallst != lastpc[(AW-1):CW])
||(~vmask[lastpc[(CW-1):PW]]))
&&((~illegal_valid)
||(lastpc[(AW-1):PW] != illegal_cache)));
 
reg last_addr;
initial last_addr = 1'b0;
always @(posedge i_clk)
last_addr <= (o_wb_cyc)&&(o_wb_addr[(PW-2):1] == {(PW-1){1'b1}})
&&((~i_wb_stall)|(o_wb_addr[0]));
 
initial o_wb_cyc = 1'b0;
initial o_wb_stb = 1'b0;
initial o_wb_addr = {(AW){1'b0}};
initial rdaddr = 0;
always @(posedge i_clk)
if ((i_rst)||(i_clear_cache))
begin
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
end else if (o_wb_cyc)
begin
if (i_wb_err)
o_wb_stb <= 1'b0;
else if ((o_wb_stb)&&(~i_wb_stall)&&(last_addr))
o_wb_stb <= 1'b0;
 
if (((i_wb_ack)&&(last_ack))||(i_wb_err))
o_wb_cyc <= 1'b0;
 
// else if (rdaddr[(PW-1):1] == {(PW-1){1'b1}})
// tags[lastpc[(CW-1):PW]] <= lastpc[(AW-1):CW];
 
end else if (needload)
begin
o_wb_cyc <= 1'b1;
o_wb_stb <= 1'b1;
end
 
always @(posedge i_clk)
if (o_wb_cyc) // &&(i_wb_ack)
tags[o_wb_addr[(CW-1):PW]] <= o_wb_addr[(AW-1):CW];
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
rdaddr <= rdaddr + 1;
else if (~o_wb_cyc)
rdaddr <= { lastpc[(CW-1):PW], {(PW){1'b0}} };
always @(posedge i_clk)
if ((o_wb_stb)&&(~i_wb_stall)&&(~last_addr))
o_wb_addr[(PW-1):0] <= o_wb_addr[(PW-1):0]+1;
else if (~o_wb_cyc)
o_wb_addr <= { lastpc[(AW-1):PW], {(PW){1'b0}} };
 
// Can't initialize an array, so leave cache uninitialized
// We'll also never get an ack without sys being active, so skip
// that check. Or rather, let's just use o_wb_cyc instead. This
// will work because multiple writes to the same address, ending with
// a valid write, aren't a problem.
always @(posedge i_clk)
if (o_wb_cyc) // &&(i_wb_ack)
cache[rdaddr] <= i_wb_data;
 
// VMask ... is a section loaded?
initial vmask = 0;
always @(posedge i_clk)
if ((i_rst)||(i_clear_cache))
vmask <= 0;
else begin
if ((o_wb_cyc)&&(i_wb_ack)&&(last_ack))
vmask[rdaddr[(CW-1):PW]] <= 1'b1;
if ((~o_wb_cyc)&&(needload))
vmask[lastpc[(CW-1):PW]] <= 1'b0;
end
 
initial illegal_cache = 0;
initial illegal_valid = 0;
always @(posedge i_clk)
if ((i_rst)||(i_clear_cache))
begin
illegal_cache <= 0;
illegal_valid <= 0;
end else if ((o_wb_cyc)&&(i_wb_err))
begin
illegal_cache <= o_wb_addr[(AW-1):PW];
illegal_valid <= 1'b1;
end
 
initial o_illegal = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(i_clear_cache))
o_illegal <= 1'b0;
else
o_illegal <= (illegal_valid)
&&(illegal_cache == i_pc[(AW-1):PW]);
 
endmodule
/rtl/cpu/ifastdec.v
0,0 → 1,620
///////////////////////////////////////////////////////////////////////////////
//
// Filename: ifastdec.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: This RTL file specifies how instructions are to be decoded
// into their underlying meanings. It is different from the
// standard idecode.v file in that this one takes two clocks, and is
// pipelined. This one is designed for a 5ns clock cycle, hence it is
// a "fast" decoder--even though the old decoder took one cycle in 10ns.
// From that standpoint, the two may well be ... comparable in speed.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////////
//
//
//
`define CPU_CC_REG 4'he
`define CPU_PC_REG 4'hf
//
`include "cpudefs.v"
//
//
//
module ifastdec(i_clk, i_rst, i_ce, i_stalled,
i_instruction, i_gie, i_pc, i_pf_valid,
i_illegal,
o_phase, o_illegal,
o_pc, o_gie,
o_R, o_A, o_B, o_I, o_zI,
o_cond, o_wF,
o_op, o_ALU, o_M, o_DV, o_FP, o_break, o_lock,
o_wR, o_rA, o_rB,
o_early_branch, o_branch_pc, o_ljmp,
o_pipe
);
parameter ADDRESS_WIDTH=24, IMPLEMENT_MPY=1, EARLY_BRANCHING=1,
IMPLEMENT_DIVIDE=1, IMPLEMENT_FPU=0, AW = ADDRESS_WIDTH;
input i_clk, i_rst, i_ce, i_stalled;
input [31:0] i_instruction;
input i_gie;
input [(AW-1):0] i_pc;
input i_pf_valid, i_illegal;
output reg o_phase;
output reg o_illegal;
output reg [(AW-1):0] o_pc;
output reg o_gie;
output reg [6:0] o_R, o_A, o_B;
output reg [31:0] o_I;
output reg o_zI;
output reg [3:0] o_cond;
output reg o_wF;
output reg [3:0] o_op;
output reg o_ALU, o_M, o_DV, o_FP, o_break;
output reg o_lock;
output reg o_wR, o_rA, o_rB;
output reg o_early_branch;
output reg [(AW-1):0] o_branch_pc;
output reg o_ljmp;
output reg o_pipe;
 
 
//////
//
// Path 1: Full size instruction
//
// Prefix: wf (wire, full)
//
//////
 
// The 5-bit opcode, as extracted
wire [4:0] wf_op;
// Instruction types
wire wf_ldi, wf_mov, wf_cmptst, wf_ldilo, wf_brev, wf_noop,
wf_break, wf_lock,
wf_ljmp, wf_ALU, wf_MEM, wf_DIV, wf_FPU;
wire [4:0] wf_R, wf_A, wf_B; // Instruction registers
wire [3:0] wf_cond;
wire wf_wF; // Write flags?
wire wf_wR_n, // Write destination register? or not?
wf_rA, // Read register A?
wf_rB; // Read register B?
wire [22:0] wf_pI; // Partial immediate ...
wire wf_Iz;
 
assign wf_op = i_instruction[26:22];
assign wf_brev = (wf_op == 5'hc);
assign wf_mov = (wf_op == 5'h0f);
assign wf_ldi = (wf_op[4:1] == 4'hb);
assign wf_cmptst=(wf_op[4:1] == 4'h8);
assign wf_ldilo= (wf_op[4:0] == 5'h9);
assign wf_noop = (wf_op[4:0] == 5'h18)&&(wf_R[3:1] == 3'h7);
assign wf_break= (wf_op[4:0] == 5'h19)&&(wf_R[3:1] == 3'h7);
assign wf_lock = (wf_op[4:0] == 5'h1a)&&(wf_R[3:1] == 3'h7);
//
assign wf_R = { (wf_mov)&&(i_gie)?i_instruction[18]:i_gie, (i_instruction[30:27]) };
assign wf_A = { (wf_mov)&&(i_gie)?i_instruction[18]:i_gie, (i_instruction[30:27]) };
assign wf_B = { (wf_mov)&&(i_gie)?i_instruction[13]:i_gie, (i_instruction[17:14]) };
//
assign wf_ALU = (~wf_op[4]);
assign wf_MEM = ( wf_op[4:1] == 4'h9);
assign wf_DIV = ( wf_op[4:1] == 4'ha);
assign wf_FPU = ( wf_op[4:2] == 3'h7)&&(i_instruction[30:28]==3'h7);
assign wf_ljmp = (i_instruction == 32'h7c87c000);
 
assign wf_pI = (wf_ldi) ? { i_instruction[22:0] } // LDI
:((wf_mov) ?{ {(23-13){i_instruction[12]}}, i_instruction[12:0] } // Move
:((~i_instruction[18]) ? { {(23-18){i_instruction[17]}}, i_instruction[17:0] }
: { {(23-14){i_instruction[13]}}, i_instruction[13:0] }
));
assign wf_Iz= (wf_pI == 23'h00);
 
// Will we be writing register R?
assign wf_wR_n = ((wf_MEM)&&(wf_op[0])) // Store's dont write regs
// Neither do NOOP, BREAK, or LOCKs
||((wf_op[4:3]==2'b11)&&(wf_R[3:1]==3'h7))
// nor CMPs and TSTs
||(wf_cmptst);
// Do we read register 'A'?
assign wf_rA = (wf_FPU)&&(wf_op[4:1]!=4'he) // FPU, but not CVT or INT
||(wf_DIV)
||(wf_ALU)&&(~wf_mov)
||(wf_MEM)&&(wf_op[0])
||(wf_cmptst);
// Do we need to read register 'B'?
assign wf_rB = (wf_mov)||((i_instruction[18])&&(~wf_ldi));
 
// What are the conditions for this instruction? NOOP, BREAK, and LOCK
// are also unconditional, but they'll just ignore this setting
assign wf_cond = (wf_ldi) ? 4'h8 // LDI is unconditional
: { (i_instruction[21:19]==3'h0), i_instruction[21:19] };
// How about the flags, will we be writing them?
assign wf_wF = (wf_cmptst) // Compares always write flags
||((wf_cond[3])&&(
// FPU and DIV instructions always write flags
(wf_FPU)||(wf_DIV)
// So do ALU instructions, UNLESS the ALU
// instruction is a MOV, LDILO, or BREV, or
// the results are being written into the PC
// or CC register--those don't set flags
||((wf_ALU)&&(~wf_mov)&&(~wf_ldilo)&&(~wf_brev)
&&(i_instruction[30:28] != 3'h7))));
 
reg [3:0] rf_op;
reg rf_break, rf_lock;
reg [4:0] rf_R, rf_A, rf_B;
reg rf_ALU, rf_MEM, rf_DIV, rf_FPU, rf_ljmp;
reg [3:0] rf_cond;
reg rf_rA, rf_rB, rf_wR, rf_wF;
 
reg [22:0] rf_pI;
reg rf_Iz;
wire [31:0] wf_I;
assign wf_I = { {(32-22){rf_pI[22]}}, rf_pI[21:0] };
reg rf_early_branch;
reg [(AW-1):0] rf_branch_pc;
always @(posedge i_clk)
if (i_ce)
begin
rf_op <= wf_op[3:0];
rf_break<= wf_break;
rf_lock <= wf_lock;
//
rf_R <= (wf_R);
rf_A <= (wf_A);
rf_B <= (wf_B);
//
rf_ALU <= (~wf_op[4]);
rf_MEM <= ( wf_op[4:1] == 4'h9);
rf_DIV <= ( wf_op[4:1] == 4'ha);
rf_FPU <= ( wf_op[4:2] == 3'h7)&&(i_instruction[30:28]==3'h7);
rf_ljmp <= (i_instruction == 32'h7c87c000);
 
rf_pI <= wf_pI;
rf_Iz<= wf_Iz;
 
// What are the conditions of this instruction?
rf_cond <= wf_cond;
 
// Do we read register 'A'?
rf_rA <= wf_rA;
// Do we need to read register 'B'?
rf_rB <= wf_rB;
// Will we be writing register 'R'?
rf_wR <= ~wf_wR_n;
// How about the flags, will we be writing those?
rf_wF <= wf_wF;
 
//
rf_early_branch <=
// PC is the result
(wf_R[3:0]==4'hf)
// Unconditional instruction
&&(i_instruction[21:19]==3'h0)
&&
// Either an ADD #x,PC
((wf_op == 5'h02)&&(~i_instruction[18])
// Or a LOD #x,PC
||(wf_ldi));
rf_branch_pc <= (wf_ldi)?{{(AW-22){wf_pI[22]}},wf_pI[21:0]}
:(i_pc + {{(AW-18){i_instruction[17]}},
i_instruction[16:0]});
end
 
//////
//
// Path 2: Half size instruction, high half
//
// Prefix: wh (wire, high-half)
//
//////
 
// The 5-bit opcode, as extracted -- same as wf_
// Instruction types -- same as wf_
wire [4:0] wh_R, wh_A, wh_B; // Instruction registers
wire [3:0] wh_cond;
wire wh_wF; // Write flags?
wire wh_wR, wh_wR_n, // Write destination register? or not?
wh_rA, // Read register A?
wh_rB; // Read register B?
wire [4:0] wh_pI; // Partial immediate ...
wire wh_Iz;
 
assign wh_R = { i_gie, (i_instruction[30:27]) };
assign wh_A = { i_gie, (i_instruction[30:27]) };
assign wh_B = { i_gie, (i_instruction[17:14]) };
//
 
assign wh_pI = (wf_ldi) ? { i_instruction[18:14] } // LDI
:((~i_instruction[18])
? { i_instruction[17], i_instruction[17:14] }
: 5'h0);
assign wh_Iz= (wh_pI == 5'h0);
 
// Will we be writing register R?
assign wh_wR_n = ((wf_MEM)&&(wf_op[0])) // Store's dont write regs
// Neither do NOOP, BREAK, or LOCKs
||((wf_op[4:3]==2'b11)&&(wh_R[3:1]==3'h7))
// nor CMPs and TSTs
||(wf_cmptst);
 
assign wh_cond = (wf_ldi) ? 4'h8 // LDI is unconditional
: { (i_instruction[20:19]==2'h0), 1'b0, i_instruction[20:19] };
// How about the flags, will we be writing them?
assign wh_wF = (wf_cmptst) // Compares always write flags
||((wh_cond[3])&&(
// FPU and DIV instructions always write flags
(wf_FPU)||(wf_DIV)
// So do ALU instructions, UNLESS the ALU
// instruction is a MOV, LDILO, or BREV, or
// the results are being written into the PC
// or CC register--those don't set flags
||((wf_ALU)&&(~wf_mov)&&(~wf_ldilo)&&(~wf_brev)
&&(i_instruction[30:28] != 3'h7))));
 
reg [3:0] rh_op;
reg rh_break, rh_lock;
reg [4:0] rh_R, rh_A, rh_B;
reg rh_ALU, rh_MEM, rh_DIV, rh_FPU;
reg [3:0] rh_cond;
reg rh_rA, rh_rB, rh_wR, rh_wF;
wire [31:0] wh_I;
reg [4:0] rh_pI;
reg rh_Iz;
assign wh_I = { {(32-4){rh_pI[4]}}, rh_pI[3:0] };
always @(posedge i_clk)
if (i_ce)
begin
rh_op <= wf_op[3:0];
rh_break<= wf_break;
rh_lock <= wf_lock;
//
rh_R <= (wh_R);
rh_A <= (wh_A);
rh_B <= (wh_B);
//
rh_ALU <= wf_ALU;
rh_MEM <= wf_MEM;
rh_DIV <= wf_DIV;
rh_FPU <= wf_FPU;
 
rh_pI <= wh_pI;
rh_Iz <= wh_Iz;
 
// What are the conditions of this instruction?
rh_cond <= wh_cond;
 
// Do we read register 'A'?
rh_rA <= (wf_FPU)&&(wf_op[4:1]!=4'he)
||(wf_DIV)
||(wf_ALU)&&(~wf_mov)
||(wf_MEM)&&(wf_op[0])
||(wf_cmptst);
// Do we need to read register 'B'?
rh_rB <= (i_instruction[18])&&(~wf_ldi);
// Will we be writing register 'R'?
rh_wR <= ~wh_wR_n;
rh_wF <= wh_wF;
end
 
 
//////
//
// Path 3: Half size instruction, low half
//
//////
 
// The 5-bit opcode, as extracted
wire [4:0] wl_op;
// Instruction types
wire wl_ldi, wl_mov, wl_cmptst, wl_ldilo, wl_brev, wl_noop,
wl_break, wl_lock,
wl_ljmp, wl_ALU, wl_MEM, wl_DIV, wl_FPU;
wire [4:0] wl_R, wl_A, wl_B; // Instruction registers
wire [3:0] wl_cond;
wire wl_wF; // Write flags?
wire wl_wR, wl_wR_n, // Write destination register? or not?
wl_rA, // Read register A?
wl_rB; // Read register B?
wire [4:0] wl_pI; // Partial immediate ...
wire wl_Iz;
 
assign wl_op = i_instruction[9:5];
assign wl_brev = (wl_op == 5'hc);
assign wl_mov = (wl_op == 5'h0f);
assign wl_ldi = (wl_op[4:1] == 4'hb);
assign wl_cmptst=(wl_op[4:1] == 4'h8);
assign wl_ldilo= (wl_op[4:0] == 5'h9);
assign wl_noop = (wl_op[4:0] == 5'h18)&&(wl_R[3:1] == 3'h7);
assign wl_break= (wl_op[4:0] == 5'h19)&&(wl_R[3:1] == 3'h7);
assign wl_lock = (wl_op[4:0] == 5'h1a)&&(wl_R[3:1] == 3'h7);
//
assign wl_R = { i_gie, i_instruction[13:10] };
assign wl_A = { i_gie, i_instruction[13:10] };
assign wl_B = { i_gie, i_instruction[ 3: 0] };
//
assign wl_ALU = (~wl_op[4]);
assign wl_MEM = ( wl_op[4:1] == 4'h9);
assign wl_DIV = ( wl_op[4:1] == 4'ha);
assign wl_FPU = ( wl_op[4:2] == 3'h7)&&(i_instruction[30:28]==3'h7);
assign wl_ljmp = ( i_instruction[21:19] == 3'h00) // 1111_10010_1_1111
&&(i_instruction[13:0]==14'h3e5f);
 
assign wl_pI = (wl_ldi) ? { i_instruction[4:0] } // LDI
:((~i_instruction[4])
? { i_instruction[3], i_instruction[3:0] }
: 5'h0);
assign wl_Iz= (wl_pI == 5'h0);
 
// Will we be writing register R?
assign wl_wR_n = ((wl_MEM)&&(wl_op[0])) // Store's dont write regs
// Neither do NOOP, BREAK, or LOCKs
||((wl_op[4:3]==2'b11)&&(wl_R[3:1]==3'h7))
// nor CMPs and TSTs
||(wl_cmptst);
 
// What are the conditions for this instruction? NOOP, BREAK, and LOCK
// are also unconditional, but they'll just ignore this setting
assign wl_cond = (wl_ldi) ? 4'h8 // LDI is unconditional
: { (i_instruction[20:19]==2'h0),
1'b0, i_instruction[20:19] };
// How about the flags, will we be writing them?
assign wl_wF = (wl_cmptst) // Compares always write flags
||((wl_cond[3])&&(
// FPU and DIV instructions always write flags
(wl_FPU)||(wl_DIV)
// So do ALU instructions, UNLESS the ALU
// instruction is a MOV, LDILO, or BREV, or
// the results are being written into the PC
// or CC register--those don't set flags
||((wl_ALU)&&(~wl_mov)&&(~wl_ldilo)&&(~wl_brev)
&&(i_instruction[13:11] != 3'h7))));
 
reg [3:0] rl_op;
reg rl_break, rl_lock;
reg [4:0] rl_R, rl_A, rl_B;
reg rl_ALU, rl_MEM, rl_DIV, rl_FPU, rl_ljmp;
reg [3:0] rl_cond;
reg rl_rA, rl_rB, rl_wR, rl_wF;
wire [31:0] wl_I;
reg [4:0] rl_pI;
reg rl_Iz;
assign wl_I = { {(32-4){rl_pI[4]}}, rl_pI[3:0] };
always @(posedge i_clk)
if (i_ce)
begin
rl_op <= wl_op[3:0];
rl_break<= wl_break;
rl_lock <= wl_lock;
//
rl_R <= (wl_R);
rl_A <= (wl_A);
rl_B <= (wl_B);
//
rl_ALU <= (~wl_op[4]);
rl_MEM <= ( wl_op[4:1] == 4'h9);
rl_DIV <= ( wl_op[4:1] == 4'ha);
rl_FPU <= ( wl_op[4:2] == 3'h7)&&(i_instruction[30:28]==3'h7);
rl_ljmp <= wl_ljmp;
 
rl_pI <= wl_pI;
rl_Iz<= wl_Iz;
 
// What are the conditions of this instruction?
rl_cond <= wl_cond;
 
// Do we read register 'A'?
rl_rA <= (wl_FPU)&&(wl_op[4:1]!=4'he)
||(wl_DIV)
||(wl_ALU)&&(~wf_mov)
||(wl_MEM)&&(wl_op[0])
||(wl_cmptst);
// Do we need to read register 'B'?
rl_rB <= (i_instruction[18])&&(~wl_ldi);
// Will we be writing register 'R'?
rl_wR <= ~wl_wR_n;
// How about the flags?
rl_wF <= wl_wF;
end
 
//////
//
// Path 4: triplet instruction: MOV A,B; OP C,B
// becomes OP C,A -> B
//
//////
wire w_triplet;
reg r_triplet;
assign w_triplet =
// Must be a VLIW instruction
(i_instruction[31])
// First half must be a move
&&(i_instruction[26:22] == 5'h0f)
// Move destination must also be register A in 2nd Op
&&(i_instruction[30:27]==i_instruction[13:10])
// Only if this is unconditional, or share conditions
&&((i_instruction[21])|(i_instruction[20:19]==2'h0))
// Not if the destination is PC or CC regs
&&(i_instruction[30:28]!=3'h7);
always @(posedge i_clk)
if (i_ce)
r_triplet <= w_triplet;
 
// Now, let's string our instruction(s) together to create a useful
// decoded instruction
reg r_singlet, r_gie;
reg [(AW-1):0] r_pc;
always @(posedge i_clk)
if (i_ce)
begin
r_gie <= i_gie;
o_gie<= r_gie;
r_singlet <= ~i_instruction[31];
r_pc <= i_pc;
 
if (r_triplet)
begin
o_phase <= 1'b0;
o_pc <= r_pc + {{(AW-1){1'b0}}, 1'b1};
o_lock <= 1'b0;
o_break <= 1'b0;
o_R<={(rl_R=={r_gie, 4'he }),(rl_R=={r_gie,4'hf}),rl_R};
o_A<={(rh_B=={r_gie, 4'he }),(rh_B=={r_gie,4'hf}),rh_B};
o_B<={(rl_B=={r_gie, 4'he }),(rl_B=={r_gie,4'hf}),rl_B};
o_wR <= rl_wR;
o_rA <= 1'b1;
o_rB <= rl_rB;
o_cond<= rh_cond;
o_wF <= rl_wF;
o_I <= wl_I;
o_zI <= rl_Iz;
o_op <= rl_op;
o_ALU<= rl_ALU;
o_M<= rl_MEM;
o_DV<= rl_DIV;
o_FP <= rl_FPU;
o_ljmp <= 1'b0;
o_early_branch <= 1'b0;
o_branch_pc <= 0;
// o_pipe will never be true for a triplet
end else if (r_singlet)
begin
o_phase <= 1'b0;
o_pc <= r_pc + {{(AW-1){1'b0}}, 1'b1};
o_R<={(rf_R=={r_gie, 4'he }),(rf_R=={r_gie,4'hf}),rf_R};
o_A<={(rf_A=={r_gie, 4'he }),(rf_A=={r_gie,4'hf}),rf_A};
o_B<={(rf_B=={r_gie, 4'he }),(rf_B=={r_gie,4'hf}),rf_B};
o_break <= rf_break;
o_lock <= rf_lock;
o_wR <= rf_wR;
o_rA <= rf_rA;
o_rB <= rf_rB;
o_cond<= rf_cond;
o_wF <= rf_wF;
o_I <= wf_I;
o_zI <= rf_Iz;
o_op <= rf_op;
o_ALU<= rf_ALU;
o_M<= rf_MEM;
o_DV<= rf_DIV;
o_FP <= rf_FPU;
o_ljmp <= rf_ljmp;
o_early_branch <= (rf_ljmp);
o_branch_pc <= i_instruction[(AW-1):0];
end else if (~o_phase)
begin
o_phase <= 1'b1;
o_pc <= r_pc;
o_R<={(rh_R=={r_gie, 4'he }),(rh_R=={r_gie,4'hf}),rh_R};
o_A<={(rh_A=={r_gie, 4'he }),(rh_A=={r_gie,4'hf}),rh_A};
o_B<={(rh_B=={r_gie, 4'he }),(rh_B=={r_gie,4'hf}),rh_B};
o_lock <= rh_lock;
o_break <= rh_break;
o_wR <= rh_wR;
o_rA <= rh_rA;
o_rB <= rh_rB;
o_cond<= rh_cond;
o_wF <= rh_wF;
o_I <= wh_I;
o_zI <= rh_Iz;
o_op <= rh_op;
o_ALU<= rh_ALU;
o_M<= rh_MEM;
o_DV<= rh_DIV;
o_FP <= rh_FPU;
o_ljmp <= 1'b0; // Can't jump from high-half
o_early_branch <= 1'b0;
// o_branch_pc <= i_instruction;
end else begin
o_phase <= 1'b0;
o_pc <= r_pc + {{(AW-1){1'b0}}, 1'b1};
o_lock <= rl_lock;
o_break <= rl_break;
o_R<={(rl_R=={r_gie, 4'he }),(rl_R=={r_gie,4'hf}),rl_R};
o_A<={(rl_A=={r_gie, 4'he }),(rl_A=={r_gie,4'hf}),rl_A};
o_B<={(rl_B=={r_gie, 4'he }),(rl_B=={r_gie,4'hf}),rl_B};
o_wR <= rl_wR;
o_rA <= rl_rA;
o_rB <= rl_rB;
o_cond<= rl_cond;
o_wF <= rl_wF;
o_I <= wl_I;
o_zI <= rl_Iz;
o_op <= rl_op;
o_ALU<= rl_ALU;
o_M<= rl_MEM;
o_DV<= rl_DIV;
o_FP <= rl_FPU;
o_ljmp <= rl_ljmp;
o_early_branch <= 1'b0;
o_branch_pc <= i_instruction[(AW-1):0];
end
o_illegal <= 1'b0;
end
 
/*
always @(posedge i_clk)
begin
pipe_M <= { o_M, o_op[0] };
pipe_I <= o_I;
pipe_pI <= o_I+1;
pipe_B <= o_B[3:0];
pipe_rB<= o_rB;
pipe_AB <= ({ o_A[6:5], o_B[6:5] } == 4'h00) // 12 inputs
&&(o_A[3:0] != o_B[3:0]);
pipe_gie<= o_gie;
 
// 36 bits (18*2)
match_sI <= (pipe_I == o_I);
// 36 bits
match_pI <= (pipe_pI == o_I);
// 9 bits
match_regs <= (pipe_M[1])&&(pipe_M == { o_M, o_op[0] })
&&((~pipe_rB)||(pipe_B == o_B[3:0]));
// 9 inputs
match_cnd <= ((pipe_cnd == o_cond)||(o_cond[3]));
// 5 inputs
match_aux <= (pipe_gie == o_gie)&&(pipeAB)&&(pipe_rB==o_rB)
 
o_pipe <= ((match_sI)||(match_pI))&&(match_regs)&&(match_cnd)
&&(match_aux)&&(pipe_AB);
end
*/
 
/*
always @(posedge i_clk)
if (i_rst)
r_valid <= 1'b0;
else if ((i_ce)&&(o_ljmp))
r_valid <= 1'b0;
else if ((i_ce)&&(i_pf_valid))
r_valid <= 1'b1;
else if (~i_stalled)
r_valid <= 1'b0;
*/
endmodule
/rtl/cpu/div.v
0,0 → 1,195
///////////////////////////////////////////////////////////////////////////////
//
// Filename: div.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: Provide an Integer divide capability to the Zip CPU.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////////
//
// `include "cpudefs.v"
//
module div(i_clk, i_rst, i_wr, i_signed, i_numerator, i_denominator,
o_busy, o_valid, o_err, o_quotient, o_flags);
parameter BW=32, LGBW = 5;
input i_clk, i_rst;
// Input parameters
input i_wr, i_signed;
input [(BW-1):0] i_numerator, i_denominator;
// Output parameters
output reg o_busy, o_valid, o_err;
output reg [(BW-1):0] o_quotient;
output wire [3:0] o_flags;
 
// r_busy is an internal busy register. It will clear one clock
// before we are valid, so it can't be o_busy ...
//
reg r_busy;
reg [(2*BW-2):0] r_divisor;
reg [(BW-1):0] r_dividend;
wire [(BW):0] diff; // , xdiff[(BW-1):0];
assign diff = r_dividend - r_divisor[(BW-1):0];
// assign xdiff= r_dividend - { 1'b0, r_divisor[(BW-1):1] };
 
reg r_sign, pre_sign, r_z, r_c, last_bit;
reg [(LGBW-1):0] r_bit;
 
reg zero_divisor;
initial zero_divisor = 1'b0;
always @(posedge i_clk)
zero_divisor <= (r_divisor == 0)&&(r_busy);
 
initial r_busy = 1'b0;
always @(posedge i_clk)
if (i_rst)
r_busy <= 1'b0;
else if (i_wr)
r_busy <= 1'b1;
else if ((last_bit)||(zero_divisor))
r_busy <= 1'b0;
 
initial o_busy = 1'b0;
always @(posedge i_clk)
if (i_rst)
o_busy <= 1'b0;
else if (i_wr)
o_busy <= 1'b1;
else if (((last_bit)&&(~r_sign))||(zero_divisor))
o_busy <= 1'b0;
else if (~r_busy)
o_busy <= 1'b0;
 
always @(posedge i_clk)
if ((i_rst)||(i_wr))
o_valid <= 1'b0;
else if (r_busy)
begin
if ((last_bit)||(zero_divisor))
o_valid <= (zero_divisor)||(~r_sign);
end else if (r_sign)
begin
o_valid <= (~zero_divisor); // 1'b1;
end else
o_valid <= 1'b0;
 
initial o_err = 1'b0;
always @(posedge i_clk)
if((i_rst)||(o_valid))
o_err <= 1'b0;
else if (((r_busy)||(r_sign))&&(zero_divisor))
o_err <= 1'b1;
else
o_err <= 1'b0;
 
initial last_bit = 1'b0;
always @(posedge i_clk)
if ((i_wr)||(pre_sign)||(i_rst))
last_bit <= 1'b0;
else if (r_busy)
last_bit <= (r_bit == {{(LGBW-1){1'b0}},1'b1});
 
always @(posedge i_clk)
// if (i_rst) r_busy <= 1'b0;
// else
if (i_wr)
begin
//
// Set our values upon an initial command. Here's
// where we come in and start.
//
// r_busy <= 1'b1;
//
o_quotient <= 0;
r_bit <= {(LGBW){1'b1}};
r_divisor <= { i_denominator, {(BW-1){1'b0}} };
r_dividend <= i_numerator;
r_sign <= 1'b0;
pre_sign <= i_signed;
r_z <= 1'b1;
end else if (pre_sign)
begin
//
// Note that we only come in here, for one clock, if
// our initial value may have been signed. If we are
// doing an unsigned divide, we then skip this step.
//
r_sign <= ((r_divisor[(2*BW-2)])^(r_dividend[(BW-1)]));
// Negate our dividend if necessary so that it becomes
// a magnitude only value
if (r_dividend[BW-1])
r_dividend <= -r_dividend;
// Do the same with the divisor--rendering it into
// a magnitude only.
if (r_divisor[(2*BW-2)])
r_divisor[(2*BW-2):(BW-1)] <= -r_divisor[(2*BW-2):(BW-1)];
//
// We only do this stage for a single clock, so go on
// with the rest of the divide otherwise.
pre_sign <= 1'b0;
end else if (r_busy)
begin
// While the divide is taking place, we examine each bit
// in turn here.
//
r_bit <= r_bit + {(LGBW){1'b1}}; // r_bit = r_bit - 1;
r_divisor <= { 1'b0, r_divisor[(2*BW-2):1] };
if (|r_divisor[(2*BW-2):(BW)])
begin
end else if (diff[BW])
begin
//
// diff = r_dividend - r_divisor[(BW-1):0];
//
// If this value was negative, there wasn't
// enough value in the dividend to support
// pulling off a bit. We'll move down a bit
// therefore and try again.
//
end else begin
//
// Put a '1' into our output accumulator.
// Subtract the divisor from the dividend,
// and then move on to the next bit
//
r_dividend <= diff[(BW-1):0];
o_quotient[r_bit[(LGBW-1):0]] <= 1'b1;
r_z <= 1'b0;
end
r_sign <= (r_sign)&&(~zero_divisor);
end else if (r_sign)
begin
r_sign <= 1'b0;
o_quotient <= -o_quotient;
end
 
// Set Carry on an exact divide
wire w_n;
always @(posedge i_clk)
r_c <= (r_busy)&&((diff == 0)||(r_dividend == 0));
assign w_n = o_quotient[(BW-1)];
 
assign o_flags = { 1'b0, w_n, r_c, r_z };
endmodule
/rtl/cpu/cpudefs.v
0,0 → 1,278
///////////////////////////////////////////////////////////////////////////////
//
// Filename: cpudefs.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: Some architectures have some needs, others have other needs.
// Some of my projects need a Zip CPU with pipelining, others
// can't handle the timing required to get the answer from the ALU
// back into the input for the ALU. As each different projects has
// different needs, I can either 1) reconfigure my entire baseline prior
// to building each project, or 2) host a configuration file which contains
// the information regarding each baseline. This file is that
// configuration file. It controls how the CPU (not the system,
// peripherals, or other) is defined and implemented. Several options
// are available within here, making the Zip CPU pipelined or not,
// able to handle a faster clock with more stalls or a slower clock with
// no stalls, etc.
//
// This file encapsulates those control options.
//
// The number of LUTs the Zip CPU uses varies dramatically with the
// options defined in this file.
//
//
// OpenArty comments:
// My goal on the OpenArty is going to be using the CPU to its fullest
// extent. All features shall be turned on if they exist, full pipelines,
// multiplies, divides, and hopefully even the 200MHz clock. This file
// reflects that purpose.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////////
`ifndef CPUDEFS_H
`define CPUDEFS_H
//
//
// The first couple options control the Zip CPU instruction set, and how
// it handles various instructions within the set:
//
//
// OPT_ILLEGAL_INSTRUCTION is part of a new section of code that is supposed
// to recognize illegal instructions and interrupt the CPU whenever one such
// instruction is encountered. The goal is to create a soft floating point
// unit via this approach, that can then be replaced with a true floating point
// unit. As I'm not there yet, it just catches illegal instructions and
// interrupts the CPU on any such instruction--when defined. Otherwise,
// illegal instructions are quietly ignored and their behaviour is ...
// undefined. (Many get treated like NOOPs ...)
//
// I recommend setting this flag, although it can be taken out if area is
// critical ...
//
`define OPT_ILLEGAL_INSTRUCTION
//
//
//
// OPT_MULTIPLY controls whether or not the multiply is built and included
// in the ALU by default. Set this option and a parameter will be set that
// includes the multiply. (This parameter may still be overridden, as with
// any parameter ...) If the multiply is not included and
// OPT_ILLEGAL_INSTRUCTION is set, then the multiply will create an illegal
// instruction that will then trip the illegal instruction trap.
//
//
`define OPT_MULTIPLY 1
//
//
//
// OPT_DIVIDE controls whether or not the divide instruction is built and
// included into the ZipCPU by default. Set this option and a parameter will
// be set that causes the divide unit to be included. (This parameter may
// still be overridden, as with any parameter ...) If the divide is not
// included and OPT_ILLEGAL_INSTRUCTION is set, then the multiply will create
// an illegal instruction exception that will send the CPU into supervisor
// mode.
//
//
// `define OPT_DIVIDE
//
//
//
// OPT_IMPLEMENT_FPU will (one day) control whether or not the floating point
// unit (once I have one) is built and included into the ZipCPU by default.
// At that time, if this option is set then a parameter will be set that
// causes the floating point unit to be included. (This parameter may
// still be overridden, as with any parameter ...) If the floating point unit
// is not included and OPT_ILLEGAL_INSTRUCTION is set, then as with the
// multiply and divide any floating point instruction will result in an illegal
// instruction exception that will send the CPU into supervisor mode.
//
//
// `define OPT_IMPLEMENT_FPU
//
//
//
// OPT_NEW_INSTRUCTION_SET controls whether or not the new instruction set
// is in use. The new instruction set contains space for floating point
// operations, signed and unsigned divide instructions, as well as bit reversal
// and ... at least two other operations yet to be defined. The decoder alone
// uses about 70 fewer LUTs, although in practice this works out to 12 fewer
// when all works out in the wash. Further, floating point and divide
// instructions will cause an illegal instruction exception if they are not
// implemented--so software capability can be built to use these instructions
// immediately, even if the hardware is not yet ready.
//
// This option is likely to go away in the future, obsoleting the previous
// instruction set, so I recommend setting this option and switching to the
// new instruction set as soon as possible.
//
`define OPT_NEW_INSTRUCTION_SET
//
//
//
//
//
//
// OPT_SINGLE_FETCH controls whether or not the prefetch has a cache, and
// whether or not it can issue one instruction per clock. When set, the
// prefetch has no cache, and only one instruction is fetched at a time.
// This effectively sets the CPU so that only one instruction is ever
// in the pipeline at once, and hence you may think of this as a "kill
// pipeline" option. However, since the pipelined fetch component uses so
// much area on the FPGA, this is an important option to use in trimming down
// used area if necessary. Hence, it needs to be maintained for that purpose.
// Be aware, though, it will drop your performance by a factor between 2x and
// 3x.
//
// We can either pipeline our fetches, or issue one fetch at a time. Pipelined
// fetches are more complicated and therefore use more FPGA resources, while
// single fetches will cause the CPU to stall for about 5 stalls each
// instruction cycle, effectively reducing the instruction count per clock to
// about 0.2. However, the area cost may be worth it. Consider:
//
// Slice LUTs ZipSystem ZipCPU
// Single Fetching 2521 1734
// Pipelined fetching 2796 2046
// (These numbers may be dated, but should still be representative ...)
//
// I recommend only defining this if you "need" to, if area is tight and
// speed isn't as important. Otherwise, just leave this undefined.
//
// `define OPT_SINGLE_FETCH
//
//
//
// The next several options are pipeline optimization options. They make no
// sense in a single instruction fetch mode, hence we #ifndef them so they
// are only defined if we are in a full pipelined mode (i.e. OPT_SINGLE_FETCH
// is not defined).
//
`ifndef OPT_SINGLE_FETCH
//
//
//
// OPT_PIPELINED is the natural result and opposite of using the single
// instruction fetch unit. If you are not using that unit, the ZipCPU will
// be pipelined. The option is defined here more for readability than
// anything else, since OPT_PIPELINED makes more sense than OPT_SINGLE_FETCH,
// well ... that and it does a better job of explaining what is going on.
//
// In other words, leave this define alone--lest you break the ZipCPU.
//
`define OPT_PIPELINED
//
//
//
// OPT_TRADITIONAL_PFCACHE allows you to switch between one of two prefetch
// caches. If enabled, a more traditional cache is implemented. This more
// traditional cache (currently) uses many more LUTs, but it also reduces
// the stall count tremendously over the alternative hacked pipeline cache.
// (The traditional pfcache is also pipelined, whereas the pipeline cache
// implements a windowed approach to caching.)
//
// If you have the fabric to support this option, I recommend including it.
//
`define OPT_TRADITIONAL_PFCACHE
//
//
//
// OPT_EARLY_BRANCHING is an attempt to execute a BRA statement as early
// as possible, to avoid as many pipeline stalls on a branch as possible.
// It's not tremendously successful yet--BRA's still suffer stalls,
// but I intend to keep working on this approach until the number of stalls
// gets down to one or (ideally) zero. (With the OPT_TRADITIONAL_PFCACHE, this
// gets down to a single stall cycle ...) That way a "BRA" can be used as the
// compiler's branch prediction optimizer: BRA's barely stall, while branches
// on conditions will always suffer about 4 stall cycles or so.
//
// I recommend setting this flag, so as to turn early branching on.
//
`define OPT_EARLY_BRANCHING
//
//
//
// OPT_PIPELINED_BUS_ACCESS controls whether or not LOD/STO instructions
// can take advantaged of pipelined bus instructions. To be eligible, the
// operations must be identical (cannot pipeline loads and stores, just loads
// only or stores only), and the addresses must either be identical or one up
// from the previous address. Further, the load/store string must all have
// the same conditional. This approach gains the must use, in my humble
// opinion, when saving registers to or restoring registers from the stack
// at the beginning/end of a procedure, or when doing a context swap.
//
// I recommend setting this flag, for performance reasons, especially if your
// wishbone bus can handle pipelined bus accesses.
//
`define OPT_PIPELINED_BUS_ACCESS
//
//
//
`ifdef OPT_NEW_INSTRUCTION_SET
//
//
//
// The new instruction set also defines a set of very long instruction words.
// Well, calling them "very long" instruction words is probably a misnomer,
// although we're going to do it. They're really 2x16-bit instructions---
// instruction words that pack two instructions into one word. (2x14 bit
// really--'cause you need a bit to note the instruction is a 2x instruction,
// and then 3-bits for the condition codes ...) Set OPT_VLIW to include these
// double instructions as part of the new instruction set. These allow a single
// instruction to contain two instructions within. These instructions are
// designed to get more code density from the instruction set, and to hopefully
// take some pain off of the performance of the pre-fetch and instruction cache.
//
// These new instructions, however, also necessitate a change in the Zip
// CPU--the Zip CPU can no longer execute instructions atomically. It must
// now execute non-VLIW instructions, or VLIW instruction pairs, atomically.
// This logic has been added into the ZipCPU, but it has not (yet) been
// tested thoroughly.
//
// Oh, and the assembler, the debugger, and the object file dumper, and the
// simulator all need to be updated as well ....
//
`define OPT_VLIW
//
//
`endif // OPT_NEW_INSTRUCTION_SET
//
//
`endif // OPT_SINGLE_FETCH
//
//
//
// Now let's talk about peripherals for a moment. These next two defines
// control whether the DMA controller is included in the Zip System, and
// whether or not the 8 accounting timers are also included. Set these to
// include the respective peripherals, comment them out not to.
//
`define INCLUDE_DMA_CONTROLLER
`define INCLUDE_ACCOUNTING_COUNTERS
//
//
// `define DEBUG_SCOPE
//
`endif // CPUDEFS_H
/rtl/cpu/pfcache.v
0,0 → 1,298
////////////////////////////////////////////////////////////////////////////////
//
// Filename: pfcache.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: Keeping our CPU fed with instructions, at one per clock and
// with no stalls. An unusual feature of this cache is the
// requirement that the entire cache may be cleared (if necessary).
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
module pfcache(i_clk, i_rst, i_new_pc, i_clear_cache,
// i_early_branch, i_from_addr,
i_stall_n, i_pc, o_i, o_pc, o_v,
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,
o_illegal);
parameter LGCACHELEN = 8, ADDRESS_WIDTH=24,
CACHELEN=(1<<LGCACHELEN), BUSW=32, AW=ADDRESS_WIDTH,
CW=LGCACHELEN, PW=LGCACHELEN-5;
input i_clk, i_rst, i_new_pc;
input i_clear_cache;
input i_stall_n;
input [(AW-1):0] i_pc;
output wire [(BUSW-1):0] o_i;
output wire [(AW-1):0] o_pc;
output wire o_v;
//
output reg o_wb_cyc, o_wb_stb;
output wire o_wb_we;
output reg [(AW-1):0] o_wb_addr;
output wire [(BUSW-1):0] o_wb_data;
//
input i_wb_ack, i_wb_stall, i_wb_err;
input [(BUSW-1):0] i_wb_data;
//
output reg o_illegal;
 
// Fixed bus outputs: we read from the bus only, never write.
// Thus the output data is ... irrelevant and don't care. We set it
// to zero just to set it to something.
assign o_wb_we = 1'b0;
assign o_wb_data = 0;
 
wire r_v;
reg [(BUSW-1):0] cache [0:((1<<CW)-1)];
reg [(AW-CW-1):0] tags [0:((1<<(CW-PW))-1)];
reg [((1<<(CW-PW))-1):0] vmask;
 
reg [(AW-1):0] lastpc;
reg [(CW-1):0] rdaddr;
reg [(AW-1):CW] tagvalipc, tagvallst;
wire [(AW-1):CW] tagval;
wire [(AW-1):PW] lasttag;
reg illegal_valid;
reg [(AW-1):PW] illegal_cache;
 
// initial o_i = 32'h76_00_00_00; // A NOOP instruction
// initial o_pc = 0;
reg [(BUSW-1):0] r_pc_cache, r_last_cache;
reg [(AW-1):0] r_pc, r_lastpc;
reg isrc;
always @(posedge i_clk)
begin
// We don't have the logic to select what to read, we must
// read both the value at i_pc and lastpc. cache[i_pc] is
// the value we return if the cache is good, cacne[lastpc] is
// the value we return if we've been stalled, weren't valid,
// or had to wait a clock or two. (Remember i_pc can't stop
// changing for a clock, so we need to keep track of the last
// one from before it stopped.)
//
// Here we keep track of which answer we want/need
isrc <= ((r_v)&&(i_stall_n))||(i_new_pc);
 
// Here we read both, and select which was write using isrc
// on the next clock.
r_pc_cache <= cache[i_pc[(CW-1):0]];
r_last_cache <= cache[lastpc[(CW-1):0]];
r_pc <= i_pc;
r_lastpc <= lastpc;
end
assign o_pc = (isrc) ? r_pc : r_lastpc;
assign o_i = (isrc) ? r_pc_cache : r_last_cache;
 
reg tagsrc;
always @(posedge i_clk)
// It may be possible to recover a clock once the cache line
// has been filled, but our prior attempt to do so has lead
// to a race condition, so we keep this logic simple.
if (((r_v)&&(i_stall_n))||(i_clear_cache)||(i_new_pc))
tagsrc <= 1'b1;
else
tagsrc <= 1'b0;
initial tagvalipc = 0;
always @(posedge i_clk)
tagvalipc <= tags[i_pc[(CW-1):PW]];
initial tagvallst = 0;
always @(posedge i_clk)
tagvallst <= tags[lastpc[(CW-1):PW]];
assign tagval = (tagsrc)?tagvalipc : tagvallst;
 
// i_pc will only increment when everything else isn't stalled, thus
// we can set it without worrying about that. Doing this enables
// us to work in spite of stalls. For example, if the next address
// isn't valid, but the decoder is stalled, get the next address
// anyway.
initial lastpc = 0;
always @(posedge i_clk)
if (((r_v)&&(i_stall_n))||(i_clear_cache)||(i_new_pc))
lastpc <= i_pc;
 
assign lasttag = lastpc[(AW-1):PW];
 
wire w_v_from_pc, w_v_from_last;
assign w_v_from_pc = ((i_pc[(AW-1):PW] == lasttag)
&&(tagvalipc == i_pc[(AW-1):CW])
&&(vmask[i_pc[(CW-1):PW]]));
assign w_v_from_last = (
//(lastpc[(AW-1):PW] == lasttag)&&
(tagval == lastpc[(AW-1):CW])
&&(vmask[lastpc[(CW-1):PW]]));
 
reg [1:0] delay;
 
initial delay = 2'h3;
reg rvsrc;
always @(posedge i_clk)
if ((i_rst)||(i_clear_cache)||(i_new_pc)||((r_v)&&(i_stall_n)))
begin
// r_v <= r_v_from_pc;
rvsrc <= 1'b1;
delay <= 2'h2;
end else if (~r_v) begin // Otherwise, r_v was true and we were
// stalled, hence only if ~r_v
rvsrc <= 1'b0;
if (o_wb_cyc)
delay <= 2'h2;
else if (delay != 0)
delay <= delay + 2'b11; // i.e. delay -= 1;
end
reg r_v_from_pc, r_v_from_last;
always @(posedge i_clk)
r_v_from_pc <= w_v_from_pc;
always @(posedge i_clk)
r_v_from_last <= w_v_from_last;
 
assign r_v = ((rvsrc)?(r_v_from_pc):(r_v_from_last));
assign o_v = (((rvsrc)?(r_v_from_pc):(r_v_from_last))
||((o_illegal)&&(~o_wb_cyc)))
&&(~i_new_pc)&&(~i_rst);
 
reg last_ack;
initial last_ack = 1'b0;
always @(posedge i_clk)
last_ack <= (o_wb_cyc)&&(
(rdaddr[(PW-1):1]=={(PW-1){1'b1}})
&&((rdaddr[0])||(i_wb_ack)));
 
reg needload;
initial needload = 1'b0;
always @(posedge i_clk)
needload <= ((~r_v)&&(delay==0)
&&((tagvallst != lastpc[(AW-1):CW])
||(~vmask[lastpc[(CW-1):PW]]))
&&((~illegal_valid)
||(lastpc[(AW-1):PW] != illegal_cache)));
 
reg last_addr;
initial last_addr = 1'b0;
always @(posedge i_clk)
last_addr <= (o_wb_cyc)&&(o_wb_addr[(PW-1):1] == {(PW-1){1'b1}})
&&((~i_wb_stall)|(o_wb_addr[0]));
 
initial o_wb_cyc = 1'b0;
initial o_wb_stb = 1'b0;
initial o_wb_addr = {(AW){1'b0}};
initial rdaddr = 0;
always @(posedge i_clk)
if ((i_rst)||(i_clear_cache))
begin
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
end else if (o_wb_cyc)
begin
if (i_wb_err)
o_wb_stb <= 1'b0;
else if ((o_wb_stb)&&(~i_wb_stall)&&(last_addr))
o_wb_stb <= 1'b0;
 
if (((i_wb_ack)&&(last_ack))||(i_wb_err))
o_wb_cyc <= 1'b0;
 
// else if (rdaddr[(PW-1):1] == {(PW-1){1'b1}})
// tags[lastpc[(CW-1):PW]] <= lastpc[(AW-1):CW];
 
end else if (needload)
begin
o_wb_cyc <= 1'b1;
o_wb_stb <= 1'b1;
end
 
always @(posedge i_clk)
if (o_wb_cyc) // &&(i_wb_ack)
tags[o_wb_addr[(CW-1):PW]] <= o_wb_addr[(AW-1):CW];
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
rdaddr <= rdaddr + 1;
else if (~o_wb_cyc)
rdaddr <= { lastpc[(CW-1):PW], {(PW){1'b0}} };
always @(posedge i_clk)
if ((o_wb_stb)&&(~i_wb_stall)&&(~last_addr))
o_wb_addr[(PW-1):0] <= o_wb_addr[(PW-1):0]+1;
else if (~o_wb_cyc)
o_wb_addr <= { lastpc[(AW-1):PW], {(PW){1'b0}} };
 
// Can't initialize an array, so leave cache uninitialized
// We'll also never get an ack without sys being active, so skip
// that check. Or rather, let's just use o_wb_cyc instead. This
// will work because multiple writes to the same address, ending with
// a valid write, aren't a problem.
always @(posedge i_clk)
if (o_wb_cyc) // &&(i_wb_ack)
cache[rdaddr] <= i_wb_data;
 
// VMask ... is a section loaded?
// Note "svmask". It's purpose is to delay the vmask setting by one
// clock, so that we can insure the right value of the cache is loaded
// before declaring that the cache line is valid. Without this, the
// cache line would get read, and the instruction would read from the
// last cache line.
reg svmask;
initial vmask = 0;
initial svmask = 1'b0;
reg [(CW-PW-1):0] saddr;
always @(posedge i_clk)
if ((i_rst)||(i_clear_cache))
begin
vmask <= 0;
svmask<= 1'b0;
end
else begin
svmask <= ((o_wb_cyc)&&(i_wb_ack)&&(last_ack));
if (svmask)
vmask[saddr] <= 1'b1;
if ((~o_wb_cyc)&&(needload))
vmask[lastpc[(CW-1):PW]] <= 1'b0;
end
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
saddr <= rdaddr[(CW-1):PW];
 
initial illegal_cache = 0;
initial illegal_valid = 0;
always @(posedge i_clk)
if ((i_rst)||(i_clear_cache))
begin
illegal_cache <= 0;
illegal_valid <= 0;
end else if ((o_wb_cyc)&&(i_wb_err))
begin
illegal_cache <= o_wb_addr[(AW-1):PW];
illegal_valid <= 1'b1;
end
 
initial o_illegal = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(i_clear_cache)||(o_wb_cyc))
o_illegal <= 1'b0;
else
o_illegal <= (illegal_valid)
&&(illegal_cache == i_pc[(AW-1):PW]);
 
endmodule
/rtl/cpu/zipbones.v
0,0 → 1,215
///////////////////////////////////////////////////////////////////////////
//
// Filename: zipbones.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: In the spirit of keeping the Zip CPU small, this implements a
// Zip System with no peripherals: Any peripherals you wish will
// need to be implemented off-module.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
`include "cpudefs.v"
//
module zipbones(i_clk, i_rst,
// Wishbone master interface from the CPU
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_data, i_wb_err,
// Incoming interrupts
i_ext_int,
// Our one outgoing interrupt
o_ext_int,
// Wishbone slave interface for debugging purposes
i_dbg_cyc, i_dbg_stb, i_dbg_we, i_dbg_addr, i_dbg_data,
o_dbg_ack, o_dbg_stall, o_dbg_data
`ifdef DEBUG_SCOPE
, o_zip_debug
`endif
);
parameter RESET_ADDRESS=32'h0100000, ADDRESS_WIDTH=32,
LGICACHE=6, START_HALTED=0,
AW=ADDRESS_WIDTH, HIGHSPEED_CPU=1;
input i_clk, i_rst;
// Wishbone master
output wire o_wb_cyc, o_wb_stb, o_wb_we;
output wire [(AW-1):0] o_wb_addr;
output wire [31:0] o_wb_data;
input i_wb_ack, i_wb_stall;
input [31:0] i_wb_data;
input i_wb_err;
// Incoming interrupts
input i_ext_int;
// Outgoing interrupt
output wire o_ext_int;
// Wishbone slave
input i_dbg_cyc, i_dbg_stb, i_dbg_we, i_dbg_addr;
input [31:0] i_dbg_data;
output reg o_dbg_ack;
output wire o_dbg_stall;
output wire [31:0] o_dbg_data;
//
`ifdef DEBUG_SCOPE
output wire [31:0] o_zip_debug;
`endif
 
//
//
//
wire sys_cyc, sys_stb, sys_we;
wire [4:0] sys_addr;
wire [(AW-1):0] cpu_addr;
wire [31:0] sys_data;
wire sys_ack, sys_stall;
 
//
// The external debug interface
//
// We offer only a limited interface here, requiring a pre-register
// write to set the local address. This interface allows access to
// the Zip System on a debug basis only, and not to the rest of the
// wishbone bus. Further, to access these registers, the control
// register must first be accessed to both stop the CPU and to
// set the following address in question. Hence all accesses require
// two accesses: write the address to the control register (and halt
// the CPU if not halted), then read/write the data from the data
// register.
//
wire cpu_break, dbg_cmd_write;
reg cmd_reset, cmd_halt, cmd_step, cmd_clear_pf_cache;
reg [4:0] cmd_addr;
wire [3:0] cpu_dbg_cc;
assign dbg_cmd_write = (i_dbg_cyc)&&(i_dbg_stb)&&(i_dbg_we)&&(~i_dbg_addr);
//
// Always start us off with an initial reset
//
initial cmd_reset = 1'b1;
always @(posedge i_clk)
cmd_reset <= ((dbg_cmd_write)&&(i_dbg_data[6]));
//
initial cmd_halt = START_HALTED;
always @(posedge i_clk)
if (i_rst)
cmd_halt <= (START_HALTED == 1)? 1'b1 : 1'b0;
else if (dbg_cmd_write)
cmd_halt <= ((i_dbg_data[10])||(i_dbg_data[8]));
else if ((cmd_step)||(cpu_break))
cmd_halt <= 1'b1;
 
initial cmd_clear_pf_cache = 1'b0;
always @(posedge i_clk)
if (i_rst)
cmd_clear_pf_cache <= 1'b0;
else if (dbg_cmd_write)
cmd_clear_pf_cache <= i_dbg_data[11];
else
cmd_clear_pf_cache <= 1'b0;
//
initial cmd_step = 1'b0;
always @(posedge i_clk)
cmd_step <= (dbg_cmd_write)&&(i_dbg_data[8]);
//
initial cmd_addr = 5'h0;
always @(posedge i_clk)
if (dbg_cmd_write)
cmd_addr <= i_dbg_data[4:0];
 
wire cpu_reset;
assign cpu_reset = (cmd_reset)||(i_rst);
 
wire cpu_halt, cpu_dbg_stall;
assign cpu_halt = (i_rst)||((cmd_halt)&&(~cmd_step));
wire [31:0] cmd_data;
// Values:
// 0x0003f -> cmd_addr mask
// 0x00040 -> reset
// 0x00080 -> PIC interrrupts enabled
// 0x00100 -> cmd_step
// 0x00200 -> cmd_stall
// 0x00400 -> cmd_halt
// 0x00800 -> cmd_clear_pf_cache
// 0x01000 -> cc.sleep
// 0x02000 -> cc.gie
// 0x10000 -> External interrupt line is high
assign cmd_data = { 7'h00, 8'h00, i_ext_int,
cpu_dbg_cc,
1'b0, cmd_halt, (~cpu_dbg_stall), 1'b0,
1'b0, cpu_reset, 1'b0, cmd_addr };
 
//
// The CPU itself
//
wire cpu_gbl_stb, cpu_lcl_cyc, cpu_lcl_stb,
cpu_we, cpu_dbg_we,
cpu_op_stall, cpu_pf_stall, cpu_i_count;
wire [31:0] cpu_data;
wire [31:0] cpu_dbg_data;
assign cpu_dbg_we = ((i_dbg_cyc)&&(i_dbg_stb)
&&(i_dbg_we)&&(i_dbg_addr));
generate
if (HIGHSPEED_CPU==0)
begin
zipcpu #(RESET_ADDRESS,ADDRESS_WIDTH,LGICACHE)
thecpu(i_clk, cpu_reset, i_ext_int,
cpu_halt, cmd_clear_pf_cache, cmd_addr[4:0], cpu_dbg_we,
i_dbg_data, cpu_dbg_stall, cpu_dbg_data,
cpu_dbg_cc, cpu_break,
o_wb_cyc, o_wb_stb,
cpu_lcl_cyc, cpu_lcl_stb,
o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_data,
(i_wb_err)||((cpu_lcl_cyc)&&(cpu_lcl_stb)),
cpu_op_stall, cpu_pf_stall, cpu_i_count
`ifdef DEBUG_SCOPE
, o_zip_debug
`endif
);
end else begin
zipcpuhs #(RESET_ADDRESS,ADDRESS_WIDTH,LGICACHE)
thecpu(i_clk, cpu_reset, i_ext_int,
cpu_halt, cmd_clear_pf_cache, cmd_addr[4:0], cpu_dbg_we,
i_dbg_data, cpu_dbg_stall, cpu_dbg_data,
cpu_dbg_cc, cpu_break,
o_wb_cyc, o_wb_stb,
cpu_lcl_cyc, cpu_lcl_stb,
o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_data,
(i_wb_err)||((cpu_lcl_cyc)&&(cpu_lcl_stb)),
cpu_op_stall, cpu_pf_stall, cpu_i_count
`ifdef DEBUG_SCOPE
, o_zip_debug
`endif
);
end endgenerate
 
// Return debug response values
assign o_dbg_data = (~i_dbg_addr)?cmd_data :cpu_dbg_data;
initial o_dbg_ack = 1'b0;
always @(posedge i_clk)
o_dbg_ack <= (i_dbg_cyc)&&((~i_dbg_addr)||(~o_dbg_stall));
assign o_dbg_stall=(i_dbg_cyc)&&(cpu_dbg_stall)&&(i_dbg_addr);
 
assign o_ext_int = (cmd_halt) && (~i_wb_stall);
 
endmodule
/rtl/cpu/icontrol.v
0,0 → 1,153
////////////////////////////////////////////////////////////////////////////////
//
// Filename: icontrol.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: An interrupt controller, for managing many interrupt sources.
//
// This interrupt controller started from the question of how best to
// design a simple interrupt controller. As such, it has a few nice
// qualities to it:
// 1. This is wishbone compliant
// 2. It sits on a 32-bit wishbone data bus
// 3. It only consumes one address on that wishbone bus.
// 4. There is no extra delays associated with reading this
// device.
// 5. Common operations can all be done in one clock.
//
// So, how shall this be used? First, the 32-bit word is broken down as
// follows:
//
// Bit 31 - This is the global interrupt enable bit. If set, interrupts
// will be generated and passed on as they come in.
// Bits 16-30 - These are specific interrupt enable lines. If set,
// interrupts from source (bit#-16) will be enabled.
// To set this line and enable interrupts from this source, write
// to the register with this bit set and the global enable set.
// To disable this line, write to this register with global enable
// bit not set, but this bit set. (Writing a zero to any of these
// bits has no effect, either setting or unsetting them.)
// Bit 15 - This is the any interrupt pin. If any interrupt is pending,
// this bit will be set.
// Bits 0-14 - These are interrupt bits. When set, an interrupt is
// pending from the corresponding source--regardless of whether
// it was enabled. (If not enabled, it won't generate an
// interrupt, but it will still register here.) To clear any
// of these bits, write a '1' to the corresponding bit. Writing
// a zero to any of these bits has no effect.
//
// The peripheral also sports a parameter, IUSED, which can be set
// to any value between 1 and (buswidth/2-1, or) 15 inclusive. This will
// be the number of interrupts handled by this routine. (Without the
// parameter, Vivado was complaining about unused bits. With it, we can
// keep the complaints down and still use the routine).
//
// To get access to more than 15 interrupts, chain these together, so
// that one interrupt controller device feeds another.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
module icontrol(i_clk, i_reset, i_wr, i_proc_bus, o_proc_bus,
i_brd_ints, o_interrupt);
parameter IUSED = 15;
input i_clk, i_reset;
input i_wr;
input [31:0] i_proc_bus;
output wire [31:0] o_proc_bus;
input [(IUSED-1):0] i_brd_ints;
output wire o_interrupt;
 
reg [(IUSED-1):0] r_int_state;
reg [(IUSED-1):0] r_int_enable;
wire [(IUSED-1):0] nxt_int_state;
reg r_any, r_interrupt, r_gie;
 
assign nxt_int_state = (r_int_state|i_brd_ints);
initial r_int_state = 0;
always @(posedge i_clk)
if (i_reset)
r_int_state <= 0;
else if (i_wr)
r_int_state <= nxt_int_state & (~i_proc_bus[(IUSED-1):0]);
else
r_int_state <= nxt_int_state;
initial r_int_enable = 0;
always @(posedge i_clk)
if (i_reset)
r_int_enable <= 0;
else if ((i_wr)&&(i_proc_bus[31]))
r_int_enable <= r_int_enable | i_proc_bus[(16+IUSED-1):16];
else if ((i_wr)&&(~i_proc_bus[31]))
r_int_enable <= r_int_enable & (~ i_proc_bus[(16+IUSED-1):16]);
 
initial r_gie = 1'b0;
always @(posedge i_clk)
if (i_reset)
r_gie <= 1'b0;
else if (i_wr)
r_gie <= i_proc_bus[31];
 
initial r_any = 1'b0;
always @(posedge i_clk)
r_any <= ((r_int_state & r_int_enable) != 0);
initial r_interrupt = 1'b0;
always @(posedge i_clk)
r_interrupt <= r_gie & r_any;
 
generate
if (IUSED < 15)
begin
assign o_proc_bus = {
r_gie, { {(15-IUSED){1'b0}}, r_int_enable },
r_any, { {(15-IUSED){1'b0}}, r_int_state } };
end else begin
assign o_proc_bus = { r_gie, r_int_enable, r_any, r_int_state };
end endgenerate
 
/*
reg int_condition;
initial int_condition = 1'b0;
initial o_interrupt_strobe = 1'b0;
always @(posedge i_clk)
if (i_reset)
begin
int_condition <= 1'b0;
o_interrupt_strobe <= 1'b0;
end else if (~r_interrupt) // This might end up generating
begin // many, many, (wild many) interrupts
int_condition <= 1'b0;
o_interrupt_strobe <= 1'b0;
end else if ((~int_condition)&&(r_interrupt))
begin
int_condition <= 1'b1;
o_interrupt_strobe <= 1'b1;
end else
o_interrupt_strobe <= 1'b0;
*/
 
assign o_interrupt = r_interrupt;
 
endmodule
/rtl/cpu/wbwatchdog.v
0,0 → 1,76
///////////////////////////////////////////////////////////////////////////
//
// Filename: wbwatchdog.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: A Zip timer, redesigned to be a bus watchdog
//
// This is a **really** stripped down Zip Timer. All options for external
// control have been removed. This timer may be reset, and ... that's
// about it. The goal is that this stripped down timer be used as a bus
// watchdog element. Even at that, it's not really fully featured. The
// rest of the important features can be found in the zipsystem module.
//
// As a historical note, the wishbone watchdog timer began as a normal
// timer, with some fixed inputs. This makes sense, if you think about it:
// if the goal is to interrupt a stalled wishbone transaction by inserting
// a bus error, then you can't use the bus to set it up or configure it
// simply because the bus in question is ... well, unreliable. You're
// trying to make it reliable.
//
// The problem with using the ziptimer in a stripped down implementation
// was that the fixed inputs caused the synthesis tool to complain about
// the use of registers values would never change. This solves that
// problem by explicitly removing the cruft that would otherwise
// just create synthesis warnings and errors.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
module wbwatchdog(i_clk, i_rst, i_ce, i_timeout, o_int);
parameter BW = 32;
input i_clk, i_rst, i_ce;
// Inputs (these were at one time wishbone controlled ...)
input [(BW-1):0] i_timeout;
// Interrupt line
output reg o_int;
 
reg [(BW-1):0] r_value;
initial r_value = 0;
always @(posedge i_clk)
if (i_rst)
r_value <= i_timeout[(BW-1):0];
else if ((i_ce)&&(~o_int))
r_value <= r_value + {(BW){1'b1}}; // r_value - 1;
 
// Set the interrupt on our last tick.
initial o_int = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(~i_ce))
o_int <= 1'b0;
else
o_int <= (r_value == { {(BW-1){1'b0}}, 1'b1 });
 
endmodule
/rtl/cpu/wbdblpriarb.v
0,0 → 1,142
///////////////////////////////////////////////////////////////////////////
//
// Filename: wbdblpriarb.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: This should almost be identical to the priority arbiter, save
// for a simple diffence: it allows the arbitration of two
// separate wishbone buses. The purpose of this is to push the address
// resolution back one cycle, so that by the first clock visible to this
// core, it is known which of two parts of the bus the desired address
// will be on, save that we still use the arbiter since the underlying
// device doesn't know that there are two wishbone buses.
//
// So at this point we've deviated from the WB spec somewhat, by allowing
// two CYC and two STB lines. Everything else is the same. This allows
// (in this case the Zip CPU) to determine whether or not the access
// will be to the local ZipSystem bus or the external WB bus on the clock
// before the local bus access, otherwise peripherals were needing to do
// multiple device selection comparisons/test within a clock: 1) is this
// for the local or external bus, and 2) is this referencing me as a
// peripheral. This then caused the ZipCPU to fail all timing specs.
// By creating the two pairs of lines, CYC_A/STB_A and CYC_B/STB_B, the
// determination of local vs external can be made one clock earlier
// where there's still time for the logic, and the second comparison
// now has time to complete.
//
// So let me try to explain this again. To use this arbiter, one of the
// two masters sets CYC and STB before, only the master determines which
// of two address spaces the CYC and STB apply to before the clock and
// only sets the appropriate CYC and STB lines. Then, on the clock tick,
// the arbiter determines who gets *both* busses, as they both share every
// other WB line. Thus, only one of CYC_A and CYC_B going out will ever
// be high at a given time.
//
// Hopefully this makes more sense than it sounds. If not, check out the
// code below for a better explanation.
//
// 20150919 -- Added supported for the WB error signal.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
module wbdblpriarb(i_clk, i_rst,
// Bus A
i_a_cyc_a,i_a_cyc_b,i_a_stb_a,i_a_stb_b,i_a_we,i_a_adr, i_a_dat, o_a_ack, o_a_stall, o_a_err,
// Bus B
i_b_cyc_a,i_b_cyc_b,i_b_stb_a,i_b_stb_b,i_b_we,i_b_adr, i_b_dat, o_b_ack, o_b_stall, o_b_err,
// Both buses
o_cyc_a, o_cyc_b, o_stb_a, o_stb_b, o_we, o_adr, o_dat,
i_ack, i_stall, i_err);
parameter DW=32, AW=32;
// Wishbone doesn't use an i_ce signal. While it could, they dislike
// what it would (might) do to the synchronous reset signal, i_rst.
input i_clk, i_rst;
// Bus A
input i_a_cyc_a, i_a_cyc_b, i_a_stb_a, i_a_stb_b, i_a_we;
input [(AW-1):0] i_a_adr;
input [(DW-1):0] i_a_dat;
output wire o_a_ack, o_a_stall, o_a_err;
// Bus B
input i_b_cyc_a, i_b_cyc_b, i_b_stb_a, i_b_stb_b, i_b_we;
input [(AW-1):0] i_b_adr;
input [(DW-1):0] i_b_dat;
output wire o_b_ack, o_b_stall, o_b_err;
//
output wire o_cyc_a,o_cyc_b, o_stb_a, o_stb_b, o_we;
output wire [(AW-1):0] o_adr;
output wire [(DW-1):0] o_dat;
input i_ack, i_stall, i_err;
 
// All of our logic is really captured in the 'r_a_owner' register.
// This register determines who owns the bus. If no one is requesting
// the bus, ownership goes to A on the next clock. Otherwise, if B is
// requesting the bus and A is not, then ownership goes to not A on
// the next clock. (Sounds simple ...)
//
// The CYC logic is here to make certain that, by the time we determine
// who the bus owner is, we can do so based upon determined criteria.
assign o_cyc_a = (~i_rst)&&((r_a_owner) ? i_a_cyc_a : i_b_cyc_a);
assign o_cyc_b = (~i_rst)&&((r_a_owner) ? i_a_cyc_b : i_b_cyc_b);
reg r_a_owner;
initial r_a_owner = 1'b1;
always @(posedge i_clk)
if (i_rst)
r_a_owner <= 1'b1;
else if ((~o_cyc_a)&&(~o_cyc_b))
r_a_owner <= ((i_b_cyc_a)||(i_b_cyc_b))? 1'b0:1'b1;
 
 
// Realistically, if neither master owns the bus, the output is a
// don't care. Thus we trigger off whether or not 'A' owns the bus.
// If 'B' owns it all we care is that 'A' does not. Likewise, if
// neither owns the bus than the values on these various lines are
// irrelevant.
assign o_stb_a = (r_a_owner) ? i_a_stb_a : i_b_stb_a;
assign o_stb_b = (r_a_owner) ? i_a_stb_b : i_b_stb_b;
assign o_we = (r_a_owner) ? i_a_we : i_b_we;
assign o_adr = (r_a_owner) ? i_a_adr : i_b_adr;
assign o_dat = (r_a_owner) ? i_a_dat : i_b_dat;
 
// We cannot allow the return acknowledgement to ever go high if
// the master in question does not own the bus. Hence we force it
// low if the particular master doesn't own the bus.
assign o_a_ack = ( r_a_owner) ? i_ack : 1'b0;
assign o_b_ack = (~r_a_owner) ? i_ack : 1'b0;
 
// Stall must be asserted on the same cycle the input master asserts
// the bus, if the bus isn't granted to him.
assign o_a_stall = ( r_a_owner) ? i_stall : 1'b1;
assign o_b_stall = (~r_a_owner) ? i_stall : 1'b1;
 
//
// These error lines will be implemented soon, as soon as the rest of
// the Zip CPU is ready to support them.
//
assign o_a_err = ( r_a_owner) ? i_err : 1'b0;
assign o_b_err = (~r_a_owner) ? i_err : 1'b0;
 
endmodule
 
/rtl/cpu/pipemem.v
0,0 → 1,196
///////////////////////////////////////////////////////////////////////////
//
// Filename: pipemem.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: A memory unit to support a CPU, this time one supporting
// pipelined wishbone memory accesses. The goal is to be able
// to issue one pipelined wishbone access per clock, and (given the memory
// is fast enough) to be able to read the results back at one access per
// clock. This renders on-chip memory fast enough to handle single cycle
// (pipelined) access.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
module pipemem(i_clk, i_rst, i_pipe_stb, i_lock,
i_op, i_addr, i_data, i_oreg,
o_busy, o_pipe_stalled, o_valid, o_err, o_wreg, o_result,
o_wb_cyc_gbl, o_wb_cyc_lcl,
o_wb_stb_gbl, o_wb_stb_lcl,
o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_err, i_wb_data);
parameter ADDRESS_WIDTH=24, IMPLEMENT_LOCK=0, AW=ADDRESS_WIDTH;
input i_clk, i_rst;
input i_pipe_stb, i_lock;
// CPU interface
input i_op;
input [31:0] i_addr;
input [31:0] i_data;
input [4:0] i_oreg;
// CPU outputs
output wire o_busy;
output reg o_pipe_stalled;
output reg o_valid;
output reg o_err;
output reg [4:0] o_wreg;
output reg [31:0] o_result;
// Wishbone outputs
output wire o_wb_cyc_gbl;
output reg o_wb_stb_gbl;
output wire o_wb_cyc_lcl;
output reg o_wb_stb_lcl, o_wb_we;
output reg [(AW-1):0] o_wb_addr;
output reg [31:0] o_wb_data;
// Wishbone inputs
input i_wb_ack, i_wb_stall, i_wb_err;
input [31:0] i_wb_data;
 
reg cyc;
reg r_wb_cyc_gbl, r_wb_cyc_lcl;
reg [3:0] rdaddr, wraddr;
wire [3:0] nxt_rdaddr;
reg [(5-1):0] fifo_oreg [0:15];
initial rdaddr = 0;
initial wraddr = 0;
always @(posedge i_clk)
fifo_oreg[wraddr] <= i_oreg;
always @(posedge i_clk)
if ((i_rst)||(i_wb_err))
wraddr <= 0;
else if (i_pipe_stb)
wraddr <= wraddr + 4'h1;
always @(posedge i_clk)
if ((i_rst)||(i_wb_err))
rdaddr <= 0;
else if ((i_wb_ack)&&(cyc))
rdaddr <= rdaddr + 4'h1;
assign nxt_rdaddr = rdaddr + 4'h1;
 
wire gbl_stb, lcl_stb;
assign lcl_stb = (i_addr[31:8]==24'hc00000)&&(i_addr[7:5]==3'h0);
assign gbl_stb = (~lcl_stb);
//= ((i_addr[31:8]!=24'hc00000)||(i_addr[7:5]!=3'h0));
 
initial cyc = 0;
initial r_wb_cyc_lcl = 0;
initial r_wb_cyc_gbl = 0;
always @(posedge i_clk)
if (i_rst)
begin
r_wb_cyc_gbl <= 1'b0;
r_wb_cyc_lcl <= 1'b0;
o_wb_stb_gbl <= 1'b0;
o_wb_stb_lcl <= 1'b0;
cyc <= 1'b0;
end else if (cyc)
begin
if ((~i_wb_stall)&&(~i_pipe_stb))
begin
o_wb_stb_gbl <= 1'b0;
o_wb_stb_lcl <= 1'b0;
// end else if ((i_pipe_stb)&&(~i_wb_stall))
// begin
// o_wb_addr <= i_addr[(AW-1):0];
// o_wb_data <= i_data;
end
 
if (((i_wb_ack)&&(nxt_rdaddr == wraddr))||(i_wb_err))
begin
r_wb_cyc_gbl <= 1'b0;
r_wb_cyc_lcl <= 1'b0;
cyc <= 1'b0;
end
end else if (i_pipe_stb) // New memory operation
begin // Grab the wishbone
r_wb_cyc_lcl <= lcl_stb;
r_wb_cyc_gbl <= gbl_stb;
o_wb_stb_lcl <= lcl_stb;
o_wb_stb_gbl <= gbl_stb;
cyc <= 1'b1;
// o_wb_addr <= i_addr[(AW-1):0];
// o_wb_data <= i_data;
// o_wb_we <= i_op
end
always @(posedge i_clk)
if ((cyc)&&(i_pipe_stb)&&(~i_wb_stall))
begin
o_wb_addr <= i_addr[(AW-1):0];
o_wb_data <= i_data;
end else if ((~cyc)&&(i_pipe_stb))
begin
o_wb_addr <= i_addr[(AW-1):0];
o_wb_data <= i_data;
end
always @(posedge i_clk)
if ((i_pipe_stb)&&(~cyc))
o_wb_we <= i_op;
 
initial o_valid = 1'b0;
always @(posedge i_clk)
o_valid <= (cyc)&&(i_wb_ack)&&(~o_wb_we);
initial o_err = 1'b0;
always @(posedge i_clk)
o_err <= (cyc)&&(i_wb_err);
assign o_busy = cyc;
 
always @(posedge i_clk)
o_wreg <= fifo_oreg[rdaddr];
always @(posedge i_clk)
// if (i_wb_ack) isn't necessary, since o_valid won't be true
// then either.
o_result <= i_wb_data;
 
/*
assign o_pipe_stalled = (cyc)
&&((i_wb_stall)||((~o_wb_stb_lcl)&&(~o_wb_stb_gbl)));
*/
always @(posedge i_clk)
o_pipe_stalled <= (i_pipe_stb)&&(cyc)&&(i_wb_stall);
 
generate
if (IMPLEMENT_LOCK != 0)
begin
reg lock_gbl, lock_lcl;
 
initial lock_gbl = 1'b0;
initial lock_lcl = 1'b0;
always @(posedge i_clk)
begin
lock_gbl <= (i_lock)&&((r_wb_cyc_gbl)||(lock_gbl));
lock_lcl <= (i_lock)&&((r_wb_cyc_lcl)||(lock_gbl));
end
 
assign o_wb_cyc_gbl = (r_wb_cyc_gbl)||(lock_gbl);
assign o_wb_cyc_lcl = (r_wb_cyc_lcl)||(lock_lcl);
 
end else begin
assign o_wb_cyc_gbl = (r_wb_cyc_gbl);
assign o_wb_cyc_lcl = (r_wb_cyc_lcl);
end endgenerate
 
endmodule
/rtl/cpu/idecode.v
0,0 → 1,489
///////////////////////////////////////////////////////////////////////////////
//
// Filename: idecode.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: This RTL file specifies how instructions are to be decoded
// into their underlying meanings. This is specifically a version
// designed to support a "Next Generation", or "Version 2" instruction
// set as (currently) activated by the OPT_NEW_INSTRUCTION_SET option
// in cpudefs.v.
//
// I expect to (eventually) retire the old instruction set, at which point
// this will become the default instruction set decoder.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////////
//
//
//
`define CPU_CC_REG 4'he
`define CPU_PC_REG 4'hf
//
`include "cpudefs.v"
//
//
//
module idecode(i_clk, i_rst, i_ce, i_stalled,
i_instruction, i_gie, i_pc, i_pf_valid,
i_illegal,
o_phase, o_illegal,
o_pc, o_gie,
o_dcdR, o_dcdA, o_dcdB, o_I, o_zI,
o_cond, o_wF,
o_op, o_ALU, o_M, o_DV, o_FP, o_break, o_lock,
o_wR, o_rA, o_rB,
o_early_branch, o_branch_pc, o_ljmp,
o_pipe
);
parameter ADDRESS_WIDTH=24, IMPLEMENT_MPY=1, EARLY_BRANCHING=1,
IMPLEMENT_DIVIDE=1, IMPLEMENT_FPU=0, AW = ADDRESS_WIDTH;
input i_clk, i_rst, i_ce, i_stalled;
input [31:0] i_instruction;
input i_gie;
input [(AW-1):0] i_pc;
input i_pf_valid, i_illegal;
output wire o_phase;
output reg o_illegal;
output reg [(AW-1):0] o_pc;
output reg o_gie;
output reg [6:0] o_dcdR, o_dcdA, o_dcdB;
output wire [31:0] o_I;
output reg o_zI;
output reg [3:0] o_cond;
output reg o_wF;
output reg [3:0] o_op;
output reg o_ALU, o_M, o_DV, o_FP, o_break;
output wire o_lock;
output reg o_wR, o_rA, o_rB;
output wire o_early_branch;
output wire [(AW-1):0] o_branch_pc;
output wire o_ljmp;
output wire o_pipe;
 
wire dcdA_stall, dcdB_stall, dcdF_stall;
wire o_dcd_early_branch;
wire [(AW-1):0] o_dcd_branch_pc;
reg o_dcdI, o_dcdIz;
`ifdef OPT_PIPELINED
reg r_lock;
`endif
`ifdef OPT_PIPELINED_BUS_ACCESS
reg r_pipe;
`endif
 
 
wire [4:0] w_op;
wire w_ldi, w_mov, w_cmptst, w_ldilo, w_ALU, w_brev, w_noop;
wire [4:0] w_dcdR, w_dcdB, w_dcdA;
wire w_dcdR_pc, w_dcdR_cc;
wire w_dcdA_pc, w_dcdA_cc;
wire w_dcdB_pc, w_dcdB_cc;
wire [3:0] w_cond;
wire w_wF, w_dcdM, w_dcdDV, w_dcdFP;
wire w_wR, w_rA, w_rB, w_wR_n;
wire w_ljmp, w_ljmp_dly;
wire [31:0] iword;
 
 
`ifdef OPT_VLIW
reg [16:0] r_nxt_half;
assign iword = (o_phase)
// set second half as a NOOP ... but really
// shouldn't matter
? { r_nxt_half[16:7], 1'b0, r_nxt_half[6:0], 5'b11000, 3'h7, 6'h00 }
: i_instruction;
`else
assign iword = { 1'b0, i_instruction[30:0] };
`endif
 
generate
if (EARLY_BRANCHING != 0)
assign w_ljmp = (iword == 32'h7c87c000);
else
assign w_ljmp = 1'b0;
endgenerate
 
 
assign w_op= iword[26:22];
assign w_mov = (w_op == 5'h0f);
assign w_ldi = (w_op[4:1] == 4'hb);
assign w_brev = (w_op == 5'hc);
assign w_cmptst = (w_op[4:1] == 4'h8);
assign w_ldilo = (w_op[4:0] == 5'h9);
assign w_ALU = (~w_op[4]);
 
// 4 LUTs
//
// Two parts to the result register: the register set, given for
// moves in i_word[18] but only for the supervisor, and the other
// four bits encoded in the instruction.
//
assign w_dcdR = { ((~iword[31])&&(w_mov)&&(~i_gie))?iword[18]:i_gie,
iword[30:27] };
// 2 LUTs
//
// If the result register is either CC or PC, and this would otherwise
// be a floating point instruction with floating point opcode of 0,
// then this is a NOOP.
assign w_noop = (w_op[4:0] == 5'h18)&&(
((IMPLEMENT_FPU>0)&&(w_dcdR[3:1] == 3'h7))
||(IMPLEMENT_FPU==0));
 
// 4 LUTs
assign w_dcdB = { ((~iword[31])&&(w_mov)&&(~i_gie))?iword[13]:i_gie,
iword[17:14] };
 
// 0 LUTs
assign w_dcdA = w_dcdR;
// 2 LUTs, 1 delay each
assign w_dcdR_pc = (w_dcdR == {i_gie, `CPU_PC_REG});
assign w_dcdR_cc = (w_dcdR == {i_gie, `CPU_CC_REG});
// 0 LUTs
assign w_dcdA_pc = w_dcdR_pc;
assign w_dcdA_cc = w_dcdR_cc;
// 2 LUTs, 1 delays each
assign w_dcdB_pc = (w_dcdB[3:0] == `CPU_PC_REG);
assign w_dcdB_cc = (w_dcdB[3:0] == `CPU_CC_REG);
 
// Under what condition will we execute this
// instruction? Only the load immediate instruction
// is completely unconditional.
//
// 3+4 LUTs
assign w_cond = (w_ldi) ? 4'h8 :
(iword[31])?{(iword[20:19]==2'b00),
1'b0,iword[20:19]}
: { (iword[21:19]==3'h0), iword[21:19] };
 
// 1 LUT
assign w_dcdM = (w_op[4:1] == 4'h9);
// 1 LUT
assign w_dcdDV = (w_op[4:1] == 4'ha);
// 1 LUT
assign w_dcdFP = (w_op[4:3] == 2'b11)&&(w_dcdR[3:1] != 3'h7);
// 4 LUT's--since it depends upon FP/NOOP condition (vs 1 before)
// Everything reads A but ... NOOP/BREAK/LOCK, LDI, LOD, MOV
assign w_rA = (w_dcdFP)
// Divide's read A
||(w_dcdDV)
// ALU read's A, unless it's a MOV to A
// This includes LDIHI/LDILO
||((~w_op[4])&&(w_op[3:0]!=4'hf))
// STO's read A
||((w_dcdM)&&(w_op[0]))
// Test/compares
||(w_op[4:1]== 4'h8);
// 1 LUTs -- do we read a register for operand B? Specifically, do
// we need to stall if the register is not (yet) ready?
assign w_rB = (w_mov)||((iword[18])&&(~w_ldi));
// 1 LUT: All but STO, NOOP/BREAK/LOCK, and CMP/TST write back to w_dcdR
assign w_wR_n = ((w_dcdM)&&(w_op[0]))
||((w_op[4:3]==2'b11)&&(w_dcdR[3:1]==3'h7))
||(w_cmptst);
assign w_wR = ~w_wR_n;
//
// 1-output bit (5 Opcode bits, 4 out-reg bits, 3 condition bits)
//
// This'd be 4 LUTs, save that we have the carve out for NOOPs
// and writes to the PC/CC register(s).
assign w_wF = (w_cmptst)
||((w_cond[3])&&((w_dcdFP)||(w_dcdDV)
||((w_ALU)&&(~w_mov)&&(~w_ldilo)&&(~w_brev)
&&(iword[30:28] != 3'h7))));
 
// Bottom 13 bits: no LUT's
// w_dcd[12: 0] -- no LUTs
// w_dcd[ 13] -- 2 LUTs
// w_dcd[17:14] -- (5+i0+i1) = 3 LUTs, 1 delay
// w_dcd[22:18] : 5 LUTs, 1 delay (assuming high bit is o/w determined)
reg [22:0] r_I;
wire [22:0] w_I, w_fullI;
wire w_Iz;
 
assign w_fullI = (w_ldi) ? { iword[22:0] } // LDI
:((w_mov) ?{ {(23-13){iword[12]}}, iword[12:0] } // Move
:((~iword[18]) ? { {(23-18){iword[17]}}, iword[17:0] }
: { {(23-14){iword[13]}}, iword[13:0] }
));
 
`ifdef OPT_VLIW
wire [5:0] w_halfI;
assign w_halfI = (w_ldi) ? iword[5:0]
:((iword[5]) ? 6'h00 : {iword[4],iword[4:0]});
assign w_I = (iword[31])? {{(23-6){w_halfI[5]}}, w_halfI }:w_fullI;
`else
assign w_I = w_fullI;
`endif
assign w_Iz = (w_I == 0);
 
 
`ifdef OPT_VLIW
//
// The o_phase parameter is special. It needs to let the software
// following know that it cannot break/interrupt on an o_phase asserted
// instruction, lest the break take place between the first and second
// half of a VLIW instruction. To do this, o_phase must be asserted
// when the first instruction half is valid, but not asserted on either
// a 32-bit instruction or the second half of a 2x16-bit instruction.
reg r_phase;
initial r_phase = 1'b0;
always @(posedge i_clk)
if ((i_rst) // When no instruction is in the pipe, phase is zero
||(o_early_branch)||(w_ljmp_dly))
r_phase <= 1'b0;
else if ((i_ce)&&(i_pf_valid))
r_phase <= (o_phase)? 1'b0:(i_instruction[31]);
// Phase is '1' on the first instruction of a two-part set
// But, due to the delay in processing, it's '1' when our output is
// valid for that first part, but that'll be the same time we
// are processing the second part ... so it may look to us like a '1'
// on the second half of processing.
 
assign o_phase = r_phase;
`else
assign o_phase = 1'b0;
`endif
 
 
initial o_illegal = 1'b0;
always @(posedge i_clk)
if (i_rst)
o_illegal <= 1'b0;
else if (i_ce)
begin
`ifdef OPT_VLIW
o_illegal <= (i_illegal);
`else
o_illegal <= ((i_illegal) || (i_instruction[31]));
`endif
if ((IMPLEMENT_MPY==0)&&((w_op[4:1]==4'h5)||(w_op[4:0]==5'h08)))
o_illegal <= 1'b1;
 
if ((IMPLEMENT_DIVIDE==0)&&(w_dcdDV))
o_illegal <= 1'b1;
else if ((IMPLEMENT_DIVIDE!=0)&&(w_dcdDV)&&(w_dcdR[3:1]==3'h7))
o_illegal <= 1'b1;
 
 
if ((IMPLEMENT_FPU!=0)&&(w_dcdFP)&&(w_dcdR[3:1]==3'h7))
o_illegal <= 1'b1;
else if ((IMPLEMENT_FPU==0)&&(w_dcdFP))
o_illegal <= 1'b1;
 
if ((w_op[4:3]==2'b11)&&(w_dcdR[3:1]==3'h7)
&&(
(w_op[2:0] != 3'h1) // BREAK
`ifdef OPT_PIPELINED
&&(w_op[2:0] != 3'h2) // LOCK
`endif
&&(w_op[2:0] != 3'h0))) // NOOP
o_illegal <= 1'b1;
end
 
 
always @(posedge i_clk)
if (i_ce)
begin
`ifdef OPT_VLIW
if (~o_phase)
begin
o_gie<= i_gie;
// i.e. dcd_pc+1
o_pc <= i_pc+{{(AW-1){1'b0}},1'b1};
end
`else
o_gie<= i_gie;
o_pc <= i_pc+{{(AW-1){1'b0}},1'b1};
`endif
 
// Under what condition will we execute this
// instruction? Only the load immediate instruction
// is completely unconditional.
o_cond <= w_cond;
// Don't change the flags on conditional instructions,
// UNLESS: the conditional instruction was a CMP
// or TST instruction.
o_wF <= w_wF;
 
// Record what operation/op-code (4-bits) we are doing
// Note that LDI magically becomes a MOV
// instruction here. That way it's a pass through
// the ALU. Likewise, the two compare instructions
// CMP and TST becomes SUB and AND here as well.
// We keep only the bottom four bits, since we've
// already done the rest of the decode necessary to
// settle between the other instructions. For example,
// o_FP plus these four bits uniquely defines the FP
// instruction, o_DV plus the bottom of these defines
// the divide, etc.
o_op <= (w_ldi)||(w_noop)? 4'hf:w_op[3:0];
 
// Default values
o_dcdR <= { w_dcdR_cc, w_dcdR_pc, w_dcdR};
o_dcdA <= { w_dcdA_cc, w_dcdA_pc, w_dcdA};
o_dcdB <= { w_dcdB_cc, w_dcdB_pc, w_dcdB};
o_wR <= w_wR;
o_rA <= w_rA;
o_rB <= w_rB;
r_I <= w_I;
o_zI <= w_Iz;
 
// Turn a NOOP into an ALU operation--subtract in
// particular, although it doesn't really matter as long
// as it doesn't take longer than one clock. Note
// also that this depends upon not setting any registers
// or flags, which should already be true.
o_ALU <= (w_ALU)||(w_ldi)||(w_cmptst)||(w_noop); // 2 LUT
o_M <= w_dcdM;
o_DV <= w_dcdDV;
o_FP <= w_dcdFP;
o_break <= (w_op[4:0]==5'b11001)&&(
((IMPLEMENT_FPU>0)&&(w_dcdR[3:1]==3'h7))
||(IMPLEMENT_FPU==0));
`ifdef OPT_PIPELINED
r_lock <= (w_op[4:0]==5'b11010)&&(
((IMPLEMENT_FPU>0)&&(w_dcdR[3:1]==3'h7))
||(IMPLEMENT_FPU==0));
`endif
`ifdef OPT_VLIW
r_nxt_half <= { iword[31], iword[13:5],
((iword[21])? iword[20:19] : 2'h0),
iword[4:0] };
`endif
end
 
`ifdef OPT_PIPELINED
assign o_lock = r_lock;
`else
assign o_lock = 1'b0;
`endif
 
generate
if (EARLY_BRANCHING!=0)
begin
reg r_early_branch, r_ljmp;
reg [(AW-1):0] r_branch_pc;
 
initial r_ljmp = 1'b0;
always @(posedge i_clk)
if (i_rst)
r_ljmp <= 1'b0;
else if ((i_ce)&&(i_pf_valid))
r_ljmp <= (w_ljmp);
assign o_ljmp = r_ljmp;
 
always @(posedge i_clk)
if (i_rst)
r_early_branch <= 1'b0;
else if ((i_ce)&&(i_pf_valid))
begin
if (r_ljmp)
// LOD (PC),PC
r_early_branch <= 1'b1;
else if ((~iword[31])&&(iword[30:27]==`CPU_PC_REG)&&(w_cond[3]))
begin
if (w_op[4:1] == 4'hb) // LDI to PC
// LDI x,PC
r_early_branch <= 1'b1;
else if ((w_op[4:0]==5'h02)&&(~iword[18]))
// Add x,PC
r_early_branch <= 1'b1;
else begin
r_early_branch <= 1'b0;
end
end else
r_early_branch <= 1'b0;
end else if (i_ce)
r_early_branch <= 1'b0;
 
always @(posedge i_clk)
if (i_ce)
begin
if (r_ljmp)
r_branch_pc <= iword[(AW-1):0];
else if (w_op[4:1] == 4'hb) // LDI
r_branch_pc <= {{(AW-23){iword[22]}},iword[22:0]};
else // Add x,PC
r_branch_pc <= i_pc
+ {{(AW-17){iword[17]}},iword[16:0]}
+ {{(AW-1){1'b0}},1'b1};
end
 
assign w_ljmp_dly = r_ljmp;
assign o_early_branch = r_early_branch;
assign o_branch_pc = r_branch_pc;
end else begin
assign w_ljmp_dly = 1'b0;
assign o_early_branch = 1'b0;
assign o_branch_pc = {(AW){1'b0}};
assign o_ljmp = 1'b0;
end endgenerate
 
 
// To be a pipeable operation there must be ...
// 1. Two valid adjacent instructions
// 2. Both must be memory operations, of the same time (both lods
// or both stos)
// 3. Both must use the same register base address
// 4. Both must be to the same address, or the address incremented
// by one
// Note that we're not using iword here ... there's a lot of logic
// taking place, and it's only valid if the new word is not compressed.
//
reg r_valid;
`ifdef OPT_PIPELINED_BUS_ACCESS
initial r_pipe = 1'b0;
always @(posedge i_clk)
if (i_ce)
r_pipe <= (r_valid)&&(i_pf_valid)&&(~i_instruction[31])
&&(w_dcdM)&&(o_M)&&(o_op[0] ==i_instruction[22])
&&(i_instruction[17:14] == o_dcdB[3:0])
&&(i_instruction[17:14] != o_dcdA[3:0])
&&(i_gie == o_gie)
&&((i_instruction[21:19]==o_cond[2:0])
||(o_cond[2:0] == 3'h0))
&&((i_instruction[13:0]==r_I[13:0])
||({1'b0, i_instruction[13:0]}==(r_I[13:0]+14'h1)));
assign o_pipe = r_pipe;
`else
assign o_pipe = 1'b0;
`endif
 
always @(posedge i_clk)
if (i_rst)
r_valid <= 1'b0;
else if ((i_ce)&&(o_ljmp))
r_valid <= 1'b0;
else if ((i_ce)&&(i_pf_valid))
r_valid <= 1'b1;
else if (~i_stalled)
r_valid <= 1'b0;
 
assign o_I = { {(32-22){r_I[22]}}, r_I[21:0] };
 
endmodule
/rtl/cpu/wbpriarbiter.v
0,0 → 1,117
///////////////////////////////////////////////////////////////////////////
//
// Filename: wbpriarbiter.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: This is a priority bus arbiter. It allows two separate wishbone
// masters to connect to the same bus, while also guaranteeing
// that one master can have the bus with no delay any time the
// other master is not using the bus. The goal is to eliminate
// the combinatorial logic required in the other wishbone
// arbiter, while still guarateeing access time for the priority
// channel.
//
// The core logic works like this:
//
// 1. When no one requests the bus, 'A' is granted the bus and
// guaranteed that any access will go right through.
// 2. If 'B' requests the bus (asserts cyc), and the bus is idle,
// then 'B' will be granted the bus.
// 3. Bus grants last as long as the 'cyc' line is high.
// 4. Once 'cyc' is dropped, the bus returns to 'A' as the owner.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
module wbpriarbiter(i_clk,
// Bus A
i_a_cyc, i_a_stb, i_a_we, i_a_adr, i_a_dat, o_a_ack, o_a_stall, o_a_err,
// Bus B
i_b_cyc, i_b_stb, i_b_we, i_b_adr, i_b_dat, o_b_ack, o_b_stall, o_b_err,
// Both buses
o_cyc, o_stb, o_we, o_adr, o_dat, i_ack, i_stall, i_err);
parameter DW=32, AW=32;
//
input i_clk;
// Bus A
input i_a_cyc, i_a_stb, i_a_we;
input [(AW-1):0] i_a_adr;
input [(DW-1):0] i_a_dat;
output wire o_a_ack, o_a_stall, o_a_err;
// Bus B
input i_b_cyc, i_b_stb, i_b_we;
input [(AW-1):0] i_b_adr;
input [(DW-1):0] i_b_dat;
output wire o_b_ack, o_b_stall, o_b_err;
//
output wire o_cyc, o_stb, o_we;
output wire [(AW-1):0] o_adr;
output wire [(DW-1):0] o_dat;
input i_ack, i_stall, i_err;
 
// Go high immediately (new cycle) if ...
// Previous cycle was low and *someone* is requesting a bus cycle
// Go low immadiately if ...
// We were just high and the owner no longer wants the bus
// WISHBONE Spec recommends no logic between a FF and the o_cyc
// This violates that spec. (Rec 3.15, p35)
assign o_cyc = (r_a_owner) ? i_a_cyc : i_b_cyc;
reg r_a_owner;
initial r_a_owner = 1'b1;
always @(posedge i_clk)
if (~i_b_cyc)
r_a_owner <= 1'b1;
else if ((i_b_cyc)&&(~i_a_cyc))
r_a_owner <= 1'b0;
 
 
// Realistically, if neither master owns the bus, the output is a
// don't care. Thus we trigger off whether or not 'A' owns the bus.
// If 'B' owns it all we care is that 'A' does not. Likewise, if
// neither owns the bus than the values on the various lines are
// irrelevant.
assign o_stb = (r_a_owner) ? i_a_stb : i_b_stb;
assign o_we = (r_a_owner) ? i_a_we : i_b_we;
assign o_adr = (r_a_owner) ? i_a_adr : i_b_adr;
assign o_dat = (r_a_owner) ? i_a_dat : i_b_dat;
 
// We cannot allow the return acknowledgement to ever go high if
// the master in question does not own the bus. Hence we force it
// low if the particular master doesn't own the bus.
assign o_a_ack = ( r_a_owner) ? i_ack : 1'b0;
assign o_b_ack = (~r_a_owner) ? i_ack : 1'b0;
 
// Stall must be asserted on the same cycle the input master asserts
// the bus, if the bus isn't granted to him.
assign o_a_stall = ( r_a_owner) ? i_stall : 1'b1;
assign o_b_stall = (~r_a_owner) ? i_stall : 1'b1;
 
//
//
assign o_a_err = ( r_a_owner) ? i_err : 1'b0;
assign o_b_err = (~r_a_owner) ? i_err : 1'b0;
 
endmodule
 
/rtl/cpu/wbdmac.v
0,0 → 1,471
////////////////////////////////////////////////////////////////////////////////
//
//
// Filename: wbdmac.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: Wishbone DMA controller
//
// This module is controllable via the wishbone, and moves values from
// one location in the wishbone address space to another. The amount of
// memory moved at any given time can be up to 4kB, or equivalently 1kW.
// Four registers control this DMA controller: a control/status register,
// a length register, a source WB address and a destination WB address.
// These register may be read at any time, but they may only be written
// to when the controller is idle.
//
// The meanings of three of the setup registers should be self explanatory:
// - The length register controls the total number of words to
// transfer.
// - The source address register controls where the DMA controller
// reads from. This address may or may not be incremented
// after each read, depending upon the setting in the
// control/status register.
// - The destination address register, which controls where the DMA
// controller writes to. This address may or may not be
// incremented after each write, also depending upon the
// setting in the control/status register.
//
// It is the control/status register, at local address zero, that needs
// more definition:
//
// Bits:
// 31 R Write protect If this is set to one, it means the
// write protect bit is set and the controller
// is therefore idle. This bit will be set upon
// completing any transfer.
// 30 R Error. The controller stopped mid-transfer
// after receiving a bus error.
// 29 R/W inc_s_n If set to one, the source address
// will not increment from one read to the next.
// 28 R/W inc_d_n If set to one, the destination address
// will not increment from one write to the next.
// 27 R Always 0
// 26..16 R nread Indicates how many words have been read,
// and not necessarily written (yet). This
// combined with the cfg_len parameter should tell
// exactly where the controller is at mid-transfer.
// 27..16 W WriteProtect When a 12'h3db is written to these
// bits, the write protect bit will be cleared.
//
// 15 R/W on_dev_trigger When set to '1', the controller will
// wait for an external interrupt before starting.
// 14..10 R/W device_id This determines which external interrupt
// will trigger a transfer.
// 9..0 R/W transfer_len How many bytes to transfer at one time.
// The minimum transfer length is one, while zero
// is mapped to a transfer length of 1kW.
//
//
// To use this, follow this checklist:
// 1. Wait for any prior DMA operation to complete
// (Read address 0, wait 'till either top bit is set or cfg_len==0)
// 2. Write values into length, source and destination address.
// (writei(3, &vals) should be sufficient for this.)
// 3. Enable the DMAC interrupt in whatever interrupt controller is present
// on the system.
// 4. Write the final start command to the setup/control/status register:
// Set inc_s_n, inc_d_n, on_dev_trigger, dev_trigger,
// appropriately for your task
// Write 12'h3db to the upper word.
// Set the lower word to either all zeros, or a smaller transfer
// length if desired.
// 5. wait() for the interrupt and the operation to complete.
// Prior to completion, number of items successfully transferred
// be read from the length register. If the internal buffer is
// being used, then you can read how much has been read into that
// buffer by reading from bits 25..16 of this control/status
// register.
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
//
`define DMA_IDLE 3'b000
`define DMA_WAIT 3'b001
`define DMA_READ_REQ 3'b010
`define DMA_READ_ACK 3'b011
`define DMA_PRE_WRITE 3'b100
`define DMA_WRITE_REQ 3'b101
`define DMA_WRITE_ACK 3'b110
 
module wbdmac(i_clk, i_rst,
i_swb_cyc, i_swb_stb, i_swb_we, i_swb_addr, i_swb_data,
o_swb_ack, o_swb_stall, o_swb_data,
o_mwb_cyc, o_mwb_stb, o_mwb_we, o_mwb_addr, o_mwb_data,
i_mwb_ack, i_mwb_stall, i_mwb_data, i_mwb_err,
i_dev_ints,
o_interrupt);
parameter ADDRESS_WIDTH=32, LGMEMLEN = 10,
DW=32, LGDV=5,AW=ADDRESS_WIDTH;
input i_clk, i_rst;
// Slave/control wishbone inputs
input i_swb_cyc, i_swb_stb, i_swb_we;
input [1:0] i_swb_addr;
input [(DW-1):0] i_swb_data;
// Slave/control wishbone outputs
output reg o_swb_ack;
output wire o_swb_stall;
output reg [(DW-1):0] o_swb_data;
// Master/DMA wishbone control
output wire o_mwb_cyc, o_mwb_stb, o_mwb_we;
output reg [(AW-1):0] o_mwb_addr;
output reg [(DW-1):0] o_mwb_data;
// Master/DMA wishbone responses from the bus
input i_mwb_ack, i_mwb_stall;
input [(DW-1):0] i_mwb_data;
input i_mwb_err;
// The interrupt device interrupt lines
input [(DW-1):0] i_dev_ints;
// An interrupt to be set upon completion
output reg o_interrupt;
// Need to release the bus for a higher priority user
// This logic had lots of problems, so it is being
// removed. If you want to make sure the bus is available
// for a higher priority user, adjust the transfer length
// accordingly.
//
// input i_other_busmaster_requests_bus;
//
 
 
reg [2:0] dma_state;
reg cfg_err, cfg_len_nonzero;
reg [(AW-1):0] cfg_waddr, cfg_raddr, cfg_len;
reg [(LGMEMLEN-1):0] cfg_blocklen_sub_one;
reg cfg_incs, cfg_incd;
reg [(LGDV-1):0] cfg_dev_trigger;
reg cfg_on_dev_trigger;
 
// Single block operations: We'll read, then write, up to a single
// memory block here.
 
reg [(DW-1):0] dma_mem [0:(((1<<LGMEMLEN))-1)];
reg [(LGMEMLEN):0] nread, nwritten, nwacks, nracks;
wire [(AW-1):0] bus_nracks;
assign bus_nracks = { {(AW-LGMEMLEN-1){1'b0}}, nracks };
 
reg last_read_request, last_read_ack,
last_write_request, last_write_ack;
reg trigger, abort;
 
initial dma_state = `DMA_IDLE;
initial o_interrupt = 1'b0;
initial cfg_len = {(AW){1'b0}};
initial cfg_blocklen_sub_one = {(LGMEMLEN){1'b1}};
initial cfg_on_dev_trigger = 1'b0;
initial cfg_len_nonzero = 1'b0;
always @(posedge i_clk)
case(dma_state)
`DMA_IDLE: begin
o_mwb_addr <= cfg_raddr;
nwritten <= 0;
nread <= 0;
nracks <= 0;
nwacks <= 0;
cfg_len_nonzero <= (|cfg_len);
 
// When the slave wishbone writes, and we are in this
// (ready) configuration, then allow the DMA to be controlled
// and thus to start.
if ((i_swb_cyc)&&(i_swb_stb)&&(i_swb_we))
begin
case(i_swb_addr)
2'b00: begin
if ((i_swb_data[27:16] == 12'hfed)
&&(cfg_len_nonzero))
dma_state <= `DMA_WAIT;
cfg_blocklen_sub_one
<= i_swb_data[(LGMEMLEN-1):0]
+ {(LGMEMLEN){1'b1}};
// i.e. -1;
cfg_dev_trigger <= i_swb_data[14:10];
cfg_on_dev_trigger <= i_swb_data[15];
cfg_incs <= ~i_swb_data[29];
cfg_incd <= ~i_swb_data[28];
end
2'b01: begin
cfg_len <= i_swb_data[(AW-1):0];
cfg_len_nonzero <= (|i_swb_data[(AW-1):0]);
end
2'b10: cfg_raddr <= i_swb_data[(AW-1):0];
2'b11: cfg_waddr <= i_swb_data[(AW-1):0];
endcase
end end
`DMA_WAIT: begin
o_mwb_addr <= cfg_raddr;
nracks <= 0;
nwacks <= 0;
nwritten <= 0;
nread <= 0;
if (abort)
dma_state <= `DMA_IDLE;
else if (trigger)
dma_state <= `DMA_READ_REQ;
end
`DMA_READ_REQ: begin
nwritten <= 0;
 
if (~i_mwb_stall)
begin
// Number of read acknowledgements needed
nracks <= nracks+1;
if (last_read_request)
//((nracks == {1'b0, cfg_blocklen_sub_one})||(bus_nracks == cfg_len-1))
// Wishbone interruptus
dma_state <= `DMA_READ_ACK;
if (cfg_incs)
o_mwb_addr <= o_mwb_addr
+ {{(AW-1){1'b0}},1'b1};
end
 
if (i_mwb_err)
begin
cfg_len <= 0;
dma_state <= `DMA_IDLE;
end
if (abort)
dma_state <= `DMA_IDLE;
if (i_mwb_ack)
begin
nread <= nread+1;
if (cfg_incs)
cfg_raddr <= cfg_raddr
+ {{(AW-1){1'b0}},1'b1};
end end
`DMA_READ_ACK: begin
nwritten <= 0;
 
if (i_mwb_err)
begin
cfg_len <= 0;
dma_state <= `DMA_IDLE;
end else if (i_mwb_ack)
begin
nread <= nread+1;
if (last_read_ack) // (nread+1 == nracks)
dma_state <= `DMA_PRE_WRITE;
if (cfg_incs)
cfg_raddr <= cfg_raddr
+ {{(AW-1){1'b0}},1'b1};
end
if (abort)
dma_state <= `DMA_IDLE;
end
`DMA_PRE_WRITE: begin
o_mwb_addr <= cfg_waddr;
dma_state <= (abort)?`DMA_IDLE:`DMA_WRITE_REQ;
end
`DMA_WRITE_REQ: begin
if (~i_mwb_stall)
begin
nwritten <= nwritten+1;
if (last_write_request) // (nwritten == nread-1)
// Wishbone interruptus
dma_state <= `DMA_WRITE_ACK;
if (cfg_incd)
begin
o_mwb_addr <= o_mwb_addr
+ {{(AW-1){1'b0}},1'b1};
cfg_waddr <= cfg_waddr
+ {{(AW-1){1'b0}},1'b1};
end
end
 
if (i_mwb_err)
begin
cfg_len <= 0;
dma_state <= `DMA_IDLE;
end
if (i_mwb_ack)
begin
nwacks <= nwacks+1;
cfg_len <= cfg_len +{(AW){1'b1}}; // -1
end
if (abort)
dma_state <= `DMA_IDLE;
end
`DMA_WRITE_ACK: begin
if (i_mwb_err)
begin
cfg_len <= 0;
nread <= 0;
dma_state <= `DMA_IDLE;
end else if (i_mwb_ack)
begin
nwacks <= nwacks+1;
cfg_len <= cfg_len +{(AW){1'b1}};//cfg_len -= 1;
if (last_write_ack) // (nwacks+1 == nwritten)
begin
nread <= 0;
dma_state <= (cfg_len == 1)?`DMA_IDLE:`DMA_WAIT;
end
end
 
if (abort)
dma_state <= `DMA_IDLE;
end
default:
dma_state <= `DMA_IDLE;
endcase
 
initial o_interrupt = 1'b0;
always @(posedge i_clk)
o_interrupt <= (dma_state == `DMA_WRITE_ACK)&&(i_mwb_ack)
&&(last_write_ack)
&&(cfg_len == {{(AW-1){1'b0}},1'b1});
 
initial cfg_err = 1'b0;
always @(posedge i_clk)
if (dma_state == `DMA_IDLE)
begin
if ((i_swb_cyc)&&(i_swb_stb)&&(i_swb_we)
&&(i_swb_addr==2'b00))
cfg_err <= 1'b0;
end else if (((i_mwb_err)&&(o_mwb_cyc))||(abort))
cfg_err <= 1'b1;
 
initial last_read_request = 1'b0;
always @(posedge i_clk)
if ((dma_state == `DMA_WAIT)||(dma_state == `DMA_READ_REQ))
begin
if ((~i_mwb_stall)&&(dma_state == `DMA_READ_REQ))
begin
last_read_request <=
(nracks + 1 == { 1'b0, cfg_blocklen_sub_one})
||(bus_nracks == cfg_len-2);
end else
last_read_request <=
(nracks== { 1'b0, cfg_blocklen_sub_one})
||(bus_nracks == cfg_len-1);
end else
last_read_request <= 1'b0;
 
initial last_read_ack = 1'b0;
always @(posedge i_clk)
if ((dma_state == `DMA_READ_REQ)||(dma_state == `DMA_READ_ACK))
begin
if (i_mwb_ack)
last_read_ack <= (nread+2 == nracks);
else
last_read_ack <= (nread+1 == nracks);
end else
last_read_ack <= 1'b0;
 
initial last_write_request = 1'b0;
always @(posedge i_clk)
if (dma_state == `DMA_PRE_WRITE)
last_write_request <= (nread <= 1);
else if (dma_state == `DMA_WRITE_REQ)
begin
if (i_mwb_stall)
last_write_request <= (nwritten >= nread-1);
else
last_write_request <= (nwritten >= nread-2);
end else
last_write_request <= 1'b0;
 
initial last_write_ack = 1'b0;
always @(posedge i_clk)
if((dma_state == `DMA_WRITE_REQ)||(dma_state == `DMA_WRITE_ACK))
begin
if (i_mwb_ack)
last_write_ack <= (nwacks+2 == nwritten);
else
last_write_ack <= (nwacks+1 == nwritten);
end else
last_write_ack <= 1'b0;
 
assign o_mwb_cyc = (dma_state == `DMA_READ_REQ)
||(dma_state == `DMA_READ_ACK)
||(dma_state == `DMA_WRITE_REQ)
||(dma_state == `DMA_WRITE_ACK);
 
assign o_mwb_stb = (dma_state == `DMA_READ_REQ)
||(dma_state == `DMA_WRITE_REQ);
 
assign o_mwb_we = (dma_state == `DMA_PRE_WRITE)
||(dma_state == `DMA_WRITE_REQ)
||(dma_state == `DMA_WRITE_ACK);
 
//
// This is tricky. In order for Vivado to consider dma_mem to be a
// proper memory, it must have a simple address fed into it. Hence
// the read_address (rdaddr) register. The problem is that this
// register must always be one greater than the address we actually
// want to read from, unless we are idling. So ... the math is touchy.
//
reg [(LGMEMLEN-1):0] rdaddr;
always @(posedge i_clk)
if((dma_state == `DMA_IDLE)||(dma_state == `DMA_WAIT)
||(dma_state == `DMA_WRITE_ACK))
rdaddr <= 0;
else if ((dma_state == `DMA_PRE_WRITE)
||((dma_state==`DMA_WRITE_REQ)&&(~i_mwb_stall)))
rdaddr <= rdaddr + {{(LGMEMLEN-1){1'b0}},1'b1};
always @(posedge i_clk)
if ((dma_state != `DMA_WRITE_REQ)||(~i_mwb_stall))
o_mwb_data <= dma_mem[rdaddr];
always @(posedge i_clk)
if((dma_state == `DMA_READ_REQ)||(dma_state == `DMA_READ_ACK))
dma_mem[nread[(LGMEMLEN-1):0]] <= i_mwb_data;
 
always @(posedge i_clk)
casez(i_swb_addr)
2'b00: o_swb_data <= { (dma_state != `DMA_IDLE), cfg_err,
~cfg_incs, ~cfg_incd,
1'b0, nread,
cfg_on_dev_trigger, cfg_dev_trigger,
cfg_blocklen_sub_one
};
2'b01: o_swb_data <= { {(DW-AW){1'b0}}, cfg_len };
2'b10: o_swb_data <= { {(DW-AW){1'b0}}, cfg_raddr};
2'b11: o_swb_data <= { {(DW-AW){1'b0}}, cfg_waddr};
endcase
 
// This causes us to wait a minimum of two clocks before starting: One
// to go into the wait state, and then one while in the wait state to
// develop the trigger.
initial trigger = 1'b0;
always @(posedge i_clk)
trigger <= (dma_state == `DMA_WAIT)
&&((~cfg_on_dev_trigger)
||(i_dev_ints[cfg_dev_trigger]));
 
// Ack any access. We'll quietly ignore any access where we are busy,
// but ack it anyway. In other words, before writing to the device,
// double check that it isn't busy, and then write.
always @(posedge i_clk)
o_swb_ack <= (i_swb_cyc)&&(i_swb_stb);
 
assign o_swb_stall = 1'b0;
 
initial abort = 1'b0;
always @(posedge i_clk)
abort <= (i_rst)||((i_swb_cyc)&&(i_swb_stb)&&(i_swb_we)
&&(i_swb_addr == 2'b00)
&&(i_swb_data == 32'hffed0000));
 
endmodule
 
/rtl/cpu/memops.v
0,0 → 1,150
///////////////////////////////////////////////////////////////////////////
//
// Filename: memops.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: A memory unit to support a CPU.
//
// In the interests of code simplicity, this memory operator is
// susceptible to unknown results should a new command be sent to it
// before it completes the last one. Unpredictable results might then
// occurr.
//
// 20150919 -- Added support for handling BUS ERR's (i.e., the WB
// error signal).
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
module memops(i_clk, i_rst, i_stb, i_lock,
i_op, i_addr, i_data, i_oreg,
o_busy, o_valid, o_err, o_wreg, o_result,
o_wb_cyc_gbl, o_wb_cyc_lcl,
o_wb_stb_gbl, o_wb_stb_lcl,
o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_err, i_wb_data);
parameter ADDRESS_WIDTH=24, IMPLEMENT_LOCK=0, AW=ADDRESS_WIDTH;
input i_clk, i_rst;
input i_stb, i_lock;
// CPU interface
input i_op;
input [31:0] i_addr;
input [31:0] i_data;
input [4:0] i_oreg;
// CPU outputs
output wire o_busy;
output reg o_valid;
output reg o_err;
output reg [4:0] o_wreg;
output reg [31:0] o_result;
// Wishbone outputs
output wire o_wb_cyc_gbl;
output reg o_wb_stb_gbl;
output wire o_wb_cyc_lcl;
output reg o_wb_stb_lcl;
output reg o_wb_we;
output reg [(AW-1):0] o_wb_addr;
output reg [31:0] o_wb_data;
// Wishbone inputs
input i_wb_ack, i_wb_stall, i_wb_err;
input [31:0] i_wb_data;
 
reg r_wb_cyc_gbl, r_wb_cyc_lcl;
wire gbl_stb, lcl_stb;
assign lcl_stb = (i_stb)&&(i_addr[31:8]==24'hc00000)&&(i_addr[7:5]==3'h0);
assign gbl_stb = (i_stb)&&((i_addr[31:8]!=24'hc00000)||(i_addr[7:5]!=3'h0));
 
initial r_wb_cyc_gbl = 1'b0;
initial r_wb_cyc_lcl = 1'b0;
always @(posedge i_clk)
if (i_rst)
begin
r_wb_cyc_gbl <= 1'b0;
r_wb_cyc_lcl <= 1'b0;
end else if ((r_wb_cyc_gbl)||(r_wb_cyc_lcl))
begin
if ((i_wb_ack)||(i_wb_err))
begin
r_wb_cyc_gbl <= 1'b0;
r_wb_cyc_lcl <= 1'b0;
end
end else if (i_stb) // New memory operation
begin // Grab the wishbone
r_wb_cyc_lcl <= lcl_stb;
r_wb_cyc_gbl <= gbl_stb;
end
always @(posedge i_clk)
if (o_wb_cyc_gbl)
o_wb_stb_gbl <= (o_wb_stb_gbl)&&(i_wb_stall);
else
o_wb_stb_gbl <= gbl_stb; // Grab wishbone on new operation
always @(posedge i_clk)
if (o_wb_cyc_lcl)
o_wb_stb_lcl <= (o_wb_stb_lcl)&&(i_wb_stall);
else
o_wb_stb_lcl <= lcl_stb; // Grab wishbone on new operation
always @(posedge i_clk)
if (i_stb)
begin
o_wb_we <= i_op;
o_wb_data <= i_data;
o_wb_addr <= i_addr[(AW-1):0];
end
 
initial o_valid = 1'b0;
always @(posedge i_clk)
o_valid <= ((o_wb_cyc_gbl)||(o_wb_cyc_lcl))&&(i_wb_ack)&&(~o_wb_we);
initial o_err = 1'b0;
always @(posedge i_clk)
o_err <= ((o_wb_cyc_gbl)||(o_wb_cyc_lcl))&&(i_wb_err);
assign o_busy = (o_wb_cyc_gbl)||(o_wb_cyc_lcl);
 
always @(posedge i_clk)
if (i_stb)
o_wreg <= i_oreg;
always @(posedge i_clk)
if (i_wb_ack)
o_result <= i_wb_data;
 
generate
if (IMPLEMENT_LOCK != 0)
begin
reg lock_gbl, lock_lcl;
 
initial lock_gbl = 1'b0;
initial lock_lcl = 1'b0;
 
always @(posedge i_clk)
begin
lock_gbl <= (i_lock)&&((r_wb_cyc_gbl)||(lock_gbl));
lock_lcl <= (i_lock)&&((r_wb_cyc_lcl)||(lock_lcl));
end
 
assign o_wb_cyc_gbl = (r_wb_cyc_gbl)||(lock_gbl);
assign o_wb_cyc_lcl = (r_wb_cyc_lcl)||(lock_lcl);
end else begin
assign o_wb_cyc_gbl = (r_wb_cyc_gbl);
assign o_wb_cyc_lcl = (r_wb_cyc_lcl);
end endgenerate
endmodule
/rtl/cpu/prefetch.v
0,0 → 1,124
////////////////////////////////////////////////////////////////////////////////
//
// Filename: prefetch.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: This is a very simple instruction fetch approach. It gets
// one instruction at a time. Future versions should pipeline
// fetches and perhaps even cache results--this doesn't do that.
// It should, however, be simple enough to get things running.
//
// The interface is fascinating. The 'i_pc' input wire is just
// a suggestion of what to load. Other wires may be loaded
// instead. i_pc is what must be output, not necessarily input.
//
// 20150919 -- Added support for the WB error signal. When reading an
// instruction results in this signal being raised, the pipefetch
// module will set an illegal instruction flag to be returned to
// the CPU together with the instruction. Hence, the ZipCPU
// can trap on it if necessary.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
// Flash requires a minimum of 4 clocks per byte to read, so that would be
// 4*(4bytes/32bit word) = 16 clocks per word read---and that's in pipeline
// mode which this prefetch does not support. In non--pipelined mode, the
// flash will require (16+6+6)*2 = 56 clocks plus 16 clocks per word read,
// or 72 clocks to fetch one instruction.
module prefetch(i_clk, i_rst, i_ce, i_stalled_n, i_pc, i_aux,
o_i, o_pc, o_aux, o_valid, o_illegal,
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);
parameter ADDRESS_WIDTH=32, AUX_WIDTH = 1, AW=ADDRESS_WIDTH;
input i_clk, i_rst, i_ce, i_stalled_n;
input [(AW-1):0] i_pc;
input [(AUX_WIDTH-1):0] i_aux;
output reg [31:0] o_i;
output reg [(AW-1):0] o_pc;
output reg [(AUX_WIDTH-1):0] o_aux;
output reg o_valid, o_illegal;
// Wishbone outputs
output reg o_wb_cyc, o_wb_stb;
output wire o_wb_we;
output reg [(AW-1):0] o_wb_addr;
output wire [31:0] o_wb_data;
// And return inputs
input i_wb_ack, i_wb_stall, i_wb_err;
input [31:0] i_wb_data;
 
assign o_wb_we = 1'b0;
assign o_wb_data = 32'h0000;
 
// Let's build it simple and upgrade later: For each instruction
// we do one bus cycle to get the instruction. Later we should
// pipeline this, but for now let's just do one at a time.
initial o_wb_cyc = 1'b0;
initial o_wb_stb = 1'b0;
initial o_wb_addr= 0;
always @(posedge i_clk)
if ((i_rst)||(i_wb_ack))
begin
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
end else if ((i_ce)&&(~o_wb_cyc)) // Initiate a bus cycle
begin
o_wb_cyc <= 1'b1;
o_wb_stb <= 1'b1;
end else if (o_wb_cyc) // Independent of ce
begin
if ((o_wb_cyc)&&(o_wb_stb)&&(~i_wb_stall))
o_wb_stb <= 1'b0;
if (i_wb_ack)
o_wb_cyc <= 1'b0;
end
 
always @(posedge i_clk)
if (i_rst) // Set the address to guarantee the result is invalid
o_wb_addr <= {(AW){1'b1}};
else if ((i_ce)&&(~o_wb_cyc))
o_wb_addr <= i_pc;
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
o_aux <= i_aux;
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
o_i <= i_wb_data;
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
o_pc <= o_wb_addr;
initial o_valid = 1'b0;
initial o_illegal = 1'b0;
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
begin
o_valid <= (i_pc == o_wb_addr)&&(~i_wb_err);
o_illegal <= i_wb_err;
end else if (i_stalled_n)
begin
o_valid <= 1'b0;
o_illegal <= 1'b0;
end
 
endmodule
/rtl/cpu/zipcounter.v
0,0 → 1,78
///////////////////////////////////////////////////////////////////////////
//
// Filename: zipcounter.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose:
// A very, _very_ simple counter. It's purpose doesn't really
// include rollover, but it will interrupt on rollover. It can be set,
// although my design concept is that it can be reset. It cannot be
// halted. It will always produce interrupts--whether or not they are
// handled interrupts is another question--that's up to the interrupt
// controller.
//
// My intention is to use this counter for process accounting: I should
// be able to use this to count clock ticks of processor time assigned to
// each task by resetting the counter at the beginning of every task
// interval, and reading the result at the end of the interval. As long
// as the interval is less than 2^32 clocks, there should be no problem.
// Similarly, this can be used to measure CPU wishbone bus stalls,
// prefetch stalls, or other CPU stalls (i.e. stalling as part of a JMP
// instruction, or a read from the condition codes following a write).
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
module zipcounter(i_clk, i_ce,
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_data,
o_wb_ack, o_wb_stall, o_wb_data,
o_int);
parameter BW = 32;
input i_clk, i_ce;
// Wishbone inputs
input i_wb_cyc, i_wb_stb, i_wb_we;
input [(BW-1):0] i_wb_data;
// Wishbone outputs
output reg o_wb_ack;
output wire o_wb_stall;
output reg [(BW-1):0] o_wb_data;
// Interrupt line
output reg o_int;
 
initial o_int = 0;
initial o_wb_data = 32'h00;
always @(posedge i_clk)
if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we))
{ o_int, o_wb_data } <= { 1'b0, i_wb_data };
else if (i_ce)
{ o_int, o_wb_data } <= o_wb_data+{{(BW-1){1'b0}},1'b1};
else
o_int <= 1'b0;
 
initial o_wb_ack = 1'b0;
always @(posedge i_clk)
o_wb_ack <= (i_wb_cyc)&&(i_wb_stb);
assign o_wb_stall = 1'b0;
endmodule
/rtl/cpu/zipjiffies.v
0,0 → 1,144
////////////////////////////////////////////////////////////////////////////////
//
// Filename: zipjiffies.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: This peripheral is motivated by the Linux use of 'jiffies'.
// A process, in Linux, can request to be put to sleep until a certain
// number of 'jiffies' have elapsed. Using this interface, the CPU can
// read the number of 'jiffies' from this peripheral (it only has the
// one location in address space), add the sleep length to it, and
// write the result back to the peripheral. The zipjiffies peripheral
// will record the value written to it only if it is nearer the current
// counter value than the last current waiting interrupt time. If no
// other interrupts are waiting, and this time is in the future, it will
// be enabled. (There is currrently no way to disable a jiffie interrupt
// once set.) The processor may then place this sleep request into a
// list among other sleep requests. Once the timer expires, it would
// write the next jiffy request to the peripheral and wake up the process
// whose timer had expired.
//
// Quite elementary, really.
//
// Interface:
// This peripheral contains one register: a counter. Reads from the
// register return the current value of the counter. Writes within
// the (N-1) bit space following the current time set an interrupt.
// Writes of values that occurred in the last 2^(N-1) ticks will be
// ignored. The timer then interrupts when it's value equals that time.
// Multiple writes cause the jiffies timer to select the nearest possible
// interrupt. Upon an interrupt, the next interrupt time/value is cleared
// and will need to be reset if the CPU wants to get notified again. With
// only the single interface, there is no way of knowing when the next
// interrupt is scheduled for, neither is there any way to slow down the
// interrupt timer in case you don't want it overflowing as often and you
// wish to wait more jiffies than it supports. Thus, currently, if you
// have a timer you wish to wait upon that is more than 2^31 into the
// future, you would need to set timers along the way, wake up on those
// timers, and set further timer's until you finally get to your
// destination.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
module zipjiffies(i_clk, i_ce,
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_data,
o_wb_ack, o_wb_stall, o_wb_data,
o_int);
parameter BW = 32;
input i_clk, i_ce;
// Wishbone inputs
input i_wb_cyc, i_wb_stb, i_wb_we;
input [(BW-1):0] i_wb_data;
// Wishbone outputs
output reg o_wb_ack;
output wire o_wb_stall;
output wire [(BW-1):0] o_wb_data;
// Interrupt line
output reg o_int;
 
//
// Our counter logic: The counter is always counting up--it cannot
// be stopped or altered. It's really quite simple. Okay, not quite.
// We still support the clock enable line. We do this in order to
// support debugging, so that if we get everything running inside a
// debugger, the timer's all slow down so that everything can be stepped
// together, one clock at a time.
//
reg [(BW-1):0] r_counter;
always @(posedge i_clk)
if (i_ce)
r_counter <= r_counter+1;
 
//
// Writes to the counter set an interrupt--but only if they are in the
// future as determined by the signed result of an unsigned subtract.
//
reg int_set, new_set;
reg [(BW-1):0] int_when, new_when;
wire signed [(BW-1):0] till_when, till_wb;
assign till_when = int_when-r_counter;
assign till_wb = new_when-r_counter;
 
initial new_set = 1'b0;
always @(posedge i_clk)
begin
// Delay things by a clock to simplify our logic
new_set <= ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we));
// new_when is a don't care when new_set = 0, so don't worry
// about setting it at all times.
new_when<= i_wb_data;
end
 
initial o_int = 1'b0;
initial int_set = 1'b0;
always @(posedge i_clk)
begin
o_int <= 1'b0;
if ((i_ce)&&(int_set)&&(r_counter == int_when))
// Interrupts are self-clearing
o_int <= 1'b1; // Set the interrupt flag for one clock
else if ((new_set)&&(till_wb <= 0))
o_int <= 1'b1;
 
if ((new_set)&&(till_wb > 0))
int_set <= 1'b1;
else if ((i_ce)&&(r_counter == int_when))
int_set <= 1'b0;
 
if ((new_set)&&(till_wb > 0)&&((till_wb<till_when)||(~int_set)))
int_when <= new_when;
end
 
//
// Acknowledge any wishbone accesses -- everything we did took only
// one clock anyway.
//
always @(posedge i_clk)
o_wb_ack <= (i_wb_cyc)&&(i_wb_stb);
 
assign o_wb_data = r_counter;
assign o_wb_stall = 1'b0;
endmodule
/rtl/cpu/ziptimer.v
0,0 → 1,158
///////////////////////////////////////////////////////////////////////////
//
// Filename: ziptimer.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: A lighter weight implementation of the Zip Timer.
//
// Interface:
// Two options:
// 1. One combined register for both control and value, and ...
// The reload value is set any time the timer data value is "set".
// Reading the register returns the timer value. Controls are
// set so that writing a value to the timer automatically starts
// it counting down.
// 2. Two registers, one for control one for value.
// The control register would have the reload value in it.
// On the clock when the interface is set to zero the interrupt is set.
// Hence setting the timer to zero will disable the timer without
// setting any interrupts. Thus setting it to five will count
// 5 clocks: 5, 4, 3, 2, 1, Interrupt.
//
//
// Control bits:
// (Start_n/Stop. This bit has been dropped. Writing to this
// timer any value but zero starts it. Writing a zero
// clears and stops it.)
// AutoReload. If set, then on reset the timer automatically
// loads the last set value and starts over. This is
// useful for distinguishing between a one-time interrupt
// timer, and a repetitive interval timer.
// (INTEN. Interrupt enable--reaching zero always creates an
// interrupt, so this control bit isn't needed. The
// interrupt controller can be used to mask the interrupt.)
// (COUNT-DOWN/UP: This timer is *only* a count-down timer.
// There is no means of setting it to count up.)
// WatchDog
// This timer can be implemented as a watchdog timer simply by
// connecting the interrupt line to the reset line of the CPU.
// When the timer then expires, it will trigger a CPU reset.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
module ziptimer(i_clk, i_rst, i_ce,
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_data,
o_wb_ack, o_wb_stall, o_wb_data,
o_int);
parameter BW = 32, VW = (BW-1), RELOADABLE=1;
input i_clk, i_rst, i_ce;
// Wishbone inputs
input i_wb_cyc, i_wb_stb, i_wb_we;
input [(BW-1):0] i_wb_data;
// Wishbone outputs
output reg o_wb_ack;
output wire o_wb_stall;
output wire [(BW-1):0] o_wb_data;
// Interrupt line
output reg o_int;
 
reg r_running;
 
wire wb_write;
assign wb_write = ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we));
 
wire auto_reload;
wire [(VW-1):0] reload_value;
 
initial r_running = 1'b0;
always @(posedge i_clk)
if (i_rst)
r_running <= 1'b0;
else if (wb_write)
r_running <= (|i_wb_data[(VW-1):0]);
else if ((o_int)&&(~auto_reload))
r_running <= 1'b0;
 
generate
if (RELOADABLE != 0)
begin
reg r_auto_reload;
reg [(VW-1):0] r_reload_value;
 
initial r_auto_reload = 1'b0;
 
always @(posedge i_clk)
if (wb_write)
r_auto_reload <= (i_wb_data[(BW-1)]);
 
assign auto_reload = r_auto_reload;
 
// If setting auto-reload mode, and the value to other
// than zero, set the auto-reload value
always @(posedge i_clk)
if ((wb_write)&&(i_wb_data[(BW-1)])&&(|i_wb_data[(VW-1):0]))
r_reload_value <= i_wb_data[(VW-1):0];
assign reload_value = r_reload_value;
end else begin
assign auto_reload = 1'b0;
assign reload_value = 0;
end endgenerate
 
 
reg [(VW-1):0] r_value;
initial r_value = 0;
always @(posedge i_clk)
if (wb_write)
r_value <= i_wb_data[(VW-1):0];
else if ((r_running)&&(i_ce)&&(~o_int))
r_value <= r_value + {(VW){1'b1}}; // r_value - 1;
else if ((r_running)&&(auto_reload)&&(o_int))
r_value <= reload_value;
 
// Set the interrupt on our last tick, as we transition from one to
// zero.
initial o_int = 1'b0;
always @(posedge i_clk)
if (i_rst)
o_int <= 1'b0;
else if (i_ce)
o_int <= (r_running)&&(r_value == { {(VW-1){1'b0}}, 1'b1 });
else
o_int <= 1'b0;
 
initial o_wb_ack = 1'b0;
always @(posedge i_clk)
o_wb_ack <= (i_wb_cyc)&&(i_wb_stb);
assign o_wb_stall = 1'b0;
 
generate
if (VW < BW-1)
assign o_wb_data = { auto_reload, {(BW-1-VW){1'b0}}, r_value };
else
assign o_wb_data = { auto_reload, r_value };
endgenerate
 
endmodule
/rtl/cpu/zipcpuhs.v
0,0 → 1,1614
///////////////////////////////////////////////////////////////////////////////
//
// Filename: zipcpu.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: This is the top level module holding the core of the Zip CPU
// together. The Zip CPU is designed to be as simple as possible.
// (actual implementation aside ...) The instruction set is about as
// RISC as you can get, there are only 16 instruction types supported.
// Please see the accompanying spec.pdf file for a description of these
// instructions.
//
// All instructions are 32-bits wide. All bus accesses, both address and
// data, are 32-bits over a wishbone bus.
//
// The Zip CPU is fully pipelined with the following pipeline stages:
//
// 1. Prefetch, returns the instruction from memory.
//
// 2. Instruction Decode
//
// 3. Read Operands
//
// 4. Apply Instruction
//
// 4. Write-back Results
//
// Further information about the inner workings of this CPU may be
// found in the spec.pdf file. (The documentation within this file
// had become out of date and out of sync with the spec.pdf, so look
// to the spec.pdf for accurate and up to date information.)
//
//
// In general, the pipelining is controlled by three pieces of logic
// per stage: _ce, _stall, and _valid. _valid means that the stage
// holds a valid instruction. _ce means that the instruction from the
// previous stage is to move into this one, and _stall means that the
// instruction from the previous stage may not move into this one.
// The difference between these control signals allows individual stages
// to propagate instructions independently. In general, the logic works
// as:
//
//
// assign (n)_ce = (n-1)_valid && (~(n)_stall)
//
//
// always @(posedge i_clk)
// if ((i_rst)||(clear_pipeline))
// (n)_valid = 0
// else if (n)_ce
// (n)_valid = 1
// else if (n+1)_ce
// (n)_valid = 0
//
// assign (n)_stall = ( (n-1)_valid && ( pipeline hazard detection ) )
// || ( (n)_valid && (n+1)_stall );
//
// and ...
//
// always @(posedge i_clk)
// if (n)_ce
// (n)_variable = ... whatever logic for this stage
//
// Note that a stage can stall even if no instruction is loaded into
// it.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////////
//
// We can either pipeline our fetches, or issue one fetch at a time. Pipelined
// fetches are more complicated and therefore use more FPGA resources, while
// single fetches will cause the CPU to stall for about 5 stalls each
// instruction cycle, effectively reducing the instruction count per clock to
// about 0.2. However, the area cost may be worth it. Consider:
//
// Slice LUTs ZipSystem ZipCPU
// Single Fetching 2521 1734
// Pipelined fetching 2796 2046
//
//
//
`define CPU_CC_REG 4'he
`define CPU_PC_REG 4'hf
`define CPU_CLRCACHE_BIT 14 // Floating point error flag, set on error
`define CPU_PHASE_BIT 13 // Floating point error flag, set on error
`define CPU_FPUERR_BIT 12 // Floating point error flag, set on error
`define CPU_DIVERR_BIT 11 // Divide error flag, set on divide by zero
`define CPU_BUSERR_BIT 10 // Bus error flag, set on error
`define CPU_TRAP_BIT 9 // User TRAP has taken place
`define CPU_ILL_BIT 8 // Illegal instruction
`define CPU_BREAK_BIT 7
`define CPU_STEP_BIT 6 // Will step one or two (VLIW) instructions
`define CPU_GIE_BIT 5
`define CPU_SLEEP_BIT 4
// Compile time defines
//
`include "cpudefs.v"
//
//
module zipcpuhs(i_clk, i_rst, i_interrupt,
// Debug interface
i_halt, i_clear_pf_cache, i_dbg_reg, i_dbg_we, i_dbg_data,
o_dbg_stall, o_dbg_reg, o_dbg_cc,
o_break,
// CPU interface to the wishbone bus
o_wb_gbl_cyc, o_wb_gbl_stb,
o_wb_lcl_cyc, o_wb_lcl_stb,
o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_data,
i_wb_err,
// Accounting/CPU usage interface
o_op_stall, o_pf_stall, o_i_count
`ifdef DEBUG_SCOPE
, o_debug
`endif
);
parameter RESET_ADDRESS=32'h0100000, ADDRESS_WIDTH=24,
LGICACHE=6;
`ifdef OPT_MULTIPLY
parameter IMPLEMENT_MPY = `OPT_MULTIPLY;
`else
parameter IMPLEMENT_MPY = 0;
`endif
`ifdef OPT_DIVIDE
parameter IMPLEMENT_DIVIDE = 1;
`else
parameter IMPLEMENT_DIVIDE = 0;
`endif
`ifdef OPT_IMPLEMENT_FPU
parameter IMPLEMENT_FPU = 1,
`else
parameter IMPLEMENT_FPU = 0,
`endif
IMPLEMENT_LOCK=1;
`ifdef OPT_EARLY_BRANCHING
parameter EARLY_BRANCHING = 1;
`else
parameter EARLY_BRANCHING = 0;
`endif
parameter AW=ADDRESS_WIDTH;
input i_clk, i_rst, i_interrupt;
// Debug interface -- inputs
input i_halt, i_clear_pf_cache;
input [4:0] i_dbg_reg;
input i_dbg_we;
input [31:0] i_dbg_data;
// Debug interface -- outputs
output wire o_dbg_stall;
output reg [31:0] o_dbg_reg;
output reg [3:0] o_dbg_cc;
output wire o_break;
// Wishbone interface -- outputs
output wire o_wb_gbl_cyc, o_wb_gbl_stb;
output wire o_wb_lcl_cyc, o_wb_lcl_stb, o_wb_we;
output wire [(AW-1):0] o_wb_addr;
output wire [31:0] o_wb_data;
// Wishbone interface -- inputs
input i_wb_ack, i_wb_stall;
input [31:0] i_wb_data;
input i_wb_err;
// Accounting outputs ... to help us count stalls and usage
output wire o_op_stall;
output wire o_pf_stall;
output wire o_i_count;
//
`ifdef DEBUG_SCOPE
output reg [31:0] o_debug;
`endif
 
 
// Registers
//
// The distributed RAM style comment is necessary on the
// SPARTAN6 with XST to prevent XST from oversimplifying the register
// set and in the process ruining everything else. It basically
// optimizes logic away, to where it no longer works. The logic
// as described herein will work, this just makes sure XST implements
// that logic.
//
(* ram_style = "distributed" *)
reg [31:0] regset [0:31];
 
// Condition codes
// (BUS, TRAP,ILL,BREAKEN,STEP,GIE,SLEEP ), V, N, C, Z
reg [3:0] flags, iflags;
wire [14:0] w_uflags, w_iflags;
reg trap, break_en, step, gie, sleep, r_halted,
break_pending;
wire w_clear_icache;
`ifdef OPT_ILLEGAL_INSTRUCTION
reg ill_err_u, ill_err_i;
`else
wire ill_err_u, ill_err_i;
`endif
reg ubreak;
reg ibus_err_flag, ubus_err_flag;
wire idiv_err_flag, udiv_err_flag;
wire ifpu_err_flag, ufpu_err_flag;
wire ihalt_phase, uhalt_phase;
 
// The master chip enable
wire master_ce;
 
//
//
// PIPELINE STAGE #1 :: Prefetch
// Variable declarations
//
reg [(AW-1):0] pf_pc;
reg new_pc;
wire clear_pipeline;
assign clear_pipeline = new_pc;
 
wire dcd_stalled;
wire pf_cyc, pf_stb, pf_we, pf_busy, pf_ack, pf_stall, pf_err;
wire [(AW-1):0] pf_addr;
wire [31:0] pf_data;
wire [31:0] instruction;
wire [(AW-1):0] instruction_pc;
wire pf_valid, instruction_gie, pf_illegal;
 
//
//
// PIPELINE STAGE #2 :: Instruction Decode
// Variable declarations
//
//
wire op_stall, dcd_ce, dcd_phase;
wire [3:0] dcdOp;
wire [4:0] dcd_iA, dcd_iB, dcd_iR;
wire dcdA_cc, dcdB_cc, dcdA_pc, dcdB_pc, dcdR_cc, dcdR_pc;
wire [3:0] dcdF;
wire dcd_wR, dcd_rA, dcd_rB,
dcdALU, dcdM, dcdDV, dcdFP,
dcdF_wr, dcd_gie, dcd_break, dcd_lock,
dcd_pipe, dcd_ljmp;
reg [1:0] r_dcdvalid;
wire dcd_valid;
wire [(AW-1):0] dcd_pc;
wire [31:0] dcd_I;
wire dcd_zI; // true if dcdI == 0
wire dcdA_stall, dcdB_stall, dcdF_stall;
 
wire dcd_illegal;
wire dcd_early_branch;
wire [(AW-1):0] dcd_branch_pc;
 
 
//
//
// PIPELINE STAGE #3a :: Read Operands
// Variable declarations
//
//
//
// Now, let's read our operands
reg opa_valid, opa_DV, opa_FP, opa_ALU, opa_M,
opa_rA, opa_rB;
reg [4:0] alu_reg;
reg [3:0] opa_opn;
reg [4:0] opa_R, opa_iA;
reg [31:0] r_opa_B;
reg [(AW-1):0] opa_pc;
wire [31:0] opA_nowait, opa_Bnowait, opa_A, opa_B, opa_I;
reg opa_wR, opa_ccR, opa_wF, opa_gie;
wire [13:0] opa_Fl;
reg [5:0] r_opa_F;
wire [7:0] opa_F;
wire opa_ce, opa_phase, opa_pipe;
// Some pipeline control wires
reg opa_A_alu, opa_A_mem;
reg opa_B_alu, opa_B_mem;
`ifdef OPT_ILLEGAL_INSTRUCTION
reg opa_illegal;
`else
wire opa_illegal;
assign opa_illegal = 1'b0;
`endif
reg opa_break;
reg opa_lock;
 
//
//
// PIPELINE STAGE #3b :: Read Operands
// Variable declarations
//
//
//
// Now, let's read our operands
reg [3:0] opb_opn;
reg opb_valid, opb_valid_mem, opb_valid_alu;
reg opb_valid_div, opb_valid_fpu;
reg [4:0] opb_R;
reg [31:0] r_opb_A, r_opb_B;
reg [(AW-1):0] opb_pc;
wire [31:0] opb_A_nowait, opb_B_nowait, opb_A, opb_B;
reg opb_wR, opb_ccR, opb_wF, opb_gie;
wire [13:0] opb_Fl;
reg [5:0] r_opb_F;
wire [7:0] opb_F;
wire opb_ce, opb_phase, opb_pipe;
// Some pipeline control wires
reg opb_A_alu, opb_A_mem;
reg opb_B_alu, opb_B_mem;
`ifdef OPT_ILLEGAL_INSTRUCTION
reg opb_illegal;
`else
wire opb_illegal;
assign opb_illegal = 1'b0;
`endif
reg opb_break;
reg opb_lock;
 
 
//
//
// PIPELINE STAGE #4 :: ALU / Memory / Divide
// Variable declarations
//
//
reg [(AW-1):0] alu_pc;
reg r_alu_pc_valid, mem_pc_valid;
wire alu_pc_valid;
wire alu_phase;
wire alu_ce, alu_stall;
wire [31:0] alu_result;
wire [3:0] alu_flags;
wire alu_valid, alu_busy;
wire set_cond;
reg alu_wr, alF_wr, alu_gie;
wire alu_illegal_op;
wire alu_illegal;
 
 
 
wire mem_ce, mem_stalled;
wire mem_pipe_stalled;
wire mem_valid, mem_ack, mem_stall, mem_err, bus_err,
mem_cyc_gbl, mem_cyc_lcl, mem_stb_gbl, mem_stb_lcl, mem_we;
wire [4:0] mem_wreg;
 
wire mem_busy, mem_rdbusy;
wire [(AW-1):0] mem_addr;
wire [31:0] mem_data, mem_result;
 
wire div_ce, div_error, div_busy, div_valid;
wire [31:0] div_result;
wire [3:0] div_flags;
 
assign div_ce = (master_ce)&&(~clear_pipeline)&&(opb_valid_div)
&&(~stage_busy)&&(set_cond);
 
wire fpu_ce, fpu_error, fpu_busy, fpu_valid;
wire [31:0] fpu_result;
wire [3:0] fpu_flags;
 
assign fpu_ce = (master_ce)&&(~clear_pipeline)&&(opb_valid_fpu)
&&(~stage_busy)&&(set_cond);
 
//
//
// PIPELINE STAGE #5 :: Write-back
// Variable declarations
//
wire wr_reg_ce, wr_flags_ce, wr_write_pc, wr_write_cc;
wire [4:0] wr_reg_id;
wire [31:0] wr_gpreg_vl, wr_spreg_vl;
wire w_switch_to_interrupt, w_release_from_interrupt;
reg [(AW-1):0] upc, ipc;
 
 
 
//
// MASTER: clock enable.
//
assign master_ce = (~i_halt)&&(~o_break)&&(~sleep);
 
 
//
// PIPELINE STAGE #1 :: Prefetch
// Calculate stall conditions
//
// These are calculated externally, within the prefetch module.
//
 
//
// PIPELINE STAGE #2 :: Instruction Decode
// Calculate stall conditions
assign dcd_ce = ((~dcd_valid)||(~dcd_stalled))&&(~clear_pipeline);
 
assign dcd_stalled = (dcd_valid)&&(op_stall);
//
// PIPELINE STAGE #3 :: Read Operands
// Calculate stall conditions
wire op_lock_stall;
assign op_stall = (opvalid)&&( // Only stall if we're loaded w/validins
// Stall if we're stopped, and not allowed to execute
// an instruction
// (~master_ce) // Already captured in alu_stall
//
// Stall if going into the ALU and the ALU is stalled
// i.e. if the memory is busy, or we are single
// stepping. This also includes our stalls for
// op_break and op_lock, so we don't need to
// include those as well here.
// This also includes whether or not the divide or
// floating point units are busy.
(alu_stall)
//
// Stall if we are going into memory with an operation
// that cannot be pipelined, and the memory is
// already busy
||(mem_stalled) // &&(opvalid_mem) part of mem_stalled
)
||(dcd_valid)&&(
// Stall if we need to wait for an operand A
// to be ready to read
(dcdA_stall)
// Likewise for B, also includes logic
// regarding immediate offset (register must
// be in register file if we need to add to
// an immediate)
||(dcdB_stall)
// Or if we need to wait on flags to work on the
// CC register
||(dcdF_stall)
);
assign opa_ce = ((dcd_valid)||(dcd_illegal))&&(~opa_stall);
 
//
// PIPELINE STAGE #4 :: ALU / Memory
// Calculate stall conditions
//
// 1. Basic stall is if the previous stage is valid and the next is
// busy.
// 2. Also stall if the prior stage is valid and the master clock enable
// is de-selected
// 3. Stall if someone on the other end is writing the CC register,
// since we don't know if it'll put us to sleep or not.
// 4. Last case: Stall if we would otherwise move a break instruction
// through the ALU. Break instructions are not allowed through
// the ALU.
assign alu_stall = (((~master_ce)||(mem_rdbusy)||(alu_busy))&&(opvalid_alu)) //Case 1&2
// Old case #3--this isn't an ALU stall though ...
||((opvalid_alu)&&(wr_reg_ce)&&(wr_reg_id[4] == op_gie)
&&(wr_write_cc)) // Case 3
||((opvalid)&&(op_lock)&&(op_lock_stall))
||((opvalid)&&(op_break))
||(div_busy)||(fpu_busy);
assign alu_ce = (master_ce)&&(stage_ce)&&(opvalid_alu)&&(~clear_pipeline);
assign stage_ce = (~div_busy)&&(~alu_busy)&&(~mem_rdbusy)&&(~fpu_busy);
//
 
//
// Note: if you change the conditions for mem_ce, you must also change
// alu_pc_valid.
//
assign mem_ce = (master_ce)&&(opvalid_mem)&&(~mem_stalled)
&&(~clear_pipeline);
assign mem_stalled = (~master_ce)||(alu_busy)||((opvalid_mem)&&(
(mem_pipe_stalled)
||((~op_pipe)&&(mem_busy))
||(div_busy)
||(fpu_busy)
// Stall waiting for flags to be valid
// Or waiting for a write to the PC register
// Or CC register, since that can change the
// PC as well
||((wr_reg_ce)&&(wr_reg_id[4] == op_gie)
&&((wr_write_pc)||(wr_write_cc)))));
 
 
//
//
// PIPELINE STAGE #1 :: Prefetch
//
//
fastcache #(LGICACHE, ADDRESS_WIDTH)
pf(i_clk, i_rst, (new_pc)||((dcd_early_branch)&&(~clear_pipeline)),
i_clear_pf_cache,
// dcd_pc,
~dcd_stalled,
((dcd_early_branch)&&(~clear_pipeline))
? dcd_branch_pc:pf_pc,
instruction, instruction_pc, pf_valid,
pf_cyc, pf_stb, pf_we, pf_addr, pf_data,
pf_ack, pf_stall, pf_err, i_wb_data,
pf_illegal);
assign instruction_gie = gie;
 
//
// The ifastdec decoder takes two clocks to decode an instruction.
// Therefore, to determine if a decoded instruction is valid, we
// need to wait two clocks from pf_valid. Hence, we dump this into
// a pipeline below.
//
initial r_dcdvalid = 2'b00;
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline)||(w_clear_icache))
r_dcdvalid <= 2'b00;
else if (dcd_ce)
r_dcdvalid <= { r_dcdvalid[0], pf_valid };
else if (opa_ce)
r_dcdvalid <= 1'b0;
assign dcd_valid = r_dcdvalid[1];
 
ifastdec #(AW, IMPLEMENT_MPY, EARLY_BRANCHING, IMPLEMENT_DIVIDE,
IMPLEMENT_FPU)
instruction_decoder(i_clk, (i_rst)||(clear_pipeline),
dcd_ce, dcd_stalled, instruction, instruction_gie,
instruction_pc, pf_valid, pf_illegal, dcd_phase,
dcd_illegal, dcd_pc, dcd_gie,
{ dcdR_cc, dcdR_pc, dcd_iR },
{ dcdA_cc, dcdA_pc, dcd_iA },
{ dcdB_cc, dcdB_pc, dcd_iB },
dcd_I, dcd_zI, dcdF, dcdF_wr, dcdOp,
dcdALU, dcdM, dcdDV, dcdFP, dcd_break, dcd_lock,
dcd_wR,dcd_rA, dcd_rB,
dcd_early_branch,
dcd_branch_pc, dcd_ljmp,
dcd_pipe);
 
reg r_op_pipe;
 
initial r_op_pipe = 1'b0;
// To be a pipeable operation, there must be
// two valid adjacent instructions
// Both must be memory instructions
// Both must be writes, or both must be reads
// Both operations must be to the same identical address,
// or at least a single (one) increment above that address
//
// However ... we need to know this before this clock, hence this is
// calculated in the instruction decoder.
always @(posedge i_clk)
if (op_ce)
r_op_pipe <= dcd_pipe;
else if (mem_ce) // Clear us any time an op_ is clocked in
r_op_pipe <= 1'b0;
assign op_pipe = r_op_pipe;
 
//
//
// PIPELINE STAGE #3 :: Read Operands (Registers)
//
//
assign w_opA = regset[dcd_iA];
assign w_opB = regset[dcd_iB];
 
wire [8:0] w_cpu_info;
assign w_cpu_info = {
`ifdef OPT_ILLEGAL_INSTRUCTION
1'b1,
`else
1'b0,
`endif
1'b1,
`ifdef OPT_DIVIDE
1'b1,
`else
1'b0,
`endif
`ifdef OPT_IMPLEMENT_FPU
1'b1,
`else
1'b0,
`endif
1'b1, 1'b1,
`ifdef OPT_EARLY_BRANCHING
1'b1,
`else
1'b0,
`endif
1'b1,
`ifdef OPT_VLIW
1'b1
`else
1'b0
`endif
};
 
wire [31:0] w_pcA_v;
generate
if (AW < 32)
assign w_pcA_v = {{(32-AW){1'b0}}, (dcd_iA[4] == dcd_gie)?dcd_pc:upc };
else
assign w_pcA_v = (dcd_iA[4] == dcd_gie)?dcd_pc:upc;
endgenerate
 
reg [4:0] opa_Aid, opa_Bid;
reg opa_Ard, opa_Brd;
always @(posedge i_clk)
if (opa_ce)
begin
opa_iA <= dcd_iA;
opa_iB <= dcd_iB;
opa_rA <= dcd_rA;
opa_rB <= dcd_rB;
end
 
always @(posedge i_clk)
if (opa_ce)
begin
if ((wr_reg_ce)&&(wr_reg_id == dcd_iA))
r_opA <= wr_gpreg_vl;
else if (dcdA_pc)
r_opA <= w_pcA_v;
else if (dcdA_cc)
r_opA <= { w_cpu_info, w_opA[22:15], (dcd_iA[4])?w_uflags:w_iflags };
else
r_opA <= w_opA;
end else if ((wr_reg_ce)&&(wr_reg_id == opa_iA)&&(opa_rA))
r_opA <= wr_gpreg_vl;
 
wire [31:0] w_opBnI, w_pcB_v;
generate
if (AW < 32)
assign w_pcB_v = {{(32-AW){1'b0}}, (dcdB[4] == dcd_gie)?dcd_pc:upc };
else
assign w_pcB_v = (dcdB[4] == dcd_gie)?dcd_pc:upc;
endgenerate
 
always @(posedge i_clk)
if (opa_ce)
begin
opa_B <= (~dcdB_rd) ? 32'h00
: (((wr_reg_ce)&&(wr_reg_id == dcdB)) ? wr_gpreg_vl
: ((dcdB_pc) ? w_pcB_v
: ((dcdB_cc) ? { w_cpu_info, w_opB[22:14], // w_opB[31:14],
(dcdB[4])?w_uflags:w_iflags}
: w_opB)));
opa_I <= dcd_I;
end
 
//
// B-Inflight
//
// We cannot read the B register if it is "in-flight", that is if the
// result register of any previous instruction still needs to be written.
//
// reg [31:0] opa_b_inflight;
// always @(posedge i_clk)
// if ((i_reset)||(clear_pipeline))
// opa_b_inflight <= 32'h00;
// else begin
// if (wr_reg_ce)
// opa_b_inflight[wr_reg_id] <= 1'b0;
// if (opb_ce)
// opa_b_inflight[opa_Rid] <= 1'b1;
// end
//
// always @(posedge i_clk)
// if (opa_b_invalid)
// opa_b_invalid <= opa_b_inflight[opa_A];
// else
// opa_b_invalid <= opa_b_inflight[dcd_iA];
//
 
always @(posedge i_clk)
if (opb_ce)
opb_B <= opa_B + opa_I;
else if ((wr_reg_ce)&&(opa_Bid == wr_reg_id)&&(opa_Brd))
opb_B <= wr_gpreg_vl;
 
always @(posedge i_clk)
if (opa_ce)
opa_F <= dcdF;
always @(posedge i_clk)
if (opb_ce)
begin
case(opa_F[2:0])
3'h0: r_opb_F <= 6'h00; // Always
// These were remapped as part of the new instruction
// set in order to make certain that the low order
// two bits contained the most commonly used
// conditions: Always, LT, Z, and NZ.
3'h1: r_opb_F <= 6'h24; // LT
3'h2: r_opb_F <= 6'h11; // Z
3'h3: r_opb_F <= 6'h10; // NE
3'h4: r_opb_F <= 6'h30; // GT (!N&!Z)
3'h5: r_opb_F <= 6'h20; // GE (!N)
3'h6: r_opb_F <= 6'h02; // C
3'h7: r_opb_F <= 6'h08; // V
endcase
end // Bit order is { (flags_not_used), VNCZ mask, VNCZ value }
assign opb_F = { r_opb_F[3], r_opb_F[5], r_opb_F[1], r_opb_F[4:0] };
 
wire w_opa_valid;
always @(posedge i_clk)
if (i_rst)
opa_valid <= 1'b0;
else if (opa_ce)
opa_valid <= ((dcd_valid)||(dcd_illegal))&&(~clear_pipeline);
 
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline))
begin
opa_valid <= 1'b0;
end else if (opa_ce)
begin
opa_valid <=(dcd_valid);
opa_M <= (dcd_valid)&&(opa_M )&&(~opa_illegal);
opa_DV <= (dcd_valid)&&(opa_DV )&&(~opa_illegal);
opa_FP <= (dcd_valid)&&(opa_FP )&&(~opa_illegal);
end else if (opb_ce)
opa_valid <= 1'b0;
 
initial opb_valid = 1'b0;
initial opb_valid_alu = 1'b0;
initial opb_valid_mem = 1'b0;
initial opb_valid_div = 1'b0;
initial opb_valid_fpu = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline))
begin
opb_valid <= 1'b0;
opb_valid_alu <= 1'b0;
opb_valid_mem <= 1'b0;
opb_valid_div <= 1'b0;
opb_valid_fpu <= 1'b0;
end else if (opb_ce)
begin
// Do we have a valid instruction?
// The decoder may vote to stall one of its
// instructions based upon something we currently
// have in our queue. This instruction must then
// move forward, and get a stall cycle inserted.
// Hence, the test on dcd_stalled here. If we must
// wait until our operands are valid, then we aren't
// valid yet until then.
opb_valid <= (opa_valid);
opb_valid_alu <=(opa_valid)&&((opa_ALU)||(opa_illegal));
opb_valid_mem <= (opa_valid)&&(opa_M )&&(~opa_illegal);
opb_valid_div <= (opa_valid)&&(opa_DV )&&(~opa_illegal);
opb_valid_fpu <= (opa_valid)&&(opa_FP )&&(~opa_illegal);
end else if ((clear_pipeline)||(stage_ce))
begin
opb_valid <= 1'b0;
opb_valid_alu <= 1'b0;
opb_valid_mem <= 1'b0;
opb_valid_div <= 1'b0;
opb_valid_fpu <= 1'b0;
end
 
initial op_break = 1'b0;
always @(posedge i_clk)
if (i_rst) opb_break <= 1'b0;
else if (opb_ce)
opb_break <= (opa_break)&&((break_en)||(~opa_gie));
else if ((clear_pipeline)||(~opb_valid))
opb_break <= 1'b0;
 
reg r_op_lock, r_op_lock_stall;
 
initial r_op_lock_stall = 1'b0;
always @(posedge i_clk)
if (i_rst)
r_op_lock_stall <= 1'b0;
else
r_op_lock_stall <= (~opvalid)||(~op_lock)
||(~dcd_valid)||(~pf_valid);
 
assign op_lock_stall = r_op_lock_stall;
 
initial opa_lock = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline))
opa_lock <= 1'b0;
else if (opa_ce)
opa_lock <= (dcd_lock)&&(~clear_pipeline);
initial opb_lock = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline))
opb_lock <= 1'b0;
else if (opb_ce)
opb_lock <= (opb_lock)&&(~clear_pipeline);
 
initial opa_illegal = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline))
opa_illegal <= 1'b0;
else if(opa_ce)
opa_illegal <=(dcd_illegal);
initial opb_illegal = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline))
opb_illegal <= 1'b0;
else if(opb_ce)
opb_illegal <=(opa_illegal);
 
always @(posedge i_clk)
if (opa_ce)
begin
opa_wF <= (dcdF_wr)&&((~dcdR_cc)||(~dcd_wR))
&&(~dcd_early_branch)&&(~dcd_illegal);
opa_wR <= (dcd_wR)&&(~dcd_early_branch)&&(~dcd_illegal);
end
always @(posedge i_clk)
if (opb_ce)
begin
opb_wF <= opa_wF;
opb_wR <= opa_wR;
end
 
always @(posedge i_clk)
if (opa_ce)
begin
opa_opn <= dcdOp; // Which ALU operation?
opa_R <= dcd_iR;
opa_ccR <= (dcdR_cc)&&(dcd_wR)&&(dcd_iR[4]==dcd_gie);
opa_gie <= dcd_gie;
//
opa_pc <= dcd_valid;
opa_rA <= dcd_;
opa_rB <= dcd_;
end
always @(posedge i_clk)
if (opb_ce)
begin
opb_opn <= opa_opn;
opb_R <= opa_R;
opb_ccR <= opa_ccR;
opb_gie <= opa_gie;
//
opb_pc <= opa_pc;
end
assign opb_Fl = (opb_gie)?(w_uflags):(w_iflags);
 
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline))
opa_phase <= 1'b0;
else if (opa_ce)
opa_phase <= dcd_phase;
 
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline))
opb_phase <= 1'b0;
else if (opb_ce)
opb_phase <= opa_phase;
 
assign opA = r_opA;
 
assign dcdA_stall = (dcd_rA) // &&(dcdvalid) is checked for elsewhere
&&((opa_valid)||(mem_rdbusy)
||(div_busy)||(fpu_busy))
&&((opF_wr)&&(dcdA_cc));
 
assign dcdB_stall = (dcdB_rd)
&&((opa_valid)||(mem_rdbusy)
||(div_busy)||(fpu_busy)||(alu_busy))
&&(
// 1.
((~dcd_zI)&&(
((opb_R == dcdB)&&(opb_wR))
||((mem_rdbusy)&&(~dcd_pipe))
))
// 2.
||((opF_wr)&&(dcdB_cc))
);
assign dcdF_stall = ((~dcdF[3])
||((dcd_rA)&&(dcdA_cc))
||((dcd_rB)&&(dcdB_cc)))
&&(opvalid)&&(opb_ccR);
//
//
// PIPELINE STAGE #4 :: Apply Instruction
//
//
fastops fastalu(i_clk, i_rst, alu_ce,
(opb_valid_alu), opb_opn, opb_A, opb_B,
alu_result, alu_flags, alu_valid, alu_illegal_op,
alu_busy);
 
div thedivide(i_clk, (i_rst)||(clear_pipeline), div_ce, opb_opn[0],
opb_A, opb_B, div_busy, div_valid, div_error, div_result,
div_flags);
 
generate
if (IMPLEMENT_FPU != 0)
begin
//
// sfpu thefpu(i_clk, i_rst, fpu_ce,
// opA, opB, fpu_busy, fpu_valid, fpu_err, fpu_result,
// fpu_flags);
//
assign fpu_error = 1'b0; // Must only be true if fpu_valid
assign fpu_busy = 1'b0;
assign fpu_valid = 1'b0;
assign fpu_result= 32'h00;
assign fpu_flags = 4'h0;
end else begin
assign fpu_error = 1'b0;
assign fpu_busy = 1'b0;
assign fpu_valid = 1'b0;
assign fpu_result= 32'h00;
assign fpu_flags = 4'h0;
end endgenerate
 
 
assign set_cond = ((opb_F[7:4]&opb_Fl[3:0])==opb_F[3:0]);
initial alF_wr = 1'b0;
initial alu_wr = 1'b0;
always @(posedge i_clk)
if (i_rst)
begin
alu_wr <= 1'b0;
alF_wr <= 1'b0;
end else if (alu_ce)
begin
// alu_reg <= opR;
alu_wr <= (opb_wR)&&(set_cond);
alF_wr <= (opb_wF)&&(set_cond);
end else if (~alu_busy) begin
// These are strobe signals, so clear them if not
// set for any particular clock
alu_wr <= (i_halt)&&(i_dbg_we);
alF_wr <= 1'b0;
end
 
initial alu_phase = 1'b0;
always @(posedge i_clk)
if (i_rst)
alu_phase <= 1'b0;
else if ((adf_ce_unconditional)||(mem_ce))
alu_phase <= opb_phase;
 
always @(posedge i_clk)
if (adf_ce_unconditional)
alu_reg <= opb_R;
else if ((i_halt)&&(i_dbg_we))
alu_reg <= i_dbg_reg;
 
//
// DEBUG Register write access starts here
//
reg dbgv;
initial dbgv = 1'b0;
always @(posedge i_clk)
dbgv <= (~i_rst)&&(i_halt)&&(i_dbg_we)&&(r_halted);
reg [31:0] dbg_val;
always @(posedge i_clk)
dbg_val <= i_dbg_data;
always @(posedge i_clk)
if (stage_ce)
alu_gie <= op_gie;
always @(posedge i_clk)
if (stage_ce)
alu_pc <= opb_pc;
 
initial alu_illegal = 0;
always @(posedge i_clk)
if (clear_pipeline)
alu_illegal <= 1'b0;
else if (stage_ce)
alu_illegal <= opb_illegal;
 
initial r_alu_pc_valid = 1'b0;
initial mem_pc_valid = 1'b0;
always @(posedge i_clk)
if (i_rst)
r_alu_pc_valid <= 1'b0;
else if (adf_ce_unconditional)//Includes&&(~alu_clear_pipeline)
r_alu_pc_valid <= 1'b1;
else if (((~alu_busy)&&(~div_busy)&&(~fpu_busy))||(clear_pipeline))
r_alu_pc_valid <= 1'b0;
assign alu_pc_valid = (r_alu_pc_valid)&&((~alu_busy)&&(~div_busy)&&(~fpu_busy));
always @(posedge i_clk)
if (i_rst)
mem_pc_valid <= 1'b0;
else
mem_pc_valid <= (mem_ce);
 
wire bus_lock;
 
reg [1:0] r_bus_lock;
initial r_bus_lock = 2'b00;
always @(posedge i_clk)
if (i_rst)
r_bus_lock <= 2'b00;
else if ((opb_ce)&&(opb_lock))
r_bus_lock <= 2'b11;
else if ((|r_bus_lock)&&((~opb_valid_mem)||(~opb_ce)))
r_bus_lock <= r_bus_lock + 2'b11; // r_bus_lock -= 1
assign bus_lock = |r_bus_lock;
 
pipemem #(AW,IMPLEMENT_LOCK) domem(i_clk, i_rst,(mem_ce)&&(set_cond), bus_lock,
(opb_opn[0]), opb_B, opb_A, opb_R,
mem_busy, mem_pipe_stalled,
mem_valid, bus_err, mem_wreg, mem_result,
mem_cyc_gbl, mem_cyc_lcl,
mem_stb_gbl, mem_stb_lcl,
mem_we, mem_addr, mem_data,
mem_ack, mem_stall, mem_err, i_wb_data);
assign mem_rdbusy = ((mem_busy)&&(~mem_we));
 
// Either the prefetch or the instruction gets the memory bus, but
// never both.
wbdblpriarb #(32,AW) pformem(i_clk, i_rst,
// Memory access to the arbiter, priority position
mem_cyc_gbl, mem_cyc_lcl, mem_stb_gbl, mem_stb_lcl,
mem_we, mem_addr, mem_data, mem_ack, mem_stall, mem_err,
// Prefetch access to the arbiter
pf_cyc, 1'b0, pf_stb, 1'b0, pf_we, pf_addr, pf_data,
pf_ack, pf_stall, pf_err,
// Common wires, in and out, of the arbiter
o_wb_gbl_cyc, o_wb_lcl_cyc, o_wb_gbl_stb, o_wb_lcl_stb,
o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_err);
 
 
 
//
//
//
//
//
//
//
//
// PIPELINE STAGE #5 :: Write-back results
//
//
 
// Unlike previous versions of the writeback routine(s), this version
// requires that everything be registered and clocked as soon as it is
// valid. So, let's start by clocking in our results.
reg [4:0] r_wr_reg;
reg [31:0] r_wr_val;
reg r_wr_ce, r_wr_err;
 
// 1. Will we need to write a register?
always @(posedge i_clk)
r_wr_ce <= (dbgv)||(mem_valid)
||((~clear_pipeline)&&(~alu_illegal)
&&(((alu_wr)&&(alu_valid))
||(div_valid)||(fpu_valid)));
assign wr_reg_ce = r_wr_ce;
 
// 2. Did the ALU/MEM/DIV/FPU stage produce an error of any type?
// a. Illegal instruction
// b. Division by zero
// c. Floating point error
// d. Bus Error
// these will be causes for an interrupt on the next clock after this
// one.
always @(posedge i_clk)
r_wr_err <= ((div_valid)&&(div_error))
||((fpu_valid)&&(fpu_error))
||((alu_pc_valid)&&(alu_illegal))
||(bus_err);
reg r_wr_illegal;
always @(posedge i_clk)
r_wr_illegal <= (alu_pc_valid)&&(alu_illegal);
 
// Which register shall be written?
// Note that the alu_reg is the register to write on a divide or
// FPU operation.
always @(posedge i_clk)
r_wr_reg <= (alu_wr|div_valid|fpu_valid)?alu_reg:mem_wreg;
assign wr_reg_id = r_wr_reg;
 
// Are we writing to the CC register?
assign wr_write_cc = (wr_reg_id[3:0] == `CPU_CC_REG);
assign wr_write_scc = (wr_reg_id[4:0] == {1'b0, `CPU_CC_REG});
assign wr_write_ucc = (wr_reg_id[4:0] == {1'b1, `CPU_CC_REG});
// Are we writing to the PC?
assign wr_write_pc = (wr_reg_id[3:0] == `CPU_PC_REG);
 
// What value to write?
always @(posedge i_clk)
r_wr_val <= ((mem_valid) ? mem_result
:((div_valid|fpu_valid))
? ((div_valid) ? div_result:fpu_result)
:((dbgv) ? dbg_val : alu_result));
assign wr_gpreg_vl = r_wr_val;
assign wr_spreg_vl = r_wr_val;
 
// Do we write back our flags?
reg r_wr_flags_ce;
initial r_wr_flags_ce = 1'b0;
always @(posedge i_clk)
r_wr_flags_ce <= ((alF_wr)||(div_valid)||(fpu_valid))
&&(~clear_pipeline)&&(~alu_illegal);
assign wr_flags_ce = r_wr_flags_ce;
 
reg [3:0] r_wr_newflags;
always @(posedge i_clk)
if (div_valid)
r_wr_newflags <= div_flags;
else if (fpu_valid)
r_wr_newflags <= fpu_flags;
else // if (alu_valid)
r_wr_newflags <= alu_flags;
 
reg r_wr_gie;
always @(posedge i_clk)
r_wr_gie <= (~dbgv)&&(alu_gie);
 
reg r_wr_pc_valid;
initial r_wr_pc_valid = 1'b0;
always @(posedge i_clk)
r_wr_pc_valid <= ((alu_pc_valid)&&(~clear_pipeline))
||(mem_pc_valid);
reg [(AW-1):0] r_wr_pc;
always @(posedge i_clk)
r_wr_pc <= alu_pc; // (alu_pc_valid)?alu_pc : mem_pc;
 
////
//
//
// Write back, second clock
//
//
////
always @(posedge i_clk)
if (wr_reg_ce)
regset[wr_reg_id] <= wr_gpreg_vl;
 
 
assign w_uflags = { uhalt_phase, ufpu_err_flag,
udiv_err_flag, ubus_err_flag, trap, ill_err_u,
1'b0, step, 1'b1, sleep,
((wr_flags_ce)&&(alu_gie))?r_wr_newflags:flags };
assign w_iflags = { ihalt_phase, ifpu_err_flag,
idiv_err_flag, ibus_err_flag, trap, ill_err_i,
break_en, 1'b0, 1'b0, sleep,
((wr_flags_ce)&&(~alu_gie))?r_wr_newflags:iflags };
 
 
// What value to write?
always @(posedge i_clk)
// If explicitly writing the register itself
if ((wr_reg_ce)&&(wr_reg_id[4])&&(wr_write_cc))
flags <= wr_gpreg_vl[3:0];
// Otherwise if we're setting the flags from an ALU operation
else if ((wr_flags_ce)&&(alu_gie))
flags <= r_wr_newflags;
 
always @(posedge i_clk)
if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_cc))
iflags <= wr_gpreg_vl[3:0];
else if ((wr_flags_ce)&&(~alu_gie))
iflags <= r_wr_newflags;
 
// The 'break' enable bit. This bit can only be set from supervisor
// mode. It control what the CPU does upon encountering a break
// instruction.
//
// The goal, upon encountering a break is that the CPU should stop and
// not execute the break instruction, choosing instead to enter into
// either interrupt mode or halt first.
// if ((break_en) AND (break_instruction)) // user mode or not
// HALT CPU
// else if (break_instruction) // only in user mode
// set an interrupt flag, set the user break bit,
// go to supervisor mode, allow supervisor to step the CPU.
// Upon a CPU halt, any break condition will be reset. The
// external debugger will then need to deal with whatever
// condition has taken place.
initial break_en = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(i_halt))
break_en <= 1'b0;
else if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_cc))
break_en <= wr_spreg_vl[`CPU_BREAK_BIT];
 
reg pipe_busy;
initial pipe_busy <= 1'b0;
always @(posedge i_clk)
pipe_busy <= ((mem_ce)||(alu_ce)||(div_ce)||(fpu_ce))
||((alu_busy)||(mem_busy)||(div_busy)||(fpu_busy));
 
// pending_break <= ((break_en)||(~op_gie))&&(op_break)
assign o_break = ((op_break)&&(~pipe_busy)&&(~clear_pipeline))
||((~r_wr_gie)&&(r_wr_err));
 
 
// The GIE register. Only interrupts can disable the interrupt register
reg slow_interrupt, fast_interrupt;
initial slow_interrupt = 1'b0;
// The key difference between a fast interrupt and a slow interrupt
// is that a fast interrupt requires the pipeline to be cleared,
// whereas a slow interrupt does not.
always @(posedge i_clk)
slow_interrupt <= (gie)&&(
(i_interrupt)
// If we encounter a break instruction, if the break
// enable isn't set. This is slow because pre
// ALU logic will prevent the break from moving forward.
||((op_break)&&(~break_en)));
initial fast_interrupt = 1'b0;
always @(posedge i_clk) // 12 inputs
fast_interrupt <= ((gie)||(alu_gie))&&(
((r_wr_pc_valid)&&(step)&&(~alu_phase)&&(~bus_lock))
// Or ... if we encountered some form of error in our
// instruction ...
||(r_wr_err)
// Or if we write to the CC register.
||((wr_reg_ce)&&(~wr_spreg_vl[`CPU_GIE_BIT])
&&(wr_reg_id[4])&&(wr_write_cc)));
 
assign w_switch_to_interrupt = fast_interrupt;
 
assign w_release_from_interrupt = (~gie)&&(~i_interrupt)
// Then if we write the CC register
&&(((wr_reg_ce)&&(~r_wr_gie)&&(wr_spreg_vl[`CPU_GIE_BIT])
&&(~wr_reg_id[4])&&(wr_write_cc))
);
always @(posedge i_clk)
if (i_rst)
gie <= 1'b0;
else if ((fast_interrupt)||(slow_interrupt))
gie <= 1'b0;
else if (w_release_from_interrupt)
gie <= 1'b1;
 
initial trap = 1'b0;
always @(posedge i_clk)
if (i_rst)
trap <= 1'b0;
else if (w_release_from_interrupt)
trap <= 1'b0;
else if ((r_wr_gie)&&(wr_reg_ce)&&(wr_write_cc)
&&(~wr_spreg_vl[`CPU_GIE_BIT]))
// &&(wr_reg_id[4]) implied
trap <= 1'b1;
else if ((wr_reg_ce)&&(wr_write_cc)&&(wr_reg_id[4]))
trap <= wr_spreg_vl[`CPU_TRAP_BIT];
 
// The sleep register. Setting the sleep register causes the CPU to
// sleep until the next interrupt. Setting the sleep register within
// interrupt mode causes the processor to halt until a reset. This is
// a panic/fault halt. The trick is that you cannot be allowed to
// set the sleep bit and switch to supervisor mode in the same
// instruction: users are not allowed to halt the CPU.
always @(posedge i_clk)
if ((i_rst)||(slow_interrupt))
sleep <= 1'b0;
else if ((wr_reg_ce)&&(wr_write_cc)&&(~r_wr_gie))
// In supervisor mode, we have no protections. The
// supervisor can set the sleep bit however he wants.
// Well ... not quite. Switching to user mode and
// sleep mode shouold only be possible if the interrupt
// flag isn't set.
// Thus: if (i_interrupt)&&(wr_spreg_vl[GIE])
// don't set the sleep bit
// otherwise however it would o.w. be set
sleep <= (wr_spreg_vl[`CPU_SLEEP_BIT])
&&((~i_interrupt)||(~wr_spreg_vl[`CPU_GIE_BIT]));
else if ((wr_reg_ce)&&(wr_write_cc)&&(wr_spreg_vl[`CPU_GIE_BIT]))
// In user mode, however, you can only set the sleep
// mode while remaining in user mode. You can't switch
// to sleep mode *and* supervisor mode at the same
// time, lest you halt the CPU.
sleep <= wr_spreg_vl[`CPU_SLEEP_BIT];
 
always @(posedge i_clk)
if ((i_rst)||(fast_interrupt))
step <= 1'b0;
else if ((wr_reg_ce)&&(~alu_gie)&&(wr_reg_id[4])&&(wr_write_cc))
step <= wr_spreg_vl[`CPU_STEP_BIT];
else if (((alu_pc_valid)||(mem_pc_valid))&&(step)&&(gie))
step <= 1'b0;
 
 
initial ill_err_i = 1'b0;
always @(posedge i_clk)
if (i_rst)
ill_err_i <= 1'b0;
// Only the debug interface can clear this bit
else if ((dbgv)&&(wr_reg_id == {1'b0, `CPU_CC_REG})
&&(~wr_spreg_vl[`CPU_ILL_BIT]))
ill_err_i <= 1'b0;
else if ((r_wr_illegal)&&(~r_wr_gie))
ill_err_i <= 1'b1;
initial ill_err_u = 1'b0;
always @(posedge i_clk)
// The bit is automatically cleared on release from interrupt
// or reset
if ((i_rst)||(w_release_from_interrupt))
ill_err_u <= 1'b0;
// If the supervisor writes to this register, clearing the
// bit, then clear it
else if ((~r_wr_gie)
&&(wr_reg_ce)&&(~wr_spreg_vl[`CPU_ILL_BIT])
&&(wr_reg_id[4])&&(wr_write_cc))
ill_err_u <= 1'b0;
else if ((r_wr_gie)&&(r_wr_illegal))
ill_err_u <= 1'b1;
// Supervisor/interrupt bus error flag -- this will crash the CPU if
// ever set.
initial ibus_err_flag = 1'b0;
always @(posedge i_clk)
if (i_rst)
ibus_err_flag <= 1'b0;
else if ((dbgv)&&(wr_reg_id == {1'b0, `CPU_CC_REG})
&&(~wr_spreg_vl[`CPU_BUSERR_BIT]))
ibus_err_flag <= 1'b0;
else if ((bus_err)&&(~alu_gie))
ibus_err_flag <= 1'b1;
// User bus error flag -- if ever set, it will cause an interrupt to
// supervisor mode.
initial ubus_err_flag = 1'b0;
always @(posedge i_clk)
if (i_rst)
ubus_err_flag <= 1'b0;
else if (w_release_from_interrupt)
ubus_err_flag <= 1'b0;
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce)
&&(~wr_spreg_vl[`CPU_BUSERR_BIT])
&&(wr_reg_id[4])&&(wr_write_cc))
ubus_err_flag <= 1'b0;
else if ((bus_err)&&(alu_gie))
ubus_err_flag <= 1'b1;
 
reg r_idiv_err_flag, r_udiv_err_flag;
 
// Supervisor/interrupt divide (by zero) error flag -- this will
// crash the CPU if ever set. This bit is thus available for us
// to be able to tell if/why the CPU crashed.
initial r_idiv_err_flag = 1'b0;
always @(posedge i_clk)
if (i_rst)
r_idiv_err_flag <= 1'b0;
else if ((dbgv)&&(wr_reg_id == {1'b0, `CPU_CC_REG})
&&(~wr_spreg_vl[`CPU_DIVERR_BIT]))
r_idiv_err_flag <= 1'b0;
else if ((div_error)&&(div_valid)&&(~r_wr_gie))
r_idiv_err_flag <= 1'b1;
// User divide (by zero) error flag -- if ever set, it will
// cause a sudden switch interrupt to supervisor mode.
initial r_udiv_err_flag = 1'b0;
always @(posedge i_clk)
if (i_rst)
r_udiv_err_flag <= 1'b0;
else if (w_release_from_interrupt)
r_udiv_err_flag <= 1'b0;
else if (((~r_wr_gie)||(dbgv))&&(wr_reg_ce)
&&(~wr_spreg_vl[`CPU_DIVERR_BIT])
&&(wr_reg_id[4])&&(wr_write_cc))
r_udiv_err_flag <= 1'b0;
else if ((div_error)&&(r_wr_gie)&&(div_valid))
r_udiv_err_flag <= 1'b1;
 
assign idiv_err_flag = r_idiv_err_flag;
assign udiv_err_flag = r_udiv_err_flag;
 
generate
if (IMPLEMENT_FPU !=0)
begin
// Supervisor/interrupt floating point error flag -- this will
// crash the CPU if ever set.
reg r_ifpu_err_flag, r_ufpu_err_flag;
initial r_ifpu_err_flag = 1'b0;
always @(posedge i_clk)
if (i_rst)
r_ifpu_err_flag <= 1'b0;
else if ((dbgv)&&(wr_reg_id == {1'b0, `CPU_CC_REG})
&&(~wr_spreg_vl[`CPU_FPUERR_BIT]))
r_ifpu_err_flag <= 1'b0;
else if ((fpu_error)&&(fpu_valid)&&(~r_wr_gie))
r_ifpu_err_flag <= 1'b1;
// User floating point error flag -- if ever set, it will cause
// a sudden switch interrupt to supervisor mode.
initial r_ufpu_err_flag = 1'b0;
always @(posedge i_clk)
if (i_rst)
r_ufpu_err_flag <= 1'b0;
else if (w_release_from_interrupt)
r_ufpu_err_flag <= 1'b0;
else if (((~r_wr_gie)||(dbgv))&&(wr_reg_ce)
&&(~wr_spreg_vl[`CPU_FPUERR_BIT])
&&(wr_reg_id[4])&&(wr_write_cc))
r_ufpu_err_flag <= 1'b0;
else if ((fpu_error)&&(r_wr_gie)&&(fpu_valid))
r_ufpu_err_flag <= 1'b1;
 
assign ifpu_err_flag = r_ifpu_err_flag;
assign ufpu_err_flag = r_ufpu_err_flag;
end else begin
assign ifpu_err_flag = 1'b0;
assign ufpu_err_flag = 1'b0;
end endgenerate
 
`ifdef OPT_VLIW
reg r_ihalt_phase, r_uhalt_phase;
 
initial r_ihalt_phase = 0;
initial r_uhalt_phase = 0;
always @(posedge i_clk)
if (i_rst)
r_ihalt_phase <= 1'b0;
else if ((~alu_gie)&&(alu_pc_valid)&&(~clear_pipeline))
r_ihalt_phase <= alu_phase;
always @(posedge i_clk)
if (r_wr_gie)
r_uhalt_phase <= alu_phase;
else if (w_release_from_interrupt)
r_uhalt_phase <= 1'b0;
 
assign ihalt_phase = r_ihalt_phase;
assign uhalt_phase = r_uhalt_phase;
`else
assign ihalt_phase = 1'b0;
assign uhalt_phase = 1'b0;
`endif
 
//
// Write backs to the PC register, and general increments of it
// We support two: upc and ipc. If the instruction is normal,
// we increment upc, if interrupt level we increment ipc. If
// the instruction writes the PC, we write whichever PC is appropriate.
//
// Do we need to all our partial results from the pipeline?
// What happens when the pipeline has gie and ~gie instructions within
// it? Do we clear both? What if a gie instruction tries to clear
// a non-gie instruction?
always @(posedge i_clk)
if ((wr_reg_ce)&&(wr_reg_id[4])&&(wr_write_pc))
upc <= wr_spreg_vl[(AW-1):0];
else if ((r_wr_gie)&&
(((alu_pc_valid)&&(~clear_pipeline))
||(mem_pc_valid)))
upc <= alu_pc;
 
always @(posedge i_clk)
if (i_rst)
ipc <= RESET_ADDRESS;
else if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_pc))
ipc <= wr_spreg_vl[(AW-1):0];
else if ((~r_wr_gie)&&
(((alu_pc_valid)&&(~clear_pipeline))
||(mem_pc_valid)))
ipc <= alu_pc;
 
always @(posedge i_clk)
if (i_rst)
pf_pc <= RESET_ADDRESS;
else if ((w_switch_to_interrupt)||((~gie)&&(w_clear_icache)))
pf_pc <= ipc;
else if ((w_release_from_interrupt)||((gie)&&(w_clear_icache)))
pf_pc <= upc;
else if ((wr_reg_ce)&&(wr_reg_id[4] == gie)&&(wr_write_pc))
pf_pc <= wr_spreg_vl[(AW-1):0];
`ifdef OPT_PIPELINED
else if ((dcd_early_branch)&&(~clear_pipeline))
pf_pc <= dcd_branch_pc + 1;
else if ((new_pc)||((~dcd_stalled)&&(pf_valid)))
pf_pc <= pf_pc + {{(AW-1){1'b0}},1'b1};
`else
else if ((alu_gie==gie)&&(
((alu_pc_valid)&&(~clear_pipeline))
||(mem_pc_valid)))
pf_pc <= alu_pc;
`endif
 
initial new_pc = 1'b1;
always @(posedge i_clk)
if ((i_rst)||(i_clear_pf_cache))
new_pc <= 1'b1;
else if (w_switch_to_interrupt)
new_pc <= 1'b1;
else if (w_release_from_interrupt)
new_pc <= 1'b1;
else if ((wr_reg_ce)&&(wr_reg_id[4] == gie)&&(wr_write_pc))
new_pc <= 1'b1;
else
new_pc <= 1'b0;
 
`ifdef OPT_PIPELINED
reg r_clear_icache;
initial r_clear_icache = 1'b1;
always @(posedge i_clk)
if ((i_rst)||(i_clear_pf_cache))
r_clear_icache <= 1'b1;
else if ((wr_reg_ce)&&(wr_write_scc))
r_clear_icache <= wr_spreg_vl[`CPU_CLRCACHE_BIT];
else
r_clear_icache <= 1'b0;
assign w_clear_icache = r_clear_icache;
`else
assign w_clear_icache = 1'b0;
`endif
 
//
// The debug interface
generate
if (AW<32)
begin
always @(posedge i_clk)
begin
o_dbg_reg <= regset[i_dbg_reg];
if (i_dbg_reg[3:0] == `CPU_PC_REG)
o_dbg_reg <= {{(32-AW){1'b0}},(i_dbg_reg[4])?upc:ipc};
else if (i_dbg_reg[3:0] == `CPU_CC_REG)
begin
o_dbg_reg[14:0] <= (i_dbg_reg[4])?w_uflags:w_iflags;
o_dbg_reg[31:23] <= w_cpu_info;
o_dbg_reg[`CPU_GIE_BIT] <= gie;
end
end
end else begin
always @(posedge i_clk)
begin
o_dbg_reg <= regset[i_dbg_reg];
if (i_dbg_reg[3:0] == `CPU_PC_REG)
o_dbg_reg <= (i_dbg_reg[4])?upc:ipc;
else if (i_dbg_reg[3:0] == `CPU_CC_REG)
begin
o_dbg_reg[14:0] <= (i_dbg_reg[4])?w_uflags:w_iflags;
o_dbg_reg[31:23] <= w_cpu_info;
o_dbg_reg[`CPU_GIE_BIT] <= gie;
end
end
end endgenerate
 
always @(posedge i_clk)
o_dbg_cc <= { o_break, bus_err, gie, sleep };
 
always @(posedge i_clk)
r_halted <= (i_halt)&&(
// To be halted, any long lasting instruction must
// be completed.
(~pf_cyc)&&(~mem_busy)&&(~alu_busy)
&&(~div_busy)&&(~fpu_busy)
// Operations must either be valid, or illegal
&&((opvalid)||(i_rst)||(dcd_illegal))
// Decode stage must be either valid, in reset, or ill
&&((dcdvalid)||(i_rst)||(pf_illegal)));
assign o_dbg_stall = ~r_halted;
 
//
//
// Produce accounting outputs: Account for any CPU stalls, so we can
// later evaluate how well we are doing.
//
//
assign o_op_stall = (master_ce)&&(op_stall);
assign o_pf_stall = (master_ce)&&(~pf_valid);
assign o_i_count = (alu_pc_valid)&&(~clear_pipeline);
 
`ifdef DEBUG_SCOPE
always @(posedge i_clk)
o_debug <= {
/*
o_break, i_wb_err, pf_pc[1:0],
flags,
pf_valid, dcdvalid, opvalid, alu_valid, mem_valid,
op_ce, alu_ce, mem_ce,
//
master_ce, opvalid_alu, opvalid_mem,
//
alu_stall, mem_busy, op_pipe, mem_pipe_stalled,
mem_we,
// ((opvalid_alu)&&(alu_stall))
// ||((opvalid_mem)&&(~op_pipe)&&(mem_busy))
// ||((opvalid_mem)&&( op_pipe)&&(mem_pipe_stalled)));
// opA[23:20], opA[3:0],
gie, sleep, wr_reg_ce, wr_gpreg_vl[4:0]
*/
/*
i_rst, master_ce, (new_pc),
((dcd_early_branch)&&(dcdvalid)),
pf_valid, pf_illegal,
op_ce, dcd_ce, dcdvalid, dcd_stalled,
pf_cyc, pf_stb, pf_we, pf_ack, pf_stall, pf_err,
pf_pc[7:0], pf_addr[7:0]
*/
 
i_wb_err, gie, alu_illegal,
(new_pc)||((dcd_early_branch)&&(~clear_pipeline)),
mem_busy,
(mem_busy)?{ (o_wb_gbl_stb|o_wb_lcl_stb), o_wb_we,
o_wb_addr[8:0] }
: { instruction[31:21] },
pf_valid, (pf_valid) ? alu_pc[14:0]
:{ pf_cyc, pf_stb, pf_pc[12:0] }
 
/*
i_wb_err, gie, new_pc, dcd_early_branch, // 4
pf_valid, pf_cyc, pf_stb, instruction_pc[0], // 4
instruction[30:27], // 4
dcd_gie, mem_busy, o_wb_gbl_cyc, o_wb_gbl_stb, // 4
dcdvalid,
((dcd_early_branch)&&(~clear_pipeline)) // 15
? dcd_branch_pc[14:0]:pf_pc[14:0]
*/
};
`endif
endmodule
/rtl/cpu/pipefetch.v
0,0 → 1,299
////////////////////////////////////////////////////////////////////////////////
//
// Filename: pipefetch.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: Keeping our CPU fed with instructions, at one per clock and
// with no stalls, can be quite a chore. Worse, the Wishbone
// takes a couple of cycles just to read one instruction from
// the bus. However, if we use pipeline accesses to the Wishbone
// bus, then we can read more and faster. Further, if we cache
// these results so that we have them before we need them, then
// we have a chance of keeping our CPU from stalling. Those are
// the purposes of this instruction fetch module: 1) Pipeline
// wishbone accesses, and 2) an instruction cache.
//
// 20150919 -- Fixed a nasty race condition whereby the pipefetch routine
// would produce either the same instruction twice, or skip
// an instruction. This condition was dependent on the CPU stall
// condition, and would only take place if the pipeline wasn't
// completely full throughout the stall.
//
// Interface support was also added for trapping on illegal
// instructions (i.e., instruction fetches that cause bus errors),
// however the internal interface has not caught up to supporting
// these exceptions yet.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
module pipefetch(i_clk, i_rst, i_new_pc, i_clear_cache, i_stall_n, i_pc,
o_i, o_pc, o_v,
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_wb_request,
o_illegal);
parameter RESET_ADDRESS=32'h0010_0000,
LGCACHELEN = 6, ADDRESS_WIDTH=24,
CACHELEN=(1<<LGCACHELEN), BUSW=32, AW=ADDRESS_WIDTH;
input i_clk, i_rst, i_new_pc,
i_clear_cache, i_stall_n;
input [(AW-1):0] i_pc;
output reg [(BUSW-1):0] o_i;
output reg [(AW-1):0] o_pc;
output wire o_v;
//
output reg o_wb_cyc, o_wb_stb;
output wire o_wb_we;
output reg [(AW-1):0] o_wb_addr;
output wire [(BUSW-1):0] o_wb_data;
//
input i_wb_ack, i_wb_stall, i_wb_err;
input [(BUSW-1):0] i_wb_data;
//
// Is the (data) memory unit also requesting access to the bus?
input i_wb_request;
output wire o_illegal;
 
// Fixed bus outputs: we read from the bus only, never write.
// Thus the output data is ... irrelevant and don't care. We set it
// to zero just to set it to something.
assign o_wb_we = 1'b0;
assign o_wb_data = 0;
 
reg [(AW-1):0] r_cache_base;
reg [(LGCACHELEN):0] r_nvalid, r_acks_waiting;
reg [(BUSW-1):0] cache[0:(CACHELEN-1)];
 
wire [(LGCACHELEN-1):0] w_cache_offset;
reg [1:0] r_cache_offset;
 
reg r_addr_set;
reg [(AW-1):0] r_addr;
 
wire [(AW-1):0] bus_nvalid;
assign bus_nvalid = { {(AW-LGCACHELEN-1){1'b0}}, r_nvalid };
 
// What are some of the conditions for which we need to restart the
// cache?
wire w_pc_out_of_bounds;
assign w_pc_out_of_bounds = ((i_new_pc)&&((r_nvalid == 0)
||(i_pc < r_cache_base)
||(i_pc >= r_cache_base + CACHELEN)
||(i_pc >= r_cache_base + bus_nvalid+5)));
wire w_ran_off_end_of_cache;
assign w_ran_off_end_of_cache =((r_addr_set)&&((r_addr < r_cache_base)
||(r_addr >= r_cache_base + CACHELEN)
||(r_addr >= r_cache_base + bus_nvalid+5)));
wire w_running_out_of_cache;
assign w_running_out_of_cache = (r_addr_set)
&&(r_addr >= r_cache_base +
// {{(AW-LGCACHELEN-1),{1'b0}},2'b11,
// {(LGCACHELEN-1){1'b0}}})
// (1<<(LGCACHELEN-2)) + (1<<(LGCACHELEN-1)))
+(3<<(LGCACHELEN-2)))
&&(|r_nvalid[(LGCACHELEN):(LGCACHELEN-1)]);
 
initial r_cache_base = RESET_ADDRESS;
always @(posedge i_clk)
begin
if ((i_rst)||(i_clear_cache)||((o_wb_cyc)&&(i_wb_err)))
begin
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
// r_cache_base <= RESET_ADDRESS;
// end else if ((~o_wb_cyc)&&(i_new_pc)&&(r_nvalid != 0)
// &&(i_pc >= r_cache_base)
// &&(i_pc < r_cache_base + bus_nvalid))
// begin
// The new instruction is in our cache, do nothing
// with the bus here.
end else if ((o_wb_cyc)&&(w_pc_out_of_bounds))
begin
// We need to abandon our bus action to start over in
// a new region, setting up a new cache. This may
// happen mid cycle while waiting for a result. By
// dropping o_wb_cyc, we state that we are no longer
// interested in that result--whatever it might be.
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
end else if ((~o_wb_cyc)&&(~r_nvalid[LGCACHELEN])&&(~i_wb_request)&&(r_addr_set))
begin
// Restart a bus cycle that was interrupted when the
// data section wanted access to our bus.
o_wb_cyc <= 1'b1;
o_wb_stb <= 1'b1;
// o_wb_addr <= r_cache_base + bus_nvalid;
end else if ((~o_wb_cyc)&&(
(w_pc_out_of_bounds)||(w_ran_off_end_of_cache)))
begin
// Start a bus transaction
o_wb_cyc <= 1'b1;
o_wb_stb <= 1'b1;
// o_wb_addr <= (i_new_pc) ? i_pc : r_addr;
// r_nvalid <= 0;
// r_cache_base <= (i_new_pc) ? i_pc : r_addr;
// w_cache_offset <= 0;
end else if ((~o_wb_cyc)&&(w_running_out_of_cache))
begin
// If we're using the last quarter of the cache, then
// let's start a bus transaction to extend the cache.
o_wb_cyc <= 1'b1;
o_wb_stb <= 1'b1;
// o_wb_addr <= r_cache_base + (1<<(LGCACHELEN));
// r_nvalid <= r_nvalid - (1<<(LGCACHELEN-2));
// r_cache_base <= r_cache_base + (1<<(LGCACHELEN-2));
// w_cache_offset <= w_cache_offset + (1<<(LGCACHELEN-2));
end else if (o_wb_cyc)
begin
// This handles everything ... but the case where
// while reading we need to extend our cache.
if ((o_wb_stb)&&(~i_wb_stall))
begin
// o_wb_addr <= o_wb_addr + 1;
if ((o_wb_addr - r_cache_base >= CACHELEN-1)
||(i_wb_request))
o_wb_stb <= 1'b0;
end
 
if (i_wb_ack)
begin
// r_nvalid <= r_nvalid + 1;
if ((r_acks_waiting == 1)&&(~o_wb_stb))
o_wb_cyc <= 1'b0;
end else if ((r_acks_waiting == 0)&&(~o_wb_stb))
o_wb_cyc <= 1'b0;
end
end
 
initial r_nvalid = 0;
always @(posedge i_clk)
if ((i_rst)||(i_clear_cache)) // Required, so we can reload memoy and then reset
r_nvalid <= 0;
else if ((~o_wb_cyc)&&(
(w_pc_out_of_bounds)||(w_ran_off_end_of_cache)))
r_nvalid <= 0;
else if ((~o_wb_cyc)&&(w_running_out_of_cache))
r_nvalid[LGCACHELEN:(LGCACHELEN-2)]
<= r_nvalid[LGCACHELEN:(LGCACHELEN-2)] +3'b111;
// i.e. - (1<<(LGCACHELEN-2));
else if ((o_wb_cyc)&&(i_wb_ack))
r_nvalid <= r_nvalid + {{(LGCACHELEN){1'b0}},1'b1}; // +1;
 
always @(posedge i_clk)
if (i_clear_cache)
r_cache_base <= i_pc;
else if ((~o_wb_cyc)&&(
(w_pc_out_of_bounds)
||(w_ran_off_end_of_cache)))
r_cache_base <= (i_new_pc) ? i_pc : r_addr;
else if ((~o_wb_cyc)&&(w_running_out_of_cache))
r_cache_base[(AW-1):(LGCACHELEN-2)]
<= r_cache_base[(AW-1):(LGCACHELEN-2)]
+ {{(AW-LGCACHELEN+1){1'b0}},1'b1};
// i.e. + (1<<(LGCACHELEN-2));
 
always @(posedge i_clk)
if (i_clear_cache)
r_cache_offset <= 0;
else if ((~o_wb_cyc)&&(
(w_pc_out_of_bounds)
||(w_ran_off_end_of_cache)))
r_cache_offset <= 0;
else if ((~o_wb_cyc)&&(w_running_out_of_cache))
r_cache_offset[1:0] <= r_cache_offset[1:0] + 2'b01;
assign w_cache_offset = { r_cache_offset, {(LGCACHELEN-2){1'b0}} };
 
always @(posedge i_clk)
if (i_clear_cache)
o_wb_addr <= i_pc;
else if ((o_wb_cyc)&&(w_pc_out_of_bounds))
begin
if (i_wb_ack)
o_wb_addr <= r_cache_base + bus_nvalid+1;
else
o_wb_addr <= r_cache_base + bus_nvalid;
end else if ((~o_wb_cyc)&&((w_pc_out_of_bounds)
||(w_ran_off_end_of_cache)))
o_wb_addr <= (i_new_pc) ? i_pc : r_addr;
else if ((o_wb_stb)&&(~i_wb_stall)) // && o_wb_cyc
o_wb_addr <= o_wb_addr + 1;
 
initial r_acks_waiting = 0;
always @(posedge i_clk)
if (~o_wb_cyc)
r_acks_waiting <= 0;
// o_wb_cyc *must* be true for all following
else if ((o_wb_stb)&&(~i_wb_stall)&&(~i_wb_ack)) //&&(o_wb_cyc)
r_acks_waiting <= r_acks_waiting + {{(LGCACHELEN){1'b0}},1'b1};
else if ((i_wb_ack)&&((~o_wb_stb)||(i_wb_stall))) //&&(o_wb_cyc)
r_acks_waiting <= r_acks_waiting + {(LGCACHELEN+1){1'b1}}; // - 1;
 
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
cache[r_nvalid[(LGCACHELEN-1):0]+w_cache_offset]
<= i_wb_data;
 
initial r_addr_set = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(i_new_pc))
r_addr_set <= 1'b1;
else if (i_clear_cache)
r_addr_set <= 1'b0;
 
// Now, read from the cache
wire w_cv; // Cache valid, address is in the cache
reg r_cv;
assign w_cv = ((r_nvalid != 0)&&(r_addr>=r_cache_base)
&&(r_addr-r_cache_base < bus_nvalid));
always @(posedge i_clk)
r_cv <= (~i_new_pc)&&((w_cv)||((~i_stall_n)&&(r_cv)));
assign o_v = (r_cv)&&(~i_new_pc);
 
always @(posedge i_clk)
if (i_new_pc)
r_addr <= i_pc;
else if ( ((i_stall_n)&&(w_cv)) || ((~i_stall_n)&&(w_cv)&&(r_addr == o_pc)) )
r_addr <= r_addr + {{(AW-1){1'b0}},1'b1};
 
wire [(LGCACHELEN-1):0] c_rdaddr, c_cache_base;
assign c_cache_base = r_cache_base[(LGCACHELEN-1):0];
assign c_rdaddr = r_addr[(LGCACHELEN-1):0]-c_cache_base+w_cache_offset;
always @(posedge i_clk)
if ((~o_v)||((i_stall_n)&&(o_v)))
o_i <= cache[c_rdaddr];
always @(posedge i_clk)
if ((~o_v)||((i_stall_n)&&(o_v)))
o_pc <= r_addr;
 
reg [(AW-1):0] ill_address;
initial ill_address = 0;
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_err))
ill_address <= o_wb_addr - {{(AW-LGCACHELEN-1){1'b0}}, r_acks_waiting};
 
assign o_illegal = (o_pc == ill_address)&&(~i_rst)&&(~i_new_pc)&&(~i_clear_cache);
 
 
endmodule
/rtl/cpu/zipsystem.v
0,0 → 1,823
///////////////////////////////////////////////////////////////////////////
//
// Filename: zipsystem.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: This portion of the ZIP CPU implements a number of soft
// peripherals to the CPU nearby its CORE. The functionality
// sits on the data bus, and does not include any true
// external hardware peripherals. The peripherals included here
// include:
//
//
// Local interrupt controller--for any/all of the interrupts generated
// here. This would include a pin for interrupts generated
// elsewhere, so this interrupt controller could be a master
// handling all interrupts. My interrupt controller would work
// for this purpose.
//
// The ZIP-CPU supports only one interrupt because, as I understand
// modern systems (Linux), they tend to send all interrupts to the
// same interrupt vector anyway. Hence, that's what we do here.
//
// Bus Error interrupts -- generates an interrupt any time the wishbone
// bus produces an error on a given access, for whatever purpose
// also records the address on the bus at the time of the error.
//
// Trap instructions
// Writing to this "register" will always create an interrupt.
// After the interrupt, this register may be read to see what
// value had been written to it.
//
// Bit reverse register ... ?
//
// (Potentially an eventual floating point co-processor ...)
//
// Real-time clock
//
// Interval timer(s) (Count down from fixed value, and either stop on
// zero, or issue an interrupt and restart automatically on zero)
// These can be implemented as watchdog timers if desired--the
// only difference is that a watchdog timer's interrupt feeds the
// reset line instead of the processor interrupt line.
//
// Watch-dog timer: this is the same as an interval timer, only it's
// interrupt/time-out line is wired to the reset line instead of
// the interrupt line of the CPU.
//
// ROM Memory map
// Set a register to control this map, and a DMA will begin to
// fill this memory from a slower FLASH. Once filled, accesses
// will be from this memory instead of
//
//
// Doing some market comparison, let's look at what peripherals a TI
// MSP430 might offer: MSP's may have I2C ports, SPI, UART, DMA, ADC,
// Comparators, 16,32-bit timers, 16x16 or 32x32 timers, AES, BSL,
// brown-out-reset(s), real-time-clocks, temperature sensors, USB ports,
// Spi-Bi-Wire, UART Boot-strap Loader (BSL), programmable digital I/O,
// watchdog-timers,
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
`include "cpudefs.v"
//
// While I hate adding delays to any bus access, this next delay is required
// to make timing close in my Basys-3 design.
`define DELAY_DBG_BUS
// On my previous version, I needed to add a delay to access the external
// bus. Activate the define below and that delay will be put back into place.
// This particular version no longer needs the delay in order to run at
// 100 MHz. Timing indicates I may even run this at 250 MHz without the
// delay too, so we're doing better. To get rid of this, I placed the logic
// determining whether or not I was accessing the local system bus one clock
// earlier, or into the memops.v file. This also required my wishbone bus
// arbiter to maintain the bus selection as well, so that got updated ...
// you get the picture. But, the bottom line is that I no longer need this
// delay.
//
// `define DELAY_EXT_BUS // Required no longer!
//
//
// If space is tight, you might not wish to have your performance and
// accounting counters, so let's make those optional here
// Without this flag, Slice LUT count is 3315 (ZipSystem),2432 (ZipCPU)
// When including counters,
// Slice LUTs ZipSystem ZipCPU
// With Counters 3315 2432
// Without Counters 2796 2046
 
//
// Now, where am I placing all of my peripherals?
`define PERIPHBASE 32'hc0000000
`define INTCTRL 5'h0 //
`define WATCHDOG 5'h1 // Interrupt generates reset signal
`define BUSWATCHDOG 5'h2 // Sets IVEC[0]
`define CTRINT 5'h3 // Sets IVEC[5]
`define TIMER_A 5'h4 // Sets IVEC[4]
`define TIMER_B 5'h5 // Sets IVEC[3]
`define TIMER_C 5'h6 // Sets IVEC[2]
`define JIFFIES 5'h7 // Sets IVEC[1]
 
 
`ifdef INCLUDE_ACCOUNTING_COUNTERS
`define MSTR_TASK_CTR 5'h08
`define MSTR_MSTL_CTR 5'h09
`define MSTR_PSTL_CTR 5'h0a
`define MSTR_INST_CTR 5'h0b
`define USER_TASK_CTR 5'h0c
`define USER_MSTL_CTR 5'h0d
`define USER_PSTL_CTR 5'h0e
`define USER_INST_CTR 5'h0f
`endif
 
// Although I have a hole at 5'h2, the DMA controller requires four wishbone
// addresses, therefore we place it by itself and expand our address bus
// width here by another bit.
`define DMAC 5'h10
 
// `define RTC_CLOCK 32'hc0000008 // A global something
// `define BITREV 32'hc0000003
//
// DBGCTRL
// 10 HALT
// 9 HALT(ED)
// 8 STEP (W=1 steps, and returns to halted)
// 7 INTERRUPT-FLAG
// 6 RESET_FLAG
// ADDRESS:
// 5 PERIPHERAL-BIT
// [4:0] REGISTER-ADDR
// DBGDATA
// read/writes internal registers
//
//
//
module zipsystem(i_clk, i_rst,
// Wishbone master interface from the CPU
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_data, i_wb_err,
// Incoming interrupts
i_ext_int,
// Our one outgoing interrupt
o_ext_int,
// Wishbone slave interface for debugging purposes
i_dbg_cyc, i_dbg_stb, i_dbg_we, i_dbg_addr, i_dbg_data,
o_dbg_ack, o_dbg_stall, o_dbg_data
`ifdef DEBUG_SCOPE
, o_cpu_debug
`endif
);
parameter RESET_ADDRESS=24'h0100000, ADDRESS_WIDTH=24,
LGICACHE=10, START_HALTED=1, EXTERNAL_INTERRUPTS=1,
`ifdef OPT_MULTIPLY
IMPLEMENT_MPY = `OPT_MULTIPLY,
`else
IMPLEMENT_MPY = 0,
`endif
`ifdef OPT_DIVIDE
IMPLEMENT_DIVIDE=1,
`else
IMPLEMENT_DIVIDE=0,
`endif
`ifdef OPT_IMPLEMENT_FPU
IMPLEMENT_FPU=1,
`else
IMPLEMENT_FPU=0,
`endif
IMPLEMENT_LOCK=1,
HIGHSPEED_CPU=0,
// Derived parameters
AW=ADDRESS_WIDTH;
input i_clk, i_rst;
// Wishbone master
output wire o_wb_cyc, o_wb_stb, o_wb_we;
output wire [(AW-1):0] o_wb_addr;
output wire [31:0] o_wb_data;
input i_wb_ack, i_wb_stall;
input [31:0] i_wb_data;
input i_wb_err;
// Incoming interrupts
input [(EXTERNAL_INTERRUPTS-1):0] i_ext_int;
// Outgoing interrupt
output wire o_ext_int;
// Wishbone slave
input i_dbg_cyc, i_dbg_stb, i_dbg_we, i_dbg_addr;
input [31:0] i_dbg_data;
output wire o_dbg_ack;
output wire o_dbg_stall;
output wire [31:0] o_dbg_data;
//
`ifdef DEBUG_SCOPE
output wire [31:0] o_cpu_debug;
`endif
 
wire [31:0] ext_idata;
 
// Handle our interrupt vector generation/coordination
wire [14:0] main_int_vector, alt_int_vector;
wire ctri_int, tma_int, tmb_int, tmc_int, jif_int, dmac_int;
wire mtc_int, moc_int, mpc_int, mic_int,
utc_int, uoc_int, upc_int, uic_int;
generate
if (EXTERNAL_INTERRUPTS < 9)
assign main_int_vector = { {(9-EXTERNAL_INTERRUPTS){1'b0}},
i_ext_int, ctri_int,
tma_int, tmb_int, tmc_int,
jif_int, dmac_int };
else
assign main_int_vector = { i_ext_int[8:0], ctri_int,
tma_int, tmb_int, tmc_int,
jif_int, dmac_int };
endgenerate
generate
if (EXTERNAL_INTERRUPTS <= 9)
`ifdef INCLUDE_ACCOUNTING_COUNTERS
assign alt_int_vector = { 7'h00,
mtc_int, moc_int, mpc_int, mic_int,
utc_int, uoc_int, upc_int, uic_int };
`else
assign alt_int_vector = { 15'h00 };
`endif
else
`ifdef INCLUDE_ACCOUNTING_COUNTERS
assign alt_int_vector = { {(7-(EXTERNAL_INTERRUPTS-9)){1'b0}},
i_ext_int[(EXTERNAL_INTERRUPTS-1):9],
mtc_int, moc_int, mpc_int, mic_int,
utc_int, uoc_int, upc_int, uic_int };
`else
assign alt_int_vector = { {(15-(EXTERNAL_INTERRUPTS-9)){1'b0}},
i_ext_int[(EXTERNAL_INTERRUPTS-1):9] };
`endif
endgenerate
 
// Delay the debug port by one clock, to meet timing requirements
wire dbg_cyc, dbg_stb, dbg_we, dbg_addr, dbg_stall;
wire [31:0] dbg_idata, dbg_odata;
reg dbg_ack;
`ifdef DELAY_DBG_BUS
wire dbg_err, no_dbg_err;
assign dbg_err = 1'b0;
busdelay #(1,32) wbdelay(i_clk,
i_dbg_cyc, i_dbg_stb, i_dbg_we, i_dbg_addr, i_dbg_data,
o_dbg_ack, o_dbg_stall, o_dbg_data, no_dbg_err,
dbg_cyc, dbg_stb, dbg_we, dbg_addr, dbg_idata,
dbg_ack, dbg_stall, dbg_odata, dbg_err);
`else
assign dbg_cyc = i_dbg_cyc;
assign dbg_stb = i_dbg_stb;
assign dbg_we = i_dbg_we;
assign dbg_addr = i_dbg_addr;
assign dbg_idata = i_dbg_data;
assign o_dbg_ack = dbg_ack;
assign o_dbg_stall = dbg_stall;
assign o_dbg_data = dbg_odata;
`endif
 
//
//
//
wire sys_cyc, sys_stb, sys_we;
wire [4:0] sys_addr;
wire [(AW-1):0] cpu_addr;
wire [31:0] sys_data;
wire sys_ack, sys_stall;
 
//
// The external debug interface
//
// We offer only a limited interface here, requiring a pre-register
// write to set the local address. This interface allows access to
// the Zip System on a debug basis only, and not to the rest of the
// wishbone bus. Further, to access these registers, the control
// register must first be accessed to both stop the CPU and to
// set the following address in question. Hence all accesses require
// two accesses: write the address to the control register (and halt
// the CPU if not halted), then read/write the data from the data
// register.
//
wire cpu_break, dbg_cmd_write;
reg cmd_reset, cmd_halt, cmd_step, cmd_clear_pf_cache;
reg [5:0] cmd_addr;
wire [3:0] cpu_dbg_cc;
assign dbg_cmd_write = (dbg_cyc)&&(dbg_stb)&&(dbg_we)&&(~dbg_addr);
//
initial cmd_reset = 1'b1;
always @(posedge i_clk)
cmd_reset <= ((dbg_cmd_write)&&(dbg_idata[6]));
//
initial cmd_halt = START_HALTED;
always @(posedge i_clk)
if (i_rst)
cmd_halt <= (START_HALTED == 1)? 1'b1 : 1'b0;
else if (dbg_cmd_write)
cmd_halt <= ((dbg_idata[10])||(dbg_idata[8]));
else if ((cmd_step)||(cpu_break))
cmd_halt <= 1'b1;
 
initial cmd_clear_pf_cache = 1'b0;
always @(posedge i_clk)
cmd_clear_pf_cache = (~i_rst)&&(dbg_cmd_write)
&&((dbg_idata[11])||(dbg_idata[6]));
//
initial cmd_step = 1'b0;
always @(posedge i_clk)
cmd_step <= (dbg_cmd_write)&&(dbg_idata[8]);
//
always @(posedge i_clk)
if (dbg_cmd_write)
cmd_addr <= dbg_idata[5:0];
 
wire cpu_reset;
assign cpu_reset = (cmd_reset)||(wdt_reset)||(i_rst);
 
wire cpu_halt, cpu_dbg_stall;
assign cpu_halt = (i_rst)||((cmd_halt)&&(~cmd_step));
wire [31:0] pic_data;
wire [31:0] cmd_data;
// Values:
// 0x0003f -> cmd_addr mask
// 0x00040 -> reset
// 0x00080 -> PIC interrrupt pending
// 0x00100 -> cmd_step
// 0x00200 -> cmd_stall
// 0x00400 -> cmd_halt
// 0x00800 -> cmd_clear_pf_cache
// 0x01000 -> cc.sleep
// 0x02000 -> cc.gie
// 0x04000 -> External (PIC) interrupt line is high
// Other external interrupts follow
generate
if (EXTERNAL_INTERRUPTS < 16)
assign cmd_data = { {(16-EXTERNAL_INTERRUPTS){1'b0}},
i_ext_int,
cpu_dbg_cc, // 4 bits
1'b0, cmd_halt, (~cpu_dbg_stall), 1'b0,
pic_data[15], cpu_reset, cmd_addr };
else
assign cmd_data = { i_ext_int[15:0], cpu_dbg_cc,
1'b0, cmd_halt, (~cpu_dbg_stall), 1'b0,
pic_data[15], cpu_reset, cmd_addr };
endgenerate
 
wire cpu_gie;
assign cpu_gie = cpu_dbg_cc[1];
 
//
// The WATCHDOG Timer
//
wire wdt_ack, wdt_stall, wdt_reset;
wire [31:0] wdt_data;
ziptimer #(32,31,0)
watchdog(i_clk, cpu_reset, ~cmd_halt,
sys_cyc, ((sys_stb)&&(sys_addr == `WATCHDOG)), sys_we,
sys_data,
wdt_ack, wdt_stall, wdt_data, wdt_reset);
 
//
// Position two, a second watchdog timer--this time for the wishbone
// bus, in order to tell/find wishbone bus lockups. In its current
// configuration, it cannot be configured and all bus accesses must
// take less than the number written to this register.
//
reg wdbus_ack;
reg [(AW-1):0] r_wdbus_data;
wire [31:0] wdbus_data;
wire [14:0] wdbus_ignored_data;
wire reset_wdbus_timer, wdbus_int;
assign reset_wdbus_timer = ((o_wb_cyc)&&((o_wb_stb)||(i_wb_ack)));
wbwatchdog #(14) watchbus(i_clk,(cpu_reset)||(reset_wdbus_timer),
o_wb_cyc, 14'h2000, wdbus_int);
initial r_wdbus_data = 0;
always @(posedge i_clk)
if ((wdbus_int)||(cpu_ext_err))
r_wdbus_data = o_wb_addr;
assign wdbus_data = { {(32-AW){1'b0}}, r_wdbus_data };
initial wdbus_ack = 1'b0;
always @(posedge i_clk)
wdbus_ack <= ((sys_cyc)&&(sys_stb)&&(sys_addr == 5'h02));
 
// Counters -- for performance measurement and accounting
//
// Here's the stuff we'll be counting ....
//
wire cpu_op_stall, cpu_pf_stall, cpu_i_count;
 
`ifdef INCLUDE_ACCOUNTING_COUNTERS
//
// The master counters will, in general, not be reset. They'll be used
// for an overall counter.
//
// Master task counter
wire mtc_ack, mtc_stall;
wire [31:0] mtc_data;
zipcounter mtask_ctr(i_clk, (~cpu_halt), sys_cyc,
(sys_stb)&&(sys_addr == `MSTR_TASK_CTR),
sys_we, sys_data,
mtc_ack, mtc_stall, mtc_data, mtc_int);
 
// Master Operand Stall counter
wire moc_ack, moc_stall;
wire [31:0] moc_data;
zipcounter mmstall_ctr(i_clk,(cpu_op_stall), sys_cyc,
(sys_stb)&&(sys_addr == `MSTR_MSTL_CTR),
sys_we, sys_data,
moc_ack, moc_stall, moc_data, moc_int);
 
// Master PreFetch-Stall counter
wire mpc_ack, mpc_stall;
wire [31:0] mpc_data;
zipcounter mpstall_ctr(i_clk,(cpu_pf_stall), sys_cyc,
(sys_stb)&&(sys_addr == `MSTR_PSTL_CTR),
sys_we, sys_data,
mpc_ack, mpc_stall, mpc_data, mpc_int);
 
// Master Instruction counter
wire mic_ack, mic_stall;
wire [31:0] mic_data;
zipcounter mins_ctr(i_clk,(cpu_i_count), sys_cyc,
(sys_stb)&&(sys_addr == `MSTR_INST_CTR),
sys_we, sys_data,
mic_ack, mic_stall, mic_data, mic_int);
 
//
// The user counters are different from those of the master. They will
// be reset any time a task is given control of the CPU.
//
// User task counter
wire utc_ack, utc_stall;
wire [31:0] utc_data;
zipcounter utask_ctr(i_clk,(~cpu_halt)&&(cpu_gie), sys_cyc,
(sys_stb)&&(sys_addr == `USER_TASK_CTR),
sys_we, sys_data,
utc_ack, utc_stall, utc_data, utc_int);
 
// User Op-Stall counter
wire uoc_ack, uoc_stall;
wire [31:0] uoc_data;
zipcounter umstall_ctr(i_clk,(cpu_op_stall)&&(cpu_gie), sys_cyc,
(sys_stb)&&(sys_addr == `USER_MSTL_CTR),
sys_we, sys_data,
uoc_ack, uoc_stall, uoc_data, uoc_int);
 
// User PreFetch-Stall counter
wire upc_ack, upc_stall;
wire [31:0] upc_data;
zipcounter upstall_ctr(i_clk,(cpu_pf_stall)&&(cpu_gie), sys_cyc,
(sys_stb)&&(sys_addr == `USER_PSTL_CTR),
sys_we, sys_data,
upc_ack, upc_stall, upc_data, upc_int);
 
// User instruction counter
wire uic_ack, uic_stall;
wire [31:0] uic_data;
zipcounter uins_ctr(i_clk,(cpu_i_count)&&(cpu_gie), sys_cyc,
(sys_stb)&&(sys_addr == `USER_INST_CTR),
sys_we, sys_data,
uic_ack, uic_stall, uic_data, uic_int);
 
// A little bit of pre-cleanup (actr = accounting counters)
wire actr_ack, actr_stall;
wire [31:0] actr_data;
assign actr_ack = ((mtc_ack | moc_ack | mpc_ack | mic_ack)
|(utc_ack | uoc_ack | upc_ack | uic_ack));
assign actr_stall = ((mtc_stall | moc_stall | mpc_stall | mic_stall)
|(utc_stall | uoc_stall | upc_stall|uic_stall));
assign actr_data = ((mtc_ack) ? mtc_data
: ((moc_ack) ? moc_data
: ((mpc_ack) ? mpc_data
: ((mic_ack) ? mic_data
: ((utc_ack) ? utc_data
: ((uoc_ack) ? uoc_data
: ((upc_ack) ? upc_data
: uic_data)))))));
`else // INCLUDE_ACCOUNTING_COUNTERS
reg actr_ack;
wire actr_stall;
wire [31:0] actr_data;
assign actr_stall = 1'b0;
assign actr_data = 32'h0000;
 
assign mtc_int = 1'b0;
assign moc_int = 1'b0;
assign mpc_int = 1'b0;
assign mic_int = 1'b0;
assign utc_int = 1'b0;
assign uoc_int = 1'b0;
assign upc_int = 1'b0;
assign uic_int = 1'b0;
 
always @(posedge i_clk)
actr_ack <= (sys_stb)&&(sys_addr[4:3] == 2'b01);
`endif // INCLUDE_ACCOUNTING_COUNTERS
 
//
// The DMA Controller
//
wire dmac_stb, dc_err;
wire [31:0] dmac_data;
wire dmac_ack, dmac_stall;
wire dc_cyc, dc_stb, dc_we, dc_ack, dc_stall;
wire [31:0] dc_data;
wire [(AW-1):0] dc_addr;
wire cpu_gbl_cyc;
assign dmac_stb = (sys_stb)&&(sys_addr[4]);
`ifdef INCLUDE_DMA_CONTROLLER
wbdmac #(AW) dma_controller(i_clk, cpu_reset,
sys_cyc, dmac_stb, sys_we,
sys_addr[1:0], sys_data,
dmac_ack, dmac_stall, dmac_data,
// Need the outgoing DMAC wishbone bus
dc_cyc, dc_stb, dc_we, dc_addr, dc_data,
dc_ack, dc_stall, ext_idata, dc_err,
// External device interrupts
{ 1'b0, alt_int_vector, 1'b0,
main_int_vector[14:1], 1'b0 },
// DMAC interrupt, for upon completion
dmac_int);
`else
reg r_dmac_ack;
always @(posedge i_clk)
r_dmac_ack <= (sys_cyc)&&(dmac_stb);
assign dmac_ack = r_dmac_ack;
assign dmac_data = 32'h000;
assign dmac_stall = 1'b0;
 
assign dc_cyc = 1'b0;
assign dc_stb = 1'b0;
assign dc_we = 1'b0;
assign dc_addr = { (AW) {1'b0} };
assign dc_data = 32'h00;
 
assign dmac_int = 1'b0;
`endif
 
wire ctri_sel, ctri_stall;
reg ctri_ack;
wire [31:0] ctri_data;
assign ctri_sel = (sys_cyc)&&(sys_stb)&&(sys_addr == `CTRINT);
always @(posedge i_clk)
ctri_ack <= ctri_sel;
assign ctri_stall = 1'b0;
`ifdef INCLUDE_ACCOUNTING_COUNTERS
//
// Counter Interrupt controller
//
generate
if (EXTERNAL_INTERRUPTS <= 9)
begin
icontrol #(8) ctri(i_clk, cpu_reset, (ctri_sel),
sys_data, ctri_data, alt_int_vector[7:0],
ctri_int);
end else begin
icontrol #(8+(EXTERNAL_INTERRUPTS-9))
ctri(i_clk, cpu_reset, (ctri_sel),
sys_data, ctri_data,
alt_int_vector[(EXTERNAL_INTERRUPTS-2):0],
ctri_int);
end endgenerate
 
`else // INCLUDE_ACCOUNTING_COUNTERS
 
generate
if (EXTERNAL_INTERRUPTS <= 9)
begin
assign ctri_stall = 1'b0;
assign ctri_data = 32'h0000;
assign ctri_int = 1'b0;
end else begin
icontrol #(EXTERNAL_INTERRUPTS-9)
ctri(i_clk, cpu_reset, (ctri_sel),
sys_data, ctri_data,
alt_int_vector[(EXTERNAL_INTERRUPTS-10):0],
ctri_int);
end endgenerate
`endif // INCLUDE_ACCOUNTING_COUNTERS
 
 
//
// Timer A
//
wire tma_ack, tma_stall;
wire [31:0] tma_data;
ziptimer timer_a(i_clk, cpu_reset, ~cmd_halt,
sys_cyc, (sys_stb)&&(sys_addr == `TIMER_A), sys_we,
sys_data,
tma_ack, tma_stall, tma_data, tma_int);
 
//
// Timer B
//
wire tmb_ack, tmb_stall;
wire [31:0] tmb_data;
ziptimer timer_b(i_clk, cpu_reset, ~cmd_halt,
sys_cyc, (sys_stb)&&(sys_addr == `TIMER_B), sys_we,
sys_data,
tmb_ack, tmb_stall, tmb_data, tmb_int);
 
//
// Timer C
//
wire tmc_ack, tmc_stall;
wire [31:0] tmc_data;
ziptimer timer_c(i_clk, cpu_reset, ~cmd_halt,
sys_cyc, (sys_stb)&&(sys_addr == `TIMER_C), sys_we,
sys_data,
tmc_ack, tmc_stall, tmc_data, tmc_int);
 
//
// JIFFIES
//
wire jif_ack, jif_stall;
wire [31:0] jif_data;
zipjiffies jiffies(i_clk, ~cmd_halt,
sys_cyc, (sys_stb)&&(sys_addr == `JIFFIES), sys_we,
sys_data,
jif_ack, jif_stall, jif_data, jif_int);
 
//
// The programmable interrupt controller peripheral
//
wire pic_interrupt;
generate
if (EXTERNAL_INTERRUPTS < 9)
begin
icontrol #(6+EXTERNAL_INTERRUPTS) pic(i_clk, cpu_reset,
(sys_cyc)&&(sys_stb)&&(sys_we)
&&(sys_addr==`INTCTRL),
sys_data, pic_data,
main_int_vector[(6+EXTERNAL_INTERRUPTS-1):0], pic_interrupt);
end else begin
icontrol #(15) pic(i_clk, cpu_reset,
(sys_cyc)&&(sys_stb)&&(sys_we)
&&(sys_addr==`INTCTRL),
sys_data, pic_data,
main_int_vector[14:0], pic_interrupt);
end endgenerate
 
wire pic_stall;
assign pic_stall = 1'b0;
reg pic_ack;
always @(posedge i_clk)
pic_ack <= (sys_cyc)&&(sys_stb)&&(sys_addr == `INTCTRL);
 
//
// The CPU itself
//
wire cpu_gbl_stb, cpu_lcl_cyc, cpu_lcl_stb,
cpu_we, cpu_dbg_we;
wire [31:0] cpu_data, wb_data;
wire cpu_ack, cpu_stall, cpu_err;
wire [31:0] cpu_dbg_data;
assign cpu_dbg_we = ((dbg_cyc)&&(dbg_stb)&&(~cmd_addr[5])
&&(dbg_we)&&(dbg_addr));
 
generate
if (HIGHSPEED_CPU==0)
begin
zipcpu #(
.RESET_ADDRESS(RESET_ADDRESS),
.ADDRESS_WIDTH(ADDRESS_WIDTH),
.LGICACHE(LGICACHE),
.IMPLEMENT_MPY(IMPLEMENT_MPY),
.IMPLEMENT_DIVIDE(IMPLEMENT_DIVIDE),
.IMPLEMENT_FPU(IMPLEMENT_FPU),
.IMPLEMENT_LOCK(IMPLEMENT_LOCK)
)
thecpu(i_clk, cpu_reset, pic_interrupt,
cpu_halt, cmd_clear_pf_cache, cmd_addr[4:0], cpu_dbg_we,
dbg_idata, cpu_dbg_stall, cpu_dbg_data,
cpu_dbg_cc, cpu_break,
cpu_gbl_cyc, cpu_gbl_stb,
cpu_lcl_cyc, cpu_lcl_stb,
cpu_we, cpu_addr, cpu_data,
cpu_ack, cpu_stall, wb_data,
cpu_err,
cpu_op_stall, cpu_pf_stall, cpu_i_count
`ifdef DEBUG_SCOPE
, o_cpu_debug
`endif
);
end else begin
zipcpu #(
.RESET_ADDRESS(RESET_ADDRESS),
.ADDRESS_WIDTH(ADDRESS_WIDTH),
.LGICACHE(LGICACHE),
.IMPLEMENT_MPY(IMPLEMENT_MPY),
.IMPLEMENT_DIVIDE(IMPLEMENT_DIVIDE),
.IMPLEMENT_FPU(IMPLEMENT_FPU),
.IMPLEMENT_LOCK(IMPLEMENT_LOCK)
)
thecpu(i_clk, cpu_reset, pic_interrupt,
cpu_halt, cmd_clear_pf_cache, cmd_addr[4:0], cpu_dbg_we,
dbg_idata, cpu_dbg_stall, cpu_dbg_data,
cpu_dbg_cc, cpu_break,
cpu_gbl_cyc, cpu_gbl_stb,
cpu_lcl_cyc, cpu_lcl_stb,
cpu_we, cpu_addr, cpu_data,
cpu_ack, cpu_stall, wb_data,
cpu_err,
cpu_op_stall, cpu_pf_stall, cpu_i_count
`ifdef DEBUG_SCOPE
, o_cpu_debug
`endif
);
end endgenerate
 
// Now, arbitrate the bus ... first for the local peripherals
// For the debugger to have access to the local system bus, the
// following must be true:
// (dbg_cyc) The debugger must request the bus
// (~cpu_lcl_cyc) The CPU cannot be using it (CPU gets priority)
// (dbg_addr) The debugger must be requesting its data
// register, not just the control register
// and one of two other things. Either
// ((cpu_halt)&&(~cpu_dbg_stall)) the CPU is completely halted,
// or
// (~cmd_addr[5]) we are trying to read a CPU register
// while in motion. Let the user beware that,
// by not waiting for the CPU to fully halt,
// his results may not be what he expects.
//
wire sys_dbg_cyc = ((dbg_cyc)&&(~cpu_lcl_cyc)&&(dbg_addr))
&&(((cpu_halt)&&(~cpu_dbg_stall))
||(~cmd_addr[5]));
assign sys_cyc = (cpu_lcl_cyc)||(sys_dbg_cyc);
assign sys_stb = (cpu_lcl_cyc)
? (cpu_lcl_stb)
: ((dbg_stb)&&(dbg_addr)&&(cmd_addr[5]));
 
assign sys_we = (cpu_lcl_cyc) ? cpu_we : dbg_we;
assign sys_addr= (cpu_lcl_cyc) ? cpu_addr[4:0] : cmd_addr[4:0];
assign sys_data= (cpu_lcl_cyc) ? cpu_data : dbg_idata;
 
// Return debug response values
assign dbg_odata = (~dbg_addr)?cmd_data
:((~cmd_addr[5])?cpu_dbg_data : wb_data);
initial dbg_ack = 1'b0;
always @(posedge i_clk)
dbg_ack <= (dbg_cyc)&&(dbg_stb)&&(~dbg_stall);
assign dbg_stall=(dbg_cyc)&&((~sys_dbg_cyc)||(sys_stall))&&(dbg_addr);
 
// Now for the external wishbone bus
// Need to arbitrate between the flash cache and the CPU
// The way this works, though, the CPU will stall once the flash
// cache gets access to the bus--the CPU will be stuck until the
// flash cache is finished with the bus.
wire ext_cyc, ext_stb, ext_we, ext_err;
wire cpu_ext_ack, cpu_ext_stall, ext_ack, ext_stall,
cpu_ext_err;
wire [(AW-1):0] ext_addr;
wire [31:0] ext_odata;
wbpriarbiter #(32,AW) dmacvcpu(i_clk,
cpu_gbl_cyc, cpu_gbl_stb, cpu_we, cpu_addr, cpu_data,
cpu_ext_ack, cpu_ext_stall, cpu_ext_err,
dc_cyc, dc_stb, dc_we, dc_addr, dc_data,
dc_ack, dc_stall, dc_err,
ext_cyc, ext_stb, ext_we, ext_addr, ext_odata,
ext_ack, ext_stall, ext_err);
 
`ifdef DELAY_EXT_BUS
busdelay #(AW,32) extbus(i_clk,
ext_cyc, ext_stb, ext_we, ext_addr, ext_odata,
ext_ack, ext_stall, ext_idata, ext_err,
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_data, (i_wb_err)||(wdbus_int));
`else
assign o_wb_cyc = ext_cyc;
assign o_wb_stb = ext_stb;
assign o_wb_we = ext_we;
assign o_wb_addr = ext_addr;
assign o_wb_data = ext_odata;
assign ext_ack = i_wb_ack;
assign ext_stall = i_wb_stall;
assign ext_idata = i_wb_data;
assign ext_err = (i_wb_err)||(wdbus_int);
`endif
 
wire tmr_ack;
assign tmr_ack = (tma_ack|tmb_ack|tmc_ack|jif_ack);
wire [31:0] tmr_data;
assign tmr_data = (tma_ack)?tma_data
:(tmb_ack ? tmb_data
:(tmc_ack ? tmc_data
:jif_data));
assign wb_data = (tmr_ack|wdt_ack)?((tmr_ack)?tmr_data:wdt_data)
:((actr_ack|dmac_ack)?((actr_ack)?actr_data:dmac_data)
:((pic_ack|ctri_ack)?((pic_ack)?pic_data:ctri_data)
:((wdbus_ack)?wdbus_data:(ext_idata))));
 
assign sys_stall = (tma_stall | tmb_stall | tmc_stall | jif_stall
| wdt_stall | ctri_stall | actr_stall
| pic_stall | dmac_stall);
assign cpu_stall = (sys_stall)|(cpu_ext_stall);
assign sys_ack = (tmr_ack|wdt_ack|ctri_ack|actr_ack|pic_ack|dmac_ack|wdbus_ack);
assign cpu_ack = (sys_ack)||(cpu_ext_ack);
assign cpu_err = (cpu_ext_err)&&(cpu_gbl_cyc);
 
assign o_ext_int = (cmd_halt) && (~cpu_stall);
 
endmodule
/rtl/cpu/busdelay.v
0,0 → 1,96
///////////////////////////////////////////////////////////////////////////
//
// Filename: busdelay.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: Delay any access to the wishbone bus by a single clock. This
// particular version of the busdelay builds off of some previous
// work, but also delays and buffers the stall line as well. It is
// designed to allow pipelined accesses (1 access/clock) to still work,
// while also providing for single accesses.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
module busdelay(i_clk,
// The input bus
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_wb_err,
// The delayed bus
o_dly_cyc, o_dly_stb, o_dly_we, o_dly_addr, o_dly_data,
i_dly_ack, i_dly_stall, i_dly_data, i_dly_err);
parameter AW=32, DW=32;
input i_clk;
// Input/master bus
input i_wb_cyc, i_wb_stb, i_wb_we;
input [(AW-1):0] i_wb_addr;
input [(DW-1):0] i_wb_data;
output reg o_wb_ack;
output reg o_wb_stall;
output reg [(DW-1):0] o_wb_data;
output reg o_wb_err;
// Delayed bus
output reg o_dly_cyc, o_dly_we;
output wire o_dly_stb;
output reg [(AW-1):0] o_dly_addr;
output reg [(DW-1):0] o_dly_data;
input i_dly_ack;
input i_dly_stall;
input [(DW-1):0] i_dly_data;
input i_dly_err;
 
reg loaded;
initial o_dly_cyc = 1'b0;
initial loaded = 1'b0;
 
always @(posedge i_clk)
o_wb_stall <= (loaded)&&(i_dly_stall);
 
initial o_dly_cyc = 1'b0;
always @(posedge i_clk)
o_dly_cyc <= (i_wb_cyc);
// Add the i_wb_cyc criteria here, so we can simplify the o_wb_stall
// criteria below, which would otherwise *and* these two.
always @(posedge i_clk)
loaded <= (i_wb_stb)||((loaded)&&(i_dly_stall)&&(~i_dly_err)&&(i_wb_cyc));
assign o_dly_stb = loaded;
always @(posedge i_clk)
if (~i_dly_stall)
o_dly_we <= i_wb_we;
always @(posedge i_clk)
if (~i_dly_stall)
o_dly_addr<= i_wb_addr;
always @(posedge i_clk)
if (~i_dly_stall)
o_dly_data <= i_wb_data;
always @(posedge i_clk)
o_wb_ack <= (i_dly_ack)&&(o_dly_cyc)&&(i_wb_cyc);
always @(posedge i_clk)
o_wb_data <= i_dly_data;
 
always @(posedge i_clk)
o_wb_err <= (i_dly_err)&&(o_dly_cyc)&&(i_wb_cyc);
 
endmodule
/rtl/cpu/cpuops.v
0,0 → 1,368
///////////////////////////////////////////////////////////////////////////
//
// Filename: cpuops.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: This supports the instruction set reordering of operations
// created by the second generation instruction set, as well as
// the new operations of POPC (population count) and BREV (bit reversal).
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
`define LONG_MPY
module cpuops(i_clk,i_rst, i_ce, i_valid, i_op, i_a, i_b, o_c, o_f, o_valid,
o_illegal, o_busy);
parameter IMPLEMENT_MPY = 1;
input i_clk, i_rst, i_ce;
input [3:0] i_op;
input [31:0] i_a, i_b;
input i_valid;
output reg [31:0] o_c;
output wire [3:0] o_f;
output reg o_valid;
output wire o_illegal;
output wire o_busy;
 
// Rotate-left pre-logic
wire [63:0] w_rol_tmp;
assign w_rol_tmp = { i_a, i_a } << i_b[4:0];
wire [31:0] w_rol_result;
assign w_rol_result = w_rol_tmp[63:32]; // Won't set flags
 
// Shift register pre-logic
wire [32:0] w_lsr_result, w_asr_result, w_lsl_result;
wire signed [32:0] w_pre_asr_input, w_pre_asr_shifted;
assign w_pre_asr_input = { i_a, 1'b0 };
assign w_pre_asr_shifted = w_pre_asr_input >>> i_b[4:0];
assign w_asr_result = (|i_b[31:5])? {(33){i_a[31]}}
: w_pre_asr_shifted;// ASR
assign w_lsr_result = ((|i_b[31:6])||(i_b[5]&&(i_b[4:0]!=0)))? 33'h00
:((i_b[5])?{32'h0,i_a[31]}
: ( { i_a, 1'b0 } >> (i_b[4:0]) ));// LSR
assign w_lsl_result = ((|i_b[31:6])||(i_b[5]&&(i_b[4:0]!=0)))? 33'h00
:((i_b[5])?{i_a[0], 32'h0}
: ({1'b0, i_a } << i_b[4:0])); // LSL
 
// Bit reversal pre-logic
wire [31:0] w_brev_result;
genvar k;
generate
for(k=0; k<32; k=k+1)
begin : bit_reversal_cpuop
assign w_brev_result[k] = i_b[31-k];
end endgenerate
 
// Popcount pre-logic
wire [31:0] w_popc_result;
assign w_popc_result[5:0]=
({5'h0,i_b[ 0]}+{5'h0,i_b[ 1]}+{5'h0,i_b[ 2]}+{5'h0,i_b[ 3]})
+({5'h0,i_b[ 4]}+{5'h0,i_b[ 5]}+{5'h0,i_b[ 6]}+{5'h0,i_b[ 7]})
+({5'h0,i_b[ 8]}+{5'h0,i_b[ 9]}+{5'h0,i_b[10]}+{5'h0,i_b[11]})
+({5'h0,i_b[12]}+{5'h0,i_b[13]}+{5'h0,i_b[14]}+{5'h0,i_b[15]})
+({5'h0,i_b[16]}+{5'h0,i_b[17]}+{5'h0,i_b[18]}+{5'h0,i_b[19]})
+({5'h0,i_b[20]}+{5'h0,i_b[21]}+{5'h0,i_b[22]}+{5'h0,i_b[23]})
+({5'h0,i_b[24]}+{5'h0,i_b[25]}+{5'h0,i_b[26]}+{5'h0,i_b[27]})
+({5'h0,i_b[28]}+{5'h0,i_b[29]}+{5'h0,i_b[30]}+{5'h0,i_b[31]});
assign w_popc_result[31:6] = 26'h00;
 
// Prelogic for our flags registers
wire z, n, v;
reg c, pre_sign, set_ovfl;
always @(posedge i_clk)
if (i_ce) // 1 LUT
set_ovfl =(((i_op==4'h0)&&(i_a[31] != i_b[31]))//SUB&CMP
||((i_op==4'h2)&&(i_a[31] == i_b[31])) // ADD
||(i_op == 4'h6) // LSL
||(i_op == 4'h5)); // LSR
 
`ifdef LONG_MPY
reg mpyhi;
wire mpybusy;
`endif
 
// A 4-way multiplexer can be done in one 6-LUT.
// A 16-way multiplexer can therefore be done in 4x 6-LUT's with
// the Xilinx multiplexer fabric that follows.
// Given that we wish to apply this multiplexer approach to 33-bits,
// this will cost a minimum of 132 6-LUTs.
generate
if (IMPLEMENT_MPY == 0)
begin
always @(posedge i_clk)
if (i_ce)
begin
pre_sign <= (i_a[31]);
c <= 1'b0;
casez(i_op)
4'b0000:{c,o_c } <= {1'b0,i_a}-{1'b0,i_b};// CMP/SUB
4'b0001: o_c <= i_a & i_b; // BTST/And
4'b0010:{c,o_c } <= i_a + i_b; // Add
4'b0011: o_c <= i_a | i_b; // Or
4'b0100: o_c <= i_a ^ i_b; // Xor
4'b0101:{o_c,c } <= w_lsr_result[32:0]; // LSR
4'b0110:{c,o_c } <= w_lsl_result[32:0]; // LSL
4'b0111:{o_c,c } <= w_asr_result[32:0]; // ASR
`ifndef LONG_MPY
4'b1000: o_c <= { i_b[15: 0], i_a[15:0] }; // LODIHI
`endif
4'b1001: o_c <= { i_a[31:16], i_b[15:0] }; // LODILO
// 4'h1010: The unimplemented MPYU,
// 4'h1011: and here for the unimplemented MPYS
4'b1100: o_c <= w_brev_result; // BREV
4'b1101: o_c <= w_popc_result; // POPC
4'b1110: o_c <= w_rol_result; // ROL
default: o_c <= i_b; // MOV, LDI
endcase
end
 
assign o_busy = 1'b0;
 
reg r_illegal;
always @(posedge i_clk)
r_illegal <= (i_ce)&&((i_op == 4'ha)||(i_op == 4'hb)
`ifdef LONG_MPY
||(i_op == 4'h8)
`endif
);
assign o_illegal = r_illegal;
end else begin
//
// Multiply pre-logic
//
`ifdef LONG_MPY
reg [63:0] r_mpy_result;
if (IMPLEMENT_MPY == 1)
begin // Our two clock option (one clock extra)
reg signed [64:0] r_mpy_a_input, r_mpy_b_input;
reg mpypipe, x;
initial mpypipe = 1'b0;
always @(posedge i_clk)
mpypipe <= (i_ce)&&((i_op[3:1]==3'h5)||(i_op[3:0]==4'h8));
always @(posedge i_clk)
if (i_ce)
begin
r_mpy_a_input <= {{(33){(i_a[31])&(i_op[0])}},
i_a[31:0]};
r_mpy_b_input <= {{(33){(i_b[31])&(i_op[0])}},
i_b[31:0]};
end
always @(posedge i_clk)
if (mpypipe)
{x, r_mpy_result} = r_mpy_a_input
* r_mpy_b_input;
always @(posedge i_clk)
if (i_ce)
mpyhi = i_op[1];
assign mpybusy = mpypipe;
end else if (IMPLEMENT_MPY == 2)
begin // The three clock option
reg [31:0] r_mpy_a_input, r_mpy_b_input;
reg r_mpy_signed;
reg [1:0] mpypipe;
 
// First clock, latch in the inputs
always @(posedge i_clk)
begin
// mpypipe indicates we have a multiply in the
// pipeline. In this case, the multiply
// pipeline is a two stage pipeline, so we need
// two bits in the pipe.
mpypipe[0] <= (i_ce)&&((i_op[3:1]==3'h5)
||(i_op[3:0]==4'h8));
mpypipe[1] <= mpypipe[0];
if (i_op[0]) // i.e. if signed multiply
begin
r_mpy_a_input <= {(~i_a[31]),i_a[30:0]};
r_mpy_b_input <= {(~i_b[31]),i_b[30:0]};
end else begin
r_mpy_a_input <= i_a[31:0];
r_mpy_b_input <= i_b[31:0];
end
// The signed bit really only matters in the
// case of 64 bit multiply. We'll keep track
// of it, though, and pretend in all other
// cases.
r_mpy_signed <= i_op[0];
 
if (i_ce)
mpyhi = i_op[1];
end
 
assign mpybusy = |mpypipe;
 
// Second clock, do the multiplies, get the "partial
// products". Here, we break our input up into two
// halves,
//
// A = (2^16 ah + al)
// B = (2^16 bh + bl)
//
// and use these to compute partial products.
//
// AB = (2^32 ah*bh + 2^16 (ah*bl + al*bh) + (al*bl)
//
// Since we're following the FOIL algorithm to get here,
// we'll name these partial products according to FOIL.
//
// The trick is what happens if A or B is signed. In
// those cases, the real value of A will not be given by
// A = (2^16 ah + al)
// but rather
// A = (2^16 ah[31^] + al) - 2^31
// (where we have flipped the sign bit of A)
// and so ...
//
// AB= (2^16 ah + al - 2^31) * (2^16 bh + bl - 2^31)
// = 2^32(ah*bh)
// +2^16 (ah*bl+al*bh)
// +(al*bl)
// - 2^31 (2^16 bh+bl + 2^16 ah+al)
// - 2^62
// = 2^32(ah*bh)
// +2^16 (ah*bl+al*bh)
// +(al*bl)
// - 2^31 (2^16 bh+bl + 2^16 ah+al + 2^31)
//
reg [31:0] pp_f, pp_l; // F and L from FOIL
reg [32:0] pp_oi; // The O and I from FOIL
reg [32:0] pp_s;
always @(posedge i_clk)
begin
pp_f<=r_mpy_a_input[31:16]*r_mpy_b_input[31:16];
pp_oi<=r_mpy_a_input[31:16]*r_mpy_b_input[15: 0]
+ r_mpy_a_input[15: 0]*r_mpy_b_input[31:16];
pp_l<=r_mpy_a_input[15: 0]*r_mpy_b_input[15: 0];
// And a special one for the sign
if (r_mpy_signed)
pp_s <= 32'h8000_0000-(
r_mpy_a_input[31:0]
+ r_mpy_b_input[31:0]);
else
pp_s <= 33'h0;
end
 
// Third clock, add the results and produce a product
always @(posedge i_clk)
begin
r_mpy_result[15:0] <= pp_l[15:0];
r_mpy_result[63:16] <=
{ 32'h00, pp_l[31:16] }
+ { 15'h00, pp_oi }
+ { pp_s, 15'h00 }
+ { pp_f, 16'h00 };
end
end // Fourth clock -- results are available for writeback.
`else
wire signed [16:0] w_mpy_a_input, w_mpy_b_input;
wire [33:0] w_mpy_result;
reg [31:0] r_mpy_result;
assign w_mpy_a_input ={ ((i_a[15])&(i_op[0])), i_a[15:0] };
assign w_mpy_b_input ={ ((i_b[15])&(i_op[0])), i_b[15:0] };
assign w_mpy_result = w_mpy_a_input * w_mpy_b_input;
always @(posedge i_clk)
if (i_ce)
r_mpy_result = w_mpy_result[31:0];
`endif
 
//
// The master ALU case statement
//
always @(posedge i_clk)
if (i_ce)
begin
pre_sign <= (i_a[31]);
c <= 1'b0;
casez(i_op)
4'b0000:{c,o_c } <= {1'b0,i_a}-{1'b0,i_b};// CMP/SUB
4'b0001: o_c <= i_a & i_b; // BTST/And
4'b0010:{c,o_c } <= i_a + i_b; // Add
4'b0011: o_c <= i_a | i_b; // Or
4'b0100: o_c <= i_a ^ i_b; // Xor
4'b0101:{o_c,c } <= w_lsr_result[32:0]; // LSR
4'b0110:{c,o_c } <= w_lsl_result[32:0]; // LSL
4'b0111:{o_c,c } <= w_asr_result[32:0]; // ASR
`ifdef LONG_MPY
4'b1000: o_c <= r_mpy_result[31:0]; // MPY
`else
4'b1000: o_c <= { i_b[15: 0], i_a[15:0] }; // LODIHI
`endif
4'b1001: o_c <= { i_a[31:16], i_b[15:0] }; // LODILO
`ifdef LONG_MPY
4'b1010: o_c <= r_mpy_result[63:32]; // MPYHU
4'b1011: o_c <= r_mpy_result[63:32]; // MPYHS
`else
4'b1010: o_c <= r_mpy_result; // MPYU
4'b1011: o_c <= r_mpy_result; // MPYS
`endif
4'b1100: o_c <= w_brev_result; // BREV
4'b1101: o_c <= w_popc_result; // POPC
4'b1110: o_c <= w_rol_result; // ROL
default: o_c <= i_b; // MOV, LDI
endcase
end else if (r_busy)
`ifdef LONG_MPY
o_c <= (mpyhi)?r_mpy_result[63:32]:r_mpy_result[31:0];
`else
o_c <= r_mpy_result;
`endif
 
reg r_busy;
initial r_busy = 1'b0;
always @(posedge i_clk)
r_busy <= (~i_rst)&&(i_ce)&&(i_valid)
`ifdef LONG_MPY
&&((i_op[3:1] == 3'h5)
||(i_op[3:0] == 4'h8))||mpybusy;
`else
&&(i_op[3:1] == 3'h5);
`endif
 
assign o_busy = r_busy;
 
assign o_illegal = 1'b0;
end endgenerate
 
assign z = (o_c == 32'h0000);
assign n = (o_c[31]);
assign v = (set_ovfl)&&(pre_sign != o_c[31]);
 
assign o_f = { v, n, c, z };
 
initial o_valid = 1'b0;
always @(posedge i_clk)
if (i_rst)
o_valid <= 1'b0;
else
o_valid <= (i_ce)&&(i_valid)
`ifdef LONG_MPY
&&(i_op[3:1] != 3'h5)&&(i_op[3:0] != 4'h8)
||(o_busy)&&(~mpybusy);
`else
&&(i_op[3:1] != 3'h5)||(o_busy);
`endif
endmodule
/rtl/cpu/zipcpu.v
0,0 → 1,1866
///////////////////////////////////////////////////////////////////////////////
//
// Filename: zipcpu.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: This is the top level module holding the core of the Zip CPU
// together. The Zip CPU is designed to be as simple as possible.
// (actual implementation aside ...) The instruction set is about as
// RISC as you can get, there are only 16 instruction types supported.
// Please see the accompanying spec.pdf file for a description of these
// instructions.
//
// All instructions are 32-bits wide. All bus accesses, both address and
// data, are 32-bits over a wishbone bus.
//
// The Zip CPU is fully pipelined with the following pipeline stages:
//
// 1. Prefetch, returns the instruction from memory.
//
// 2. Instruction Decode
//
// 3. Read Operands
//
// 4. Apply Instruction
//
// 4. Write-back Results
//
// Further information about the inner workings of this CPU may be
// found in the spec.pdf file. (The documentation within this file
// had become out of date and out of sync with the spec.pdf, so look
// to the spec.pdf for accurate and up to date information.)
//
//
// In general, the pipelining is controlled by three pieces of logic
// per stage: _ce, _stall, and _valid. _valid means that the stage
// holds a valid instruction. _ce means that the instruction from the
// previous stage is to move into this one, and _stall means that the
// instruction from the previous stage may not move into this one.
// The difference between these control signals allows individual stages
// to propagate instructions independently. In general, the logic works
// as:
//
//
// assign (n)_ce = (n-1)_valid && (~(n)_stall)
//
//
// always @(posedge i_clk)
// if ((i_rst)||(clear_pipeline))
// (n)_valid = 0
// else if (n)_ce
// (n)_valid = 1
// else if (n+1)_ce
// (n)_valid = 0
//
// assign (n)_stall = ( (n-1)_valid && ( pipeline hazard detection ) )
// || ( (n)_valid && (n+1)_stall );
//
// and ...
//
// always @(posedge i_clk)
// if (n)_ce
// (n)_variable = ... whatever logic for this stage
//
// Note that a stage can stall even if no instruction is loaded into
// it.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////////
//
// We can either pipeline our fetches, or issue one fetch at a time. Pipelined
// fetches are more complicated and therefore use more FPGA resources, while
// single fetches will cause the CPU to stall for about 5 stalls each
// instruction cycle, effectively reducing the instruction count per clock to
// about 0.2. However, the area cost may be worth it. Consider:
//
// Slice LUTs ZipSystem ZipCPU
// Single Fetching 2521 1734
// Pipelined fetching 2796 2046
//
//
//
`define CPU_CC_REG 4'he
`define CPU_PC_REG 4'hf
`define CPU_CLRCACHE_BIT 14 // Floating point error flag, set on error
`define CPU_PHASE_BIT 13 // Floating point error flag, set on error
`define CPU_FPUERR_BIT 12 // Floating point error flag, set on error
`define CPU_DIVERR_BIT 11 // Divide error flag, set on divide by zero
`define CPU_BUSERR_BIT 10 // Bus error flag, set on error
`define CPU_TRAP_BIT 9 // User TRAP has taken place
`define CPU_ILL_BIT 8 // Illegal instruction
`define CPU_BREAK_BIT 7
`define CPU_STEP_BIT 6 // Will step one or two (VLIW) instructions
`define CPU_GIE_BIT 5
`define CPU_SLEEP_BIT 4
// Compile time defines
//
`include "cpudefs.v"
//
//
module zipcpu(i_clk, i_rst, i_interrupt,
// Debug interface
i_halt, i_clear_pf_cache, i_dbg_reg, i_dbg_we, i_dbg_data,
o_dbg_stall, o_dbg_reg, o_dbg_cc,
o_break,
// CPU interface to the wishbone bus
o_wb_gbl_cyc, o_wb_gbl_stb,
o_wb_lcl_cyc, o_wb_lcl_stb,
o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_data,
i_wb_err,
// Accounting/CPU usage interface
o_op_stall, o_pf_stall, o_i_count
`ifdef DEBUG_SCOPE
, o_debug
`endif
);
parameter RESET_ADDRESS=32'h0100000, ADDRESS_WIDTH=24,
LGICACHE=6;
`ifdef OPT_MULTIPLY
parameter IMPLEMENT_MPY = `OPT_MULTIPLY;
`else
parameter IMPLEMENT_MPY = 0;
`endif
`ifdef OPT_DIVIDE
parameter IMPLEMENT_DIVIDE = 1;
`else
parameter IMPLEMENT_DIVIDE = 0;
`endif
`ifdef OPT_IMPLEMENT_FPU
parameter IMPLEMENT_FPU = 1,
`else
parameter IMPLEMENT_FPU = 0,
`endif
IMPLEMENT_LOCK=1;
`ifdef OPT_EARLY_BRANCHING
parameter EARLY_BRANCHING = 1;
`else
parameter EARLY_BRANCHING = 0;
`endif
parameter AW=ADDRESS_WIDTH;
input i_clk, i_rst, i_interrupt;
// Debug interface -- inputs
input i_halt, i_clear_pf_cache;
input [4:0] i_dbg_reg;
input i_dbg_we;
input [31:0] i_dbg_data;
// Debug interface -- outputs
output wire o_dbg_stall;
output reg [31:0] o_dbg_reg;
output reg [3:0] o_dbg_cc;
output wire o_break;
// Wishbone interface -- outputs
output wire o_wb_gbl_cyc, o_wb_gbl_stb;
output wire o_wb_lcl_cyc, o_wb_lcl_stb, o_wb_we;
output wire [(AW-1):0] o_wb_addr;
output wire [31:0] o_wb_data;
// Wishbone interface -- inputs
input i_wb_ack, i_wb_stall;
input [31:0] i_wb_data;
input i_wb_err;
// Accounting outputs ... to help us count stalls and usage
output wire o_op_stall;
output wire o_pf_stall;
output wire o_i_count;
//
`ifdef DEBUG_SCOPE
output reg [31:0] o_debug;
`endif
 
 
// Registers
//
// The distributed RAM style comment is necessary on the
// SPARTAN6 with XST to prevent XST from oversimplifying the register
// set and in the process ruining everything else. It basically
// optimizes logic away, to where it no longer works. The logic
// as described herein will work, this just makes sure XST implements
// that logic.
//
(* ram_style = "distributed" *)
reg [31:0] regset [0:31];
 
// Condition codes
// (BUS, TRAP,ILL,BREAKEN,STEP,GIE,SLEEP ), V, N, C, Z
reg [3:0] flags, iflags;
wire [14:0] w_uflags, w_iflags;
reg trap, break_en, step, gie, sleep, r_halted,
break_pending;
wire w_clear_icache;
`ifdef OPT_ILLEGAL_INSTRUCTION
reg ill_err_u, ill_err_i;
`else
wire ill_err_u, ill_err_i;
`endif
reg ubreak;
reg ibus_err_flag, ubus_err_flag;
wire idiv_err_flag, udiv_err_flag;
wire ifpu_err_flag, ufpu_err_flag;
wire ihalt_phase, uhalt_phase;
 
// The master chip enable
wire master_ce;
 
//
//
// PIPELINE STAGE #1 :: Prefetch
// Variable declarations
//
reg [(AW-1):0] pf_pc;
reg new_pc;
wire clear_pipeline;
assign clear_pipeline = new_pc;
 
wire dcd_stalled;
wire pf_cyc, pf_stb, pf_we, pf_busy, pf_ack, pf_stall, pf_err;
wire [(AW-1):0] pf_addr;
wire [31:0] pf_data;
wire [31:0] instruction;
wire [(AW-1):0] instruction_pc;
wire pf_valid, instruction_gie, pf_illegal;
 
//
//
// PIPELINE STAGE #2 :: Instruction Decode
// Variable declarations
//
//
reg opvalid, opvalid_mem, opvalid_alu;
reg opvalid_div, opvalid_fpu;
wire op_stall, dcd_ce, dcd_phase;
wire [3:0] dcdOp;
wire [4:0] dcdA, dcdB, dcdR;
wire dcdA_cc, dcdB_cc, dcdA_pc, dcdB_pc, dcdR_cc, dcdR_pc;
wire [3:0] dcdF;
wire dcdR_wr, dcdA_rd, dcdB_rd,
dcdALU, dcdM, dcdDV, dcdFP,
dcdF_wr, dcd_gie, dcd_break, dcd_lock,
dcd_pipe, dcd_ljmp;
reg r_dcdvalid;
wire dcdvalid;
wire [(AW-1):0] dcd_pc;
wire [31:0] dcdI;
wire dcd_zI; // true if dcdI == 0
wire dcdA_stall, dcdB_stall, dcdF_stall;
 
wire dcd_illegal;
wire dcd_early_branch;
wire [(AW-1):0] dcd_branch_pc;
 
 
//
//
// PIPELINE STAGE #3 :: Read Operands
// Variable declarations
//
//
//
// Now, let's read our operands
reg [4:0] alu_reg;
reg [3:0] opn;
reg [4:0] opR;
reg [31:0] r_opA, r_opB;
reg [(AW-1):0] op_pc;
wire [31:0] w_opA, w_opB;
wire [31:0] opA_nowait, opB_nowait, opA, opB;
reg opR_wr, opR_cc, opF_wr, op_gie;
wire [14:0] opFl;
reg [5:0] r_opF;
wire [7:0] opF;
wire op_ce, op_phase, op_pipe, op_change_data_ce;
// Some pipeline control wires
`ifdef OPT_PIPELINED
reg opA_alu, opA_mem;
reg opB_alu, opB_mem;
`endif
`ifdef OPT_ILLEGAL_INSTRUCTION
reg op_illegal;
`else
wire op_illegal;
assign op_illegal = 1'b0;
`endif
reg op_break;
wire op_lock;
 
 
//
//
// PIPELINE STAGE #4 :: ALU / Memory
// Variable declarations
//
//
reg [(AW-1):0] alu_pc;
reg r_alu_pc_valid, mem_pc_valid;
wire alu_pc_valid;
wire alu_phase;
wire alu_ce, alu_stall;
wire [31:0] alu_result;
wire [3:0] alu_flags;
wire alu_valid, alu_busy;
wire set_cond;
reg alu_wr, alF_wr, alu_gie;
wire alu_illegal_op;
wire alu_illegal;
 
 
 
wire mem_ce, mem_stalled;
`ifdef OPT_PIPELINED_BUS_ACCESS
wire mem_pipe_stalled;
`endif
wire mem_valid, mem_ack, mem_stall, mem_err, bus_err,
mem_cyc_gbl, mem_cyc_lcl, mem_stb_gbl, mem_stb_lcl, mem_we;
wire [4:0] mem_wreg;
 
wire mem_busy, mem_rdbusy;
wire [(AW-1):0] mem_addr;
wire [31:0] mem_data, mem_result;
 
wire div_ce, div_error, div_busy, div_valid;
wire [31:0] div_result;
wire [3:0] div_flags;
 
assign div_ce = (master_ce)&&(~clear_pipeline)&&(opvalid_div)
&&(~mem_rdbusy)&&(~div_busy)&&(~fpu_busy)
&&(set_cond);
 
wire fpu_ce, fpu_error, fpu_busy, fpu_valid;
wire [31:0] fpu_result;
wire [3:0] fpu_flags;
 
assign fpu_ce = (master_ce)&&(~clear_pipeline)&&(opvalid_fpu)
&&(~mem_rdbusy)&&(~div_busy)&&(~fpu_busy)
&&(set_cond);
 
wire adf_ce_unconditional;
 
//
//
// PIPELINE STAGE #5 :: Write-back
// Variable declarations
//
wire wr_reg_ce, wr_flags_ce, wr_write_pc, wr_write_cc,
wr_write_scc, wr_write_ucc;
wire [4:0] wr_reg_id;
wire [31:0] wr_gpreg_vl, wr_spreg_vl;
wire w_switch_to_interrupt, w_release_from_interrupt;
reg [(AW-1):0] upc, ipc;
 
 
 
//
// MASTER: clock enable.
//
assign master_ce = (~i_halt)&&(~o_break)&&(~sleep);
 
 
//
// PIPELINE STAGE #1 :: Prefetch
// Calculate stall conditions
//
// These are calculated externally, within the prefetch module.
//
 
//
// PIPELINE STAGE #2 :: Instruction Decode
// Calculate stall conditions
assign dcd_ce = ((~dcdvalid)||(~dcd_stalled))&&(~clear_pipeline);
 
`ifdef OPT_PIPELINED
assign dcd_stalled = (dcdvalid)&&(op_stall);
`else
// If not pipelined, there will be no opvalid_ anything, and the
// op_stall will be false, dcdX_stall will be false, thus we can simply
// do a ...
assign dcd_stalled = 1'b0;
`endif
//
// PIPELINE STAGE #3 :: Read Operands
// Calculate stall conditions
wire op_lock_stall;
`ifdef OPT_PIPELINED
reg cc_invalid_for_dcd;
always @(posedge i_clk)
cc_invalid_for_dcd <= (wr_flags_ce)
||(wr_reg_ce)&&(wr_reg_id[3:0] == `CPU_CC_REG)
||(opvalid)&&((opF_wr)||((opR_wr)&&(opR[3:0] == `CPU_CC_REG)))
||((alF_wr)||((alu_wr)&&(alu_reg[3:0] == `CPU_CC_REG)))
||(mem_busy)||(div_busy)||(fpu_busy);
 
assign op_stall = (opvalid)&&( // Only stall if we're loaded w/validins
// Stall if we're stopped, and not allowed to execute
// an instruction
// (~master_ce) // Already captured in alu_stall
//
// Stall if going into the ALU and the ALU is stalled
// i.e. if the memory is busy, or we are single
// stepping. This also includes our stalls for
// op_break and op_lock, so we don't need to
// include those as well here.
// This also includes whether or not the divide or
// floating point units are busy.
(alu_stall)
//
// Stall if we are going into memory with an operation
// that cannot be pipelined, and the memory is
// already busy
||(mem_stalled) // &&(opvalid_mem) part of mem_stalled
||(opR_cc)
)
||(dcdvalid)&&(
// Stall if we need to wait for an operand A
// to be ready to read
(dcdA_stall)
// Likewise for B, also includes logic
// regarding immediate offset (register must
// be in register file if we need to add to
// an immediate)
||(dcdB_stall)
// Or if we need to wait on flags to work on the
// CC register
||(dcdF_stall)
);
assign op_ce = ((dcdvalid)||(dcd_illegal))&&(~op_stall)&&(~clear_pipeline);
 
 
// BUT ... op_ce is too complex for many of the data operations. So
// let's make their circuit enable code simpler. In particular, if
// op_ doesn't need to be preserved, we can change it all we want
// ... right? The clear_pipeline code, for example, really only needs
// to determine whether opvalid is true.
assign op_change_data_ce = (~op_stall);
`else
assign op_stall = (opvalid)&&(~master_ce);
assign op_ce = ((dcdvalid)||(dcd_illegal))&&(~clear_pipeline);
assign op_change_data_ce = 1'b1;
`endif
 
//
// PIPELINE STAGE #4 :: ALU / Memory
// Calculate stall conditions
//
// 1. Basic stall is if the previous stage is valid and the next is
// busy.
// 2. Also stall if the prior stage is valid and the master clock enable
// is de-selected
// 3. Stall if someone on the other end is writing the CC register,
// since we don't know if it'll put us to sleep or not.
// 4. Last case: Stall if we would otherwise move a break instruction
// through the ALU. Break instructions are not allowed through
// the ALU.
`ifdef OPT_PIPELINED
assign alu_stall = (((~master_ce)||(mem_rdbusy)||(alu_busy))&&(opvalid_alu)) //Case 1&2
||((opvalid)&&(op_lock)&&(op_lock_stall))
||((opvalid)&&(op_break))
||(wr_reg_ce)&&(wr_write_cc)
||(div_busy)||(fpu_busy);
assign alu_ce = (master_ce)&&(opvalid_alu)&&(~alu_stall)
&&(~clear_pipeline);
`else
assign alu_stall = (opvalid_alu)&&((~master_ce)||(op_break));
assign alu_ce = (master_ce)&&((opvalid_alu)||(op_illegal))&&(~alu_stall)&&(~clear_pipeline);
`endif
//
 
//
// Note: if you change the conditions for mem_ce, you must also change
// alu_pc_valid.
//
`ifdef OPT_PIPELINED
assign mem_ce = (master_ce)&&(opvalid_mem)&&(~mem_stalled)
&&(~clear_pipeline);
`else
// If we aren't pipelined, then no one will be changing what's in the
// pipeline (i.e. clear_pipeline), while our only instruction goes
// through the ... pipeline.
//
// However, in hind sight this logic didn't work. What happens when
// something gets in the pipeline and then (due to interrupt or some
// such) needs to be voided? Thus we avoid simplification and keep
// what worked here.
assign mem_ce = (master_ce)&&(opvalid_mem)&&(~mem_stalled)
&&(~clear_pipeline);
`endif
`ifdef OPT_PIPELINED_BUS_ACCESS
assign mem_stalled = (~master_ce)||(alu_busy)||((opvalid_mem)&&(
(mem_pipe_stalled)
||((~op_pipe)&&(mem_busy))
||(div_busy)
||(fpu_busy)
// Stall waiting for flags to be valid
// Or waiting for a write to the PC register
// Or CC register, since that can change the
// PC as well
||((wr_reg_ce)&&(wr_reg_id[4] == op_gie)
&&((wr_write_pc)||(wr_write_cc)))));
`else
`ifdef OPT_PIPELINED
assign mem_stalled = (mem_busy)||((opvalid_mem)&&(
(~master_ce)
// Stall waiting for flags to be valid
// Or waiting for a write to the PC register
// Or CC register, since that can change the
// PC as well
||((wr_reg_ce)&&(wr_reg_id[4] == op_gie)&&((wr_write_pc)||(wr_write_cc)))));
`else
assign mem_stalled = (opvalid_mem)&&(~master_ce);
`endif
`endif
 
// ALU, DIV, or FPU CE ... equivalent to the OR of all three of these
assign adf_ce_unconditional = (master_ce)&&(~clear_pipeline)&&(opvalid)
&&(~opvalid_mem)&&(~mem_rdbusy)
&&((~opvalid_alu)||(~alu_stall))&&(~op_break)
&&(~div_busy)&&(~fpu_busy)&&(~clear_pipeline);
 
//
//
// PIPELINE STAGE #1 :: Prefetch
//
//
`ifdef OPT_SINGLE_FETCH
wire pf_ce;
 
assign pf_ce = (~pf_valid)&&(~dcdvalid)&&(~opvalid)&&(~alu_busy)&&(~mem_busy)&&(~alu_pc_valid)&&(~mem_pc_valid);
prefetch #(ADDRESS_WIDTH)
pf(i_clk, (i_rst), (pf_ce), (~dcd_stalled), pf_pc, gie,
instruction, instruction_pc, instruction_gie,
pf_valid, pf_illegal,
pf_cyc, pf_stb, pf_we, pf_addr, pf_data,
pf_ack, pf_stall, pf_err, i_wb_data);
 
initial r_dcdvalid = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline))
r_dcdvalid <= 1'b0;
else if (dcd_ce)
r_dcdvalid <= (pf_valid)||(pf_illegal);
else if (op_ce)
r_dcdvalid <= 1'b0;
assign dcdvalid = r_dcdvalid;
 
`else // Pipe fetch
 
`ifdef OPT_TRADITIONAL_PFCACHE
pfcache #(LGICACHE, ADDRESS_WIDTH)
pf(i_clk, i_rst, (new_pc)||((dcd_early_branch)&&(~clear_pipeline)),
w_clear_icache,
// dcd_pc,
~dcd_stalled,
((dcd_early_branch)&&(~clear_pipeline))
? dcd_branch_pc:pf_pc,
instruction, instruction_pc, pf_valid,
pf_cyc, pf_stb, pf_we, pf_addr, pf_data,
pf_ack, pf_stall, pf_err, i_wb_data,
pf_illegal);
`else
pipefetch #(RESET_ADDRESS, LGICACHE, ADDRESS_WIDTH)
pf(i_clk, i_rst, (new_pc)||(dcd_early_branch),
w_clear_icache, ~dcd_stalled,
(new_pc)?pf_pc:dcd_branch_pc,
instruction, instruction_pc, pf_valid,
pf_cyc, pf_stb, pf_we, pf_addr, pf_data,
pf_ack, pf_stall, pf_err, i_wb_data,
//`ifdef OPT_PRECLEAR_BUS
//((dcd_clear_bus)&&(dcdvalid))
//||((op_clear_bus)&&(opvalid))
//||
//`endif
(mem_cyc_lcl)||(mem_cyc_gbl),
pf_illegal);
`endif
assign instruction_gie = gie;
 
initial r_dcdvalid = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline)||(w_clear_icache))
r_dcdvalid <= 1'b0;
else if (dcd_ce)
r_dcdvalid <= (pf_valid)&&(~dcd_ljmp)&&(~dcd_early_branch);
else if (op_ce)
r_dcdvalid <= 1'b0;
assign dcdvalid = r_dcdvalid;
`endif
 
`ifdef OPT_NEW_INSTRUCTION_SET
 
// If not pipelined, there will be no opvalid_ anything, and the
idecode #(AW, IMPLEMENT_MPY, EARLY_BRANCHING, IMPLEMENT_DIVIDE,
IMPLEMENT_FPU)
instruction_decoder(i_clk, (i_rst)||(clear_pipeline),
(~dcdvalid)||(~op_stall), dcd_stalled, instruction, instruction_gie,
instruction_pc, pf_valid, pf_illegal, dcd_phase,
dcd_illegal, dcd_pc, dcd_gie,
{ dcdR_cc, dcdR_pc, dcdR },
{ dcdA_cc, dcdA_pc, dcdA },
{ dcdB_cc, dcdB_pc, dcdB },
dcdI, dcd_zI, dcdF, dcdF_wr, dcdOp,
dcdALU, dcdM, dcdDV, dcdFP, dcd_break, dcd_lock,
dcdR_wr,dcdA_rd, dcdB_rd,
dcd_early_branch,
dcd_branch_pc, dcd_ljmp,
dcd_pipe);
`else
idecode_deprecated
#(AW, IMPLEMENT_MPY, EARLY_BRANCHING, IMPLEMENT_DIVIDE,
IMPLEMENT_FPU)
instruction_decoder(i_clk, (i_rst)||(clear_pipeline),
dcd_ce, dcd_stalled, instruction, instruction_gie,
instruction_pc, pf_valid, pf_illegal, dcd_phase,
dcd_illegal, dcd_pc, dcd_gie,
{ dcdR_cc, dcdR_pc, dcdR },
{ dcdA_cc, dcdA_pc, dcdA },
{ dcdB_cc, dcdB_pc, dcdB },
dcdI, dcd_zI, dcdF, dcdF_wr, dcdOp,
dcdALU, dcdM, dcdDV, dcdFP, dcd_break, dcd_lock,
dcdR_wr,dcdA_rd, dcdB_rd,
dcd_early_branch,
dcd_branch_pc,
dcd_pipe);
assign dcd_ljmp = 1'b0;
`endif
 
`ifdef OPT_PIPELINED_BUS_ACCESS
reg r_op_pipe;
 
initial r_op_pipe = 1'b0;
// To be a pipeable operation, there must be
// two valid adjacent instructions
// Both must be memory instructions
// Both must be writes, or both must be reads
// Both operations must be to the same identical address,
// or at least a single (one) increment above that address
//
// However ... we need to know this before this clock, hence this is
// calculated in the instruction decoder.
always @(posedge i_clk)
if (op_ce)
r_op_pipe <= dcd_pipe;
else if (mem_ce) // Clear us any time an op_ is clocked in
r_op_pipe <= 1'b0;
assign op_pipe = r_op_pipe;
`else
assign op_pipe = 1'b0;
`endif
 
//
//
// PIPELINE STAGE #3 :: Read Operands (Registers)
//
//
assign w_opA = regset[dcdA];
assign w_opB = regset[dcdB];
 
wire [8:0] w_cpu_info;
assign w_cpu_info = {
`ifdef OPT_ILLEGAL_INSTRUCTION
1'b1,
`else
1'b0,
`endif
`ifdef OPT_MULTIPLY
1'b1,
`else
1'b0,
`endif
`ifdef OPT_DIVIDE
1'b1,
`else
1'b0,
`endif
`ifdef OPT_IMPLEMENT_FPU
1'b1,
`else
1'b0,
`endif
`ifdef OPT_PIPELINED
1'b1,
`else
1'b0,
`endif
`ifdef OPT_TRADITIONAL_CACHE
1'b1,
`else
1'b0,
`endif
`ifdef OPT_EARLY_BRANCHING
1'b1,
`else
1'b0,
`endif
`ifdef OPT_PIPELINED_BUS_ACCESS
1'b1,
`else
1'b0,
`endif
`ifdef OPT_VLIW
1'b1
`else
1'b0
`endif
};
 
wire [31:0] w_pcA_v;
generate
if (AW < 32)
assign w_pcA_v = {{(32-AW){1'b0}}, (dcdA[4] == dcd_gie)?dcd_pc:upc };
else
assign w_pcA_v = (dcdA[4] == dcd_gie)?dcd_pc:upc;
endgenerate
 
`ifdef OPT_PIPELINED
reg [4:0] opA_id, opB_id;
reg opA_rd, opB_rd;
always @(posedge i_clk)
if (op_ce)
begin
opA_id <= dcdA;
opB_id <= dcdB;
opA_rd <= dcdA_rd;
opB_rd <= dcdB_rd;
end
`endif
 
always @(posedge i_clk)
if (op_change_data_ce)
begin
if ((wr_reg_ce)&&(wr_reg_id == dcdA))
r_opA <= wr_gpreg_vl;
else if (dcdA_pc)
r_opA <= w_pcA_v;
else if (dcdA_cc)
r_opA <= { w_cpu_info, w_opA[22:15], (dcdA[4])?w_uflags:w_iflags };
else
r_opA <= w_opA;
`ifdef OPT_PIPELINED
end else
begin // We were going to pick these up when they became valid,
// but for some reason we're stuck here as they became
// valid. Pick them up now anyway
// if (((opA_alu)&&(alu_wr))||((opA_mem)&&(mem_valid)))
// r_opA <= wr_gpreg_vl;
if ((wr_reg_ce)&&(wr_reg_id == opA_id)&&(opA_rd))
r_opA <= wr_gpreg_vl;
`endif
end
 
wire [31:0] w_opBnI, w_pcB_v;
generate
if (AW < 32)
assign w_pcB_v = {{(32-AW){1'b0}}, (dcdB[4] == dcd_gie)?dcd_pc:upc };
else
assign w_pcB_v = (dcdB[4] == dcd_gie)?dcd_pc:upc;
endgenerate
 
assign w_opBnI = (~dcdB_rd) ? 32'h00
: (((wr_reg_ce)&&(wr_reg_id == dcdB)) ? wr_gpreg_vl
: ((dcdB_pc) ? w_pcB_v
: ((dcdB_cc) ? { w_cpu_info, w_opB[22:15], // w_opB[31:14],
(dcdB[4])?w_uflags:w_iflags}
: w_opB)));
 
always @(posedge i_clk)
if (op_change_data_ce)
r_opB <= w_opBnI + dcdI;
`ifdef OPT_PIPELINED
else if ((wr_reg_ce)&&(opB_id == wr_reg_id)&&(opB_rd))
r_opB <= wr_gpreg_vl;
`endif
 
// The logic here has become more complex than it should be, no thanks
// to Xilinx's Vivado trying to help. The conditions are supposed to
// be two sets of four bits: the top bits specify what bits matter, the
// bottom specify what those top bits must equal. However, two of
// conditions check whether bits are on, and those are the only two
// conditions checking those bits. Therefore, Vivado complains that
// these two bits are redundant. Hence the convoluted expression
// below, arriving at what we finally want in the (now wire net)
// opF.
always @(posedge i_clk)
if (op_ce) // Cannot do op_change_data_ce here since opF depends
// upon being either correct for a valid op, or correct
// for the last valid op
begin // Set the flag condition codes, bit order is [3:0]=VNCZ
case(dcdF[2:0])
3'h0: r_opF <= 6'h00; // Always
`ifdef OPT_NEW_INSTRUCTION_SET
// These were remapped as part of the new instruction
// set in order to make certain that the low order
// two bits contained the most commonly used
// conditions: Always, LT, Z, and NZ.
3'h1: r_opF <= 6'h24; // LT
3'h2: r_opF <= 6'h11; // Z
3'h3: r_opF <= 6'h10; // NE
3'h4: r_opF <= 6'h30; // GT (!N&!Z)
3'h5: r_opF <= 6'h20; // GE (!N)
`else
3'h1: r_opF <= 6'h11; // Z
3'h2: r_opF <= 6'h10; // NE
3'h3: r_opF <= 6'h20; // GE (!N)
3'h4: r_opF <= 6'h30; // GT (!N&!Z)
3'h5: r_opF <= 6'h24; // LT
`endif
3'h6: r_opF <= 6'h02; // C
3'h7: r_opF <= 6'h08; // V
endcase
end // Bit order is { (flags_not_used), VNCZ mask, VNCZ value }
assign opF = { r_opF[3], r_opF[5], r_opF[1], r_opF[4:0] };
 
wire w_opvalid;
assign w_opvalid = (~clear_pipeline)&&(dcdvalid)&&(~dcd_ljmp);
initial opvalid = 1'b0;
initial opvalid_alu = 1'b0;
initial opvalid_mem = 1'b0;
initial opvalid_div = 1'b0;
initial opvalid_fpu = 1'b0;
always @(posedge i_clk)
if (i_rst)
begin
opvalid <= 1'b0;
opvalid_alu <= 1'b0;
opvalid_mem <= 1'b0;
opvalid_div <= 1'b0;
opvalid_fpu <= 1'b0;
end else if (op_ce)
begin
// Do we have a valid instruction?
// The decoder may vote to stall one of its
// instructions based upon something we currently
// have in our queue. This instruction must then
// move forward, and get a stall cycle inserted.
// Hence, the test on dcd_stalled here. If we must
// wait until our operands are valid, then we aren't
// valid yet until then.
opvalid<= (w_opvalid)||(dcd_illegal)&&(dcdvalid);
`ifdef OPT_ILLEGAL_INSTRUCTION
opvalid_alu <= (w_opvalid)&&((dcdALU)||(dcd_illegal));
opvalid_mem <= (dcdM)&&(~dcd_illegal)&&(w_opvalid);
opvalid_div <= (dcdDV)&&(~dcd_illegal)&&(w_opvalid);
opvalid_fpu <= (dcdFP)&&(~dcd_illegal)&&(w_opvalid);
`else
opvalid_alu <= (dcdALU)&&(w_opvalid);
opvalid_mem <= (dcdM)&&(w_opvalid);
opvalid_div <= (dcdDV)&&(w_opvalid);
opvalid_fpu <= (dcdFP)&&(w_opvalid);
`endif
end else if ((clear_pipeline)||(adf_ce_unconditional)||(mem_ce))
begin
opvalid <= 1'b0;
opvalid_alu <= 1'b0;
opvalid_mem <= 1'b0;
opvalid_div <= 1'b0;
opvalid_fpu <= 1'b0;
end
 
// Here's part of our debug interface. When we recognize a break
// instruction, we set the op_break flag. That'll prevent this
// instruction from entering the ALU, and cause an interrupt before
// this instruction. Thus, returning to this code will cause the
// break to repeat and continue upon return. To get out of this
// condition, replace the break instruction with what it is supposed
// to be, step through it, and then replace it back. In this fashion,
// a debugger can step through code.
// assign w_op_break = (dcd_break)&&(r_dcdI[15:0] == 16'h0001);
initial op_break = 1'b0;
always @(posedge i_clk)
if (i_rst) op_break <= 1'b0;
else if (op_ce) op_break <= (dcd_break); // &&(dcdvalid)
else if ((clear_pipeline)||(~opvalid))
op_break <= 1'b0;
 
`ifdef OPT_PIPELINED
generate
if (IMPLEMENT_LOCK != 0)
begin
reg r_op_lock, r_op_lock_stall;
 
initial r_op_lock_stall = 1'b0;
always @(posedge i_clk)
if (i_rst)
r_op_lock_stall <= 1'b0;
else
r_op_lock_stall <= (~opvalid)||(~op_lock)
||(~dcdvalid)||(~pf_valid);
 
assign op_lock_stall = r_op_lock_stall;
 
initial r_op_lock = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline))
r_op_lock <= 1'b0;
else if (op_ce)
r_op_lock <= (dcd_lock)&&(~clear_pipeline);
assign op_lock = r_op_lock;
 
end else begin
assign op_lock_stall = 1'b0;
assign op_lock = 1'b0;
end endgenerate
 
`else
assign op_lock_stall = 1'b0;
assign op_lock = 1'b0;
`endif
 
`ifdef OPT_ILLEGAL_INSTRUCTION
initial op_illegal = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline))
op_illegal <= 1'b0;
else if(op_ce)
`ifdef OPT_PIPELINED
op_illegal <= (dcdvalid)&&((dcd_illegal)||((dcd_lock)&&(IMPLEMENT_LOCK == 0)));
`else
op_illegal <= (dcdvalid)&&((dcd_illegal)||(dcd_lock));
`endif
`endif
else if(alu_ce)
op_illegal <= 1'b0;
 
// No generate on EARLY_BRANCHING here, since if EARLY_BRANCHING is not
// set, dcd_early_branch will simply be a wire connected to zero and
// this logic should just optimize.
always @(posedge i_clk)
if (op_ce)
begin
opF_wr <= (dcdF_wr)&&((~dcdR_cc)||(~dcdR_wr))
&&(~dcd_early_branch)&&(~dcd_illegal);
opR_wr <= (dcdR_wr)&&(~dcd_early_branch)&&(~dcd_illegal);
end
 
always @(posedge i_clk)
if (op_change_data_ce)
begin
opn <= dcdOp; // Which ALU operation?
// opM <= dcdM; // Is this a memory operation?
// What register will these results be written into?
opR <= dcdR;
opR_cc <= (dcdR_cc)&&(dcdR_wr)&&(dcdR[4]==dcd_gie);
// User level (1), vs supervisor (0)/interrupts disabled
op_gie <= dcd_gie;
 
 
//
op_pc <= (dcd_early_branch)?dcd_branch_pc:dcd_pc;
end
assign opFl = (op_gie)?(w_uflags):(w_iflags);
 
`ifdef OPT_VLIW
reg r_op_phase;
initial r_op_phase = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline))
r_op_phase <= 1'b0;
else if (op_change_data_ce)
r_op_phase <= dcd_phase;
assign op_phase = r_op_phase;
`else
assign op_phase = 1'b0;
`endif
 
// This is tricky. First, the PC and Flags registers aren't kept in
// register set but in special registers of their own. So step one
// is to select the right register. Step to is to replace that
// register with the results of an ALU or memory operation, if such
// results are now available. Otherwise, we'd need to insert a wait
// state of some type.
//
// The alternative approach would be to define some sort of
// op_stall wire, which would stall any upstream stage.
// We'll create a flag here to start our coordination. Once we
// define this flag to something other than just plain zero, then
// the stalls will already be in place.
`ifdef OPT_PIPELINED
assign opA = ((wr_reg_ce)&&(wr_reg_id == opA_id)) // &&(opA_rd))
? wr_gpreg_vl : r_opA;
`else
assign opA = r_opA;
`endif
 
`ifdef OPT_PIPELINED
// Stall if we have decoded an instruction that will read register A
// AND ... something that may write a register is running
// AND (series of conditions here ...)
// The operation might set flags, and we wish to read the
// CC register
// OR ... (No other conditions)
assign dcdA_stall = (dcdA_rd) // &&(dcdvalid) is checked for elsewhere
&&((opvalid)||(mem_rdbusy)
||(div_busy)||(fpu_busy))
&&(((opF_wr)||(cc_invalid_for_dcd))&&(dcdA_cc))
||((dcdA_rd)&&(dcdA_cc)&&(cc_invalid_for_dcd));
`else
// There are no pipeline hazards, if we aren't pipelined
assign dcdA_stall = 1'b0;
`endif
 
`ifdef OPT_PIPELINED
assign opB = ((wr_reg_ce)&&(wr_reg_id == opB_id)&&(opB_rd))
? wr_gpreg_vl: r_opB;
`else
assign opB = r_opB;
`endif
 
`ifdef OPT_PIPELINED
// Stall if we have decoded an instruction that will read register B
// AND ... something that may write a (unknown) register is running
// AND (series of conditions here ...)
// The operation might set flags, and we wish to read the
// CC register
// OR the operation might set register B, and we still need
// a clock to add the offset to it
assign dcdB_stall = (dcdB_rd) // &&(dcdvalid) is checked for elsewhere
// If the op stage isn't valid, yet something
// is running, then it must have been valid.
// We'll use the last values from that stage
// (opR_wr, opF_wr, opR) in our logic below.
&&((opvalid)||(mem_rdbusy)
||(div_busy)||(fpu_busy)||(alu_busy))
&&(
// Okay, what happens if the result register
// from instruction 1 becomes the input for
// instruction two, *and* there's an immediate
// offset in instruction two? In that case, we
// need an extra clock between the two
// instructions to calculate the base plus
// offset.
//
// What if instruction 1 (or before) is in a
// memory pipeline? We may no longer know what
// the register was! We will then need to
// blindly wait. We'll temper this only waiting
// if we're not piping this new instruction.
// If we were piping, the pipe logic in the
// decode circuit has told us that the hazard
// is clear, so we're okay then.
//
((~dcd_zI)&&(
((opR == dcdB)&&(opR_wr))
||((mem_rdbusy)&&(~dcd_pipe))
))
// Stall following any instruction that will
// set the flags, if we're going to need the
// flags (CC) register for opB.
||(((opF_wr)||(cc_invalid_for_dcd))&&(dcdB_cc))
// Stall on any ongoing memory operation that
// will write to opB -- captured above
// ||((mem_busy)&&(~mem_we)&&(mem_last_reg==dcdB)&&(~dcd_zI))
)
||((dcdB_rd)&&(dcdB_cc)&&(cc_invalid_for_dcd));
assign dcdF_stall = ((~dcdF[3])
||((dcdA_rd)&&(dcdA_cc))
||((dcdB_rd)&&(dcdB_cc)))
&&(opvalid)&&(opR_cc);
// &&(dcdvalid) is checked for elsewhere
`else
// No stalls without pipelining, 'cause how can you have a pipeline
// hazard without the pipeline?
assign dcdB_stall = 1'b0;
assign dcdF_stall = 1'b0;
`endif
//
//
// PIPELINE STAGE #4 :: Apply Instruction
//
//
`ifdef OPT_NEW_INSTRUCTION_SET
cpuops #(IMPLEMENT_MPY) doalu(i_clk, i_rst, alu_ce,
(opvalid_alu), opn, opA, opB,
alu_result, alu_flags, alu_valid, alu_illegal_op,
alu_busy);
`else
cpuops_deprecated #(IMPLEMENT_MPY) doalu(i_clk, i_rst, alu_ce,
(opvalid_alu), opn, opA, opB,
alu_result, alu_flags, alu_valid, alu_illegal_op);
assign alu_busy = 1'b0;
`endif
 
generate
if (IMPLEMENT_DIVIDE != 0)
begin
div thedivide(i_clk, (i_rst)||(clear_pipeline), div_ce, opn[0],
opA, opB, div_busy, div_valid, div_error, div_result,
div_flags);
end else begin
assign div_error = 1'b0; // Can't be high unless div_valid
assign div_busy = 1'b0;
assign div_valid = 1'b0;
assign div_result= 32'h00;
assign div_flags = 4'h0;
end endgenerate
 
generate
if (IMPLEMENT_FPU != 0)
begin
//
// sfpu thefpu(i_clk, i_rst, fpu_ce,
// opA, opB, fpu_busy, fpu_valid, fpu_err, fpu_result,
// fpu_flags);
//
assign fpu_error = 1'b0; // Must only be true if fpu_valid
assign fpu_busy = 1'b0;
assign fpu_valid = 1'b0;
assign fpu_result= 32'h00;
assign fpu_flags = 4'h0;
end else begin
assign fpu_error = 1'b0;
assign fpu_busy = 1'b0;
assign fpu_valid = 1'b0;
assign fpu_result= 32'h00;
assign fpu_flags = 4'h0;
end endgenerate
 
 
assign set_cond = ((opF[7:4]&opFl[3:0])==opF[3:0]);
initial alF_wr = 1'b0;
initial alu_wr = 1'b0;
always @(posedge i_clk)
if (i_rst)
begin
alu_wr <= 1'b0;
alF_wr <= 1'b0;
end else if (alu_ce)
begin
// alu_reg <= opR;
alu_wr <= (opR_wr)&&(set_cond);
alF_wr <= (opF_wr)&&(set_cond);
end else if (~alu_busy) begin
// These are strobe signals, so clear them if not
// set for any particular clock
alu_wr <= (i_halt)&&(i_dbg_we);
alF_wr <= 1'b0;
end
 
`ifdef OPT_VLIW
reg r_alu_phase;
initial r_alu_phase = 1'b0;
always @(posedge i_clk)
if (i_rst)
r_alu_phase <= 1'b0;
else if ((adf_ce_unconditional)||(mem_ce))
r_alu_phase <= op_phase;
assign alu_phase = r_alu_phase;
`else
assign alu_phase = 1'b0;
`endif
 
always @(posedge i_clk)
if (adf_ce_unconditional)
alu_reg <= opR;
else if ((i_halt)&&(i_dbg_we))
alu_reg <= i_dbg_reg;
 
//
// DEBUG Register write access starts here
//
reg dbgv;
initial dbgv = 1'b0;
always @(posedge i_clk)
dbgv <= (~i_rst)&&(i_halt)&&(i_dbg_we)&&(r_halted);
reg [31:0] dbg_val;
always @(posedge i_clk)
dbg_val <= i_dbg_data;
always @(posedge i_clk)
if ((adf_ce_unconditional)||(mem_ce))
alu_gie <= op_gie;
always @(posedge i_clk)
if ((adf_ce_unconditional)
||((master_ce)&&(opvalid_mem)&&(~clear_pipeline)
&&(~mem_stalled)))
alu_pc <= op_pc;
 
`ifdef OPT_ILLEGAL_INSTRUCTION
reg r_alu_illegal;
initial r_alu_illegal = 0;
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline))
r_alu_illegal <= 1'b0;
else if (alu_ce)
r_alu_illegal <= op_illegal;
else
r_alu_illegal <= 1'b0;
assign alu_illegal = (alu_illegal_op)||(r_alu_illegal);
`else
assign alu_illegal = 1'b0;
`endif
 
initial r_alu_pc_valid = 1'b0;
initial mem_pc_valid = 1'b0;
always @(posedge i_clk)
if (i_rst)
r_alu_pc_valid <= 1'b0;
else if (adf_ce_unconditional)//Includes&&(~alu_clear_pipeline)
r_alu_pc_valid <= 1'b1;
else if (((~alu_busy)&&(~div_busy)&&(~fpu_busy))||(clear_pipeline))
r_alu_pc_valid <= 1'b0;
assign alu_pc_valid = (r_alu_pc_valid)&&((~alu_busy)&&(~div_busy)&&(~fpu_busy));
always @(posedge i_clk)
if (i_rst)
mem_pc_valid <= 1'b0;
else
mem_pc_valid <= (mem_ce);
 
wire bus_lock;
`ifdef OPT_PIPELINED
generate
if (IMPLEMENT_LOCK != 0)
begin
reg [1:0] r_bus_lock;
initial r_bus_lock = 2'b00;
always @(posedge i_clk)
if (i_rst)
r_bus_lock <= 2'b00;
else if ((op_ce)&&(op_lock))
r_bus_lock <= 2'b11;
else if ((|r_bus_lock)&&((~opvalid_mem)||(~op_ce)))
r_bus_lock <= r_bus_lock + 2'b11;
assign bus_lock = |r_bus_lock;
end else begin
assign bus_lock = 1'b0;
end endgenerate
`else
assign bus_lock = 1'b0;
`endif
 
`ifdef OPT_PIPELINED_BUS_ACCESS
pipemem #(AW,IMPLEMENT_LOCK) domem(i_clk, i_rst,(mem_ce)&&(set_cond), bus_lock,
(opn[0]), opB, opA, opR,
mem_busy, mem_pipe_stalled,
mem_valid, bus_err, mem_wreg, mem_result,
mem_cyc_gbl, mem_cyc_lcl,
mem_stb_gbl, mem_stb_lcl,
mem_we, mem_addr, mem_data,
mem_ack, mem_stall, mem_err, i_wb_data);
`else // PIPELINED_BUS_ACCESS
memops #(AW,IMPLEMENT_LOCK) domem(i_clk, i_rst,(mem_ce)&&(set_cond), bus_lock,
(opn[0]), opB, opA, opR,
mem_busy,
mem_valid, bus_err, mem_wreg, mem_result,
mem_cyc_gbl, mem_cyc_lcl,
mem_stb_gbl, mem_stb_lcl,
mem_we, mem_addr, mem_data,
mem_ack, mem_stall, mem_err, i_wb_data);
`endif // PIPELINED_BUS_ACCESS
assign mem_rdbusy = ((mem_busy)&&(~mem_we));
 
// Either the prefetch or the instruction gets the memory bus, but
// never both.
wbdblpriarb #(32,AW) pformem(i_clk, i_rst,
// Memory access to the arbiter, priority position
mem_cyc_gbl, mem_cyc_lcl, mem_stb_gbl, mem_stb_lcl,
mem_we, mem_addr, mem_data, mem_ack, mem_stall, mem_err,
// Prefetch access to the arbiter
pf_cyc, 1'b0, pf_stb, 1'b0, pf_we, pf_addr, pf_data,
pf_ack, pf_stall, pf_err,
// Common wires, in and out, of the arbiter
o_wb_gbl_cyc, o_wb_lcl_cyc, o_wb_gbl_stb, o_wb_lcl_stb,
o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_err);
 
 
 
//
//
//
//
//
//
//
//
// PIPELINE STAGE #5 :: Write-back results
//
//
// This stage is not allowed to stall. If results are ready to be
// written back, they are written back at all cost. Sleepy CPU's
// won't prevent write back, nor debug modes, halting the CPU, nor
// anything else. Indeed, the (master_ce) bit is only as relevant
// as knowinig something is available for writeback.
 
//
// Write back to our generic register set ...
// When shall we write back? On one of two conditions
// Note that the flags needed to be checked before issuing the
// bus instruction, so they don't need to be checked here.
// Further, alu_wr includes (set_cond), so we don't need to
// check for that here either.
`ifdef OPT_ILLEGAL_INSTRUCTION
assign wr_reg_ce = (dbgv)||(mem_valid)
||((~clear_pipeline)&&(~alu_illegal)
&&(((alu_wr)&&(alu_valid))
||(div_valid)||(fpu_valid)));
`else
assign wr_reg_ce = (dbgv)||(mem_valid)
||((~clear_pipeline)
&&(((alu_wr)&&(alu_valid))
||(div_valid)||(fpu_valid)));
`endif
// Which register shall be written?
// COULD SIMPLIFY THIS: by adding three bits to these registers,
// One or PC, one for CC, and one for GIE match
// Note that the alu_reg is the register to write on a divide or
// FPU operation.
assign wr_reg_id = (alu_wr|div_valid|fpu_valid)?alu_reg:mem_wreg;
// Are we writing to the CC register?
assign wr_write_cc = (wr_reg_id[3:0] == `CPU_CC_REG);
assign wr_write_scc = (wr_reg_id[4:0] == {1'b0, `CPU_CC_REG});
assign wr_write_ucc = (wr_reg_id[4:0] == {1'b1, `CPU_CC_REG});
// Are we writing to the PC?
assign wr_write_pc = (wr_reg_id[3:0] == `CPU_PC_REG);
 
// What value to write?
assign wr_gpreg_vl = ((mem_valid) ? mem_result
:((div_valid|fpu_valid))
? ((div_valid) ? div_result:fpu_result)
:((dbgv) ? dbg_val : alu_result));
assign wr_spreg_vl = ((mem_valid) ? mem_result
:((dbgv) ? dbg_val : alu_result));
always @(posedge i_clk)
if (wr_reg_ce)
regset[wr_reg_id] <= wr_gpreg_vl;
 
//
// Write back to the condition codes/flags register ...
// When shall we write to our flags register? alF_wr already
// includes the set condition ...
assign wr_flags_ce = ((alF_wr)||(div_valid)||(fpu_valid))&&(~clear_pipeline)&&(~alu_illegal);
assign w_uflags = { 1'b0, uhalt_phase, ufpu_err_flag,
udiv_err_flag, ubus_err_flag, trap, ill_err_u,
ubreak, step, 1'b1, sleep,
((wr_flags_ce)&&(alu_gie))?alu_flags:flags };
assign w_iflags = { 1'b0, ihalt_phase, ifpu_err_flag,
idiv_err_flag, ibus_err_flag, trap, ill_err_i,
break_en, 1'b0, 1'b0, sleep,
((wr_flags_ce)&&(~alu_gie))?alu_flags:iflags };
 
 
// What value to write?
always @(posedge i_clk)
// If explicitly writing the register itself
if ((wr_reg_ce)&&(wr_write_ucc))
flags <= wr_gpreg_vl[3:0];
// Otherwise if we're setting the flags from an ALU operation
else if ((wr_flags_ce)&&(alu_gie))
flags <= (div_valid)?div_flags:((fpu_valid)?fpu_flags
: alu_flags);
 
always @(posedge i_clk)
if ((wr_reg_ce)&&(wr_write_scc))
iflags <= wr_gpreg_vl[3:0];
else if ((wr_flags_ce)&&(~alu_gie))
iflags <= (div_valid)?div_flags:((fpu_valid)?fpu_flags
: alu_flags);
 
// The 'break' enable bit. This bit can only be set from supervisor
// mode. It control what the CPU does upon encountering a break
// instruction.
//
// The goal, upon encountering a break is that the CPU should stop and
// not execute the break instruction, choosing instead to enter into
// either interrupt mode or halt first.
// if ((break_en) AND (break_instruction)) // user mode or not
// HALT CPU
// else if (break_instruction) // only in user mode
// set an interrupt flag, set the user break bit,
// go to supervisor mode, allow supervisor to step the CPU.
// Upon a CPU halt, any break condition will be reset. The
// external debugger will then need to deal with whatever
// condition has taken place.
initial break_en = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(i_halt))
break_en <= 1'b0;
else if ((wr_reg_ce)&&(wr_write_scc))
break_en <= wr_spreg_vl[`CPU_BREAK_BIT];
 
initial break_pending = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(clear_pipeline)||(~opvalid))
break_pending <= 1'b0;
else if (op_break)
break_pending <= (~alu_busy)&&(~div_busy)&&(~fpu_busy)&&(~mem_busy);
else
break_pending <= 1'b0;
 
 
assign o_break = ((break_en)||(~op_gie))&&(break_pending)
&&(~clear_pipeline)
||((~alu_gie)&&(bus_err))
||((~alu_gie)&&(div_error))
||((~alu_gie)&&(fpu_error))
||((~alu_gie)&&(alu_illegal));
 
// The sleep register. Setting the sleep register causes the CPU to
// sleep until the next interrupt. Setting the sleep register within
// interrupt mode causes the processor to halt until a reset. This is
// a panic/fault halt. The trick is that you cannot be allowed to
// set the sleep bit and switch to supervisor mode in the same
// instruction: users are not allowed to halt the CPU.
always @(posedge i_clk)
if ((i_rst)||(w_switch_to_interrupt))
sleep <= 1'b0;
else if ((wr_reg_ce)&&(wr_write_cc)&&(~alu_gie))
// In supervisor mode, we have no protections. The
// supervisor can set the sleep bit however he wants.
// Well ... not quite. Switching to user mode and
// sleep mode shouold only be possible if the interrupt
// flag isn't set.
// Thus: if (i_interrupt)&&(wr_spreg_vl[GIE])
// don't set the sleep bit
// otherwise however it would o.w. be set
sleep <= (wr_spreg_vl[`CPU_SLEEP_BIT])
&&((~i_interrupt)||(~wr_spreg_vl[`CPU_GIE_BIT]));
else if ((wr_reg_ce)&&(wr_write_cc)&&(wr_spreg_vl[`CPU_GIE_BIT]))
// In user mode, however, you can only set the sleep
// mode while remaining in user mode. You can't switch
// to sleep mode *and* supervisor mode at the same
// time, lest you halt the CPU.
sleep <= wr_spreg_vl[`CPU_SLEEP_BIT];
 
always @(posedge i_clk)
if ((i_rst)||(w_switch_to_interrupt))
step <= 1'b0;
else if ((wr_reg_ce)&&(~alu_gie)&&(wr_write_ucc))
step <= wr_spreg_vl[`CPU_STEP_BIT];
else if (((alu_pc_valid)||(mem_pc_valid))&&(step)&&(gie))
step <= 1'b0;
 
// The GIE register. Only interrupts can disable the interrupt register
assign w_switch_to_interrupt = (gie)&&(
// On interrupt (obviously)
((i_interrupt)&&(~alu_phase)&&(~bus_lock))
// If we are stepping the CPU
||(((alu_pc_valid)||(mem_pc_valid))&&(step)&&(~alu_phase)&&(~bus_lock))
// If we encounter a break instruction, if the break
// enable isn't set.
||((master_ce)&&(break_pending)&&(~break_en))
`ifdef OPT_ILLEGAL_INSTRUCTION
// On an illegal instruction
||(alu_illegal)
`endif
// On division by zero. If the divide isn't
// implemented, div_valid and div_error will be short
// circuited and that logic will be bypassed
||(div_error)
// Same thing on a floating point error. Note that
// fpu_error must *never* be set unless fpu_valid is
// also set as well, else this will fail.
||(fpu_error)
//
||(bus_err)
// If we write to the CC register
||((wr_reg_ce)&&(~wr_spreg_vl[`CPU_GIE_BIT])
&&(wr_reg_id[4])&&(wr_write_cc))
);
assign w_release_from_interrupt = (~gie)&&(~i_interrupt)
// Then if we write the sCC register
&&(((wr_reg_ce)&&(wr_spreg_vl[`CPU_GIE_BIT])
&&(wr_write_scc))
);
always @(posedge i_clk)
if (i_rst)
gie <= 1'b0;
else if (w_switch_to_interrupt)
gie <= 1'b0;
else if (w_release_from_interrupt)
gie <= 1'b1;
 
initial trap = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(w_release_from_interrupt))
trap <= 1'b0;
else if ((alu_gie)&&(wr_reg_ce)&&(~wr_spreg_vl[`CPU_GIE_BIT])
&&(wr_write_ucc)) // &&(wr_reg_id[4]) implied
trap <= 1'b1;
else if ((wr_reg_ce)&&(wr_write_ucc)&&(~alu_gie))
trap <= (trap)&&(wr_spreg_vl[`CPU_TRAP_BIT]);
 
initial ubreak = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(w_release_from_interrupt))
ubreak <= 1'b0;
else if ((op_gie)&&(break_pending)&&(w_switch_to_interrupt))
ubreak <= 1'b1;
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce)&&(wr_write_ucc))
ubreak <= (ubreak)&&(wr_spreg_vl[`CPU_BREAK_BIT]);
 
 
`ifdef OPT_ILLEGAL_INSTRUCTION
initial ill_err_i = 1'b0;
always @(posedge i_clk)
if (i_rst)
ill_err_i <= 1'b0;
// Only the debug interface can clear this bit
else if ((dbgv)&&(wr_write_scc))
ill_err_i <= (ill_err_i)&&(wr_spreg_vl[`CPU_ILL_BIT]);
else if ((alu_illegal)&&(~alu_gie))
ill_err_i <= 1'b1;
initial ill_err_u = 1'b0;
always @(posedge i_clk)
// The bit is automatically cleared on release from interrupt
// or reset
if ((i_rst)||(w_release_from_interrupt))
ill_err_u <= 1'b0;
// If the supervisor (or debugger) writes to this register,
// clearing the bit, then clear it
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce)&&(wr_write_ucc))
ill_err_u <=((ill_err_u)&&(wr_spreg_vl[`CPU_ILL_BIT]));
else if ((alu_illegal)&&(alu_gie))
ill_err_u <= 1'b1;
`else
assign ill_err_u = 1'b0;
assign ill_err_i = 1'b0;
`endif
// Supervisor/interrupt bus error flag -- this will crash the CPU if
// ever set.
initial ibus_err_flag = 1'b0;
always @(posedge i_clk)
if (i_rst)
ibus_err_flag <= 1'b0;
else if ((dbgv)&&(wr_write_scc))
ibus_err_flag <= (ibus_err_flag)&&(wr_spreg_vl[`CPU_BUSERR_BIT]);
else if ((bus_err)&&(~alu_gie))
ibus_err_flag <= 1'b1;
// User bus error flag -- if ever set, it will cause an interrupt to
// supervisor mode.
initial ubus_err_flag = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(w_release_from_interrupt))
ubus_err_flag <= 1'b0;
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce)&&(wr_write_ucc))
ubus_err_flag <= (ubus_err_flag)&&(wr_spreg_vl[`CPU_BUSERR_BIT]);
else if ((bus_err)&&(alu_gie))
ubus_err_flag <= 1'b1;
 
generate
if (IMPLEMENT_DIVIDE != 0)
begin
reg r_idiv_err_flag, r_udiv_err_flag;
 
// Supervisor/interrupt divide (by zero) error flag -- this will
// crash the CPU if ever set. This bit is thus available for us
// to be able to tell if/why the CPU crashed.
initial r_idiv_err_flag = 1'b0;
always @(posedge i_clk)
if (i_rst)
r_idiv_err_flag <= 1'b0;
else if ((dbgv)&&(wr_write_scc))
r_idiv_err_flag <= (r_idiv_err_flag)&&(wr_spreg_vl[`CPU_DIVERR_BIT]);
else if ((div_error)&&(~alu_gie))
r_idiv_err_flag <= 1'b1;
// User divide (by zero) error flag -- if ever set, it will
// cause a sudden switch interrupt to supervisor mode.
initial r_udiv_err_flag = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(w_release_from_interrupt))
r_udiv_err_flag <= 1'b0;
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce)
&&(wr_write_ucc))
r_udiv_err_flag <= (r_udiv_err_flag)&&(wr_spreg_vl[`CPU_DIVERR_BIT]);
else if ((div_error)&&(alu_gie))
r_udiv_err_flag <= 1'b1;
 
assign idiv_err_flag = r_idiv_err_flag;
assign udiv_err_flag = r_udiv_err_flag;
end else begin
assign idiv_err_flag = 1'b0;
assign udiv_err_flag = 1'b0;
end endgenerate
 
generate
if (IMPLEMENT_FPU !=0)
begin
// Supervisor/interrupt floating point error flag -- this will
// crash the CPU if ever set.
reg r_ifpu_err_flag, r_ufpu_err_flag;
initial r_ifpu_err_flag = 1'b0;
always @(posedge i_clk)
if (i_rst)
r_ifpu_err_flag <= 1'b0;
else if ((dbgv)&&(wr_write_scc))
r_ifpu_err_flag <= (r_ifpu_err_flag)&&(wr_spreg_vl[`CPU_FPUERR_BIT]);
else if ((fpu_error)&&(fpu_valid)&&(~alu_gie))
r_ifpu_err_flag <= 1'b1;
// User floating point error flag -- if ever set, it will cause
// a sudden switch interrupt to supervisor mode.
initial r_ufpu_err_flag = 1'b0;
always @(posedge i_clk)
if ((i_rst)&&(w_release_from_interrupt))
r_ufpu_err_flag <= 1'b0;
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce)
&&(wr_write_ucc))
r_ufpu_err_flag <= (r_ufpu_err_flag)&&(wr_spreg_vl[`CPU_FPUERR_BIT]);
else if ((fpu_error)&&(alu_gie)&&(fpu_valid))
r_ufpu_err_flag <= 1'b1;
 
assign ifpu_err_flag = r_ifpu_err_flag;
assign ufpu_err_flag = r_ufpu_err_flag;
end else begin
assign ifpu_err_flag = 1'b0;
assign ufpu_err_flag = 1'b0;
end endgenerate
 
`ifdef OPT_VLIW
reg r_ihalt_phase, r_uhalt_phase;
 
initial r_ihalt_phase = 0;
initial r_uhalt_phase = 0;
always @(posedge i_clk)
if (i_rst)
r_ihalt_phase <= 1'b0;
else if ((~alu_gie)&&(alu_pc_valid)&&(~clear_pipeline))
r_ihalt_phase <= alu_phase;
always @(posedge i_clk)
if ((i_rst)||(w_release_from_interrupt))
r_uhalt_phase <= 1'b0;
else if ((alu_gie)&&(alu_pc_valid))
r_uhalt_phase <= alu_phase;
else if ((~alu_gie)&&(wr_reg_ce)&&(wr_write_ucc))
r_uhalt_phase <= wr_spreg_vl[`CPU_PHASE_BIT];
 
assign ihalt_phase = r_ihalt_phase;
assign uhalt_phase = r_uhalt_phase;
`else
assign ihalt_phase = 1'b0;
assign uhalt_phase = 1'b0;
`endif
 
//
// Write backs to the PC register, and general increments of it
// We support two: upc and ipc. If the instruction is normal,
// we increment upc, if interrupt level we increment ipc. If
// the instruction writes the PC, we write whichever PC is appropriate.
//
// Do we need to all our partial results from the pipeline?
// What happens when the pipeline has gie and ~gie instructions within
// it? Do we clear both? What if a gie instruction tries to clear
// a non-gie instruction?
always @(posedge i_clk)
if ((wr_reg_ce)&&(wr_reg_id[4])&&(wr_write_pc))
upc <= wr_spreg_vl[(AW-1):0];
else if ((alu_gie)&&
(((alu_pc_valid)&&(~clear_pipeline))
||(mem_pc_valid)))
upc <= alu_pc;
 
always @(posedge i_clk)
if (i_rst)
ipc <= RESET_ADDRESS;
else if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_pc))
ipc <= wr_spreg_vl[(AW-1):0];
else if ((~alu_gie)&&
(((alu_pc_valid)&&(~clear_pipeline))
||(mem_pc_valid)))
ipc <= alu_pc;
 
always @(posedge i_clk)
if (i_rst)
pf_pc <= RESET_ADDRESS;
else if ((w_switch_to_interrupt)||((~gie)&&(w_clear_icache)))
pf_pc <= ipc;
else if ((w_release_from_interrupt)||((gie)&&(w_clear_icache)))
pf_pc <= upc;
else if ((wr_reg_ce)&&(wr_reg_id[4] == gie)&&(wr_write_pc))
pf_pc <= wr_spreg_vl[(AW-1):0];
`ifdef OPT_PIPELINED
else if ((dcd_early_branch)&&(~clear_pipeline))
pf_pc <= dcd_branch_pc + 1;
else if ((new_pc)||((~dcd_stalled)&&(pf_valid)))
pf_pc <= pf_pc + {{(AW-1){1'b0}},1'b1};
`else
else if ((alu_gie==gie)&&(
((alu_pc_valid)&&(~clear_pipeline))
||(mem_pc_valid)))
pf_pc <= alu_pc;
`endif
 
initial new_pc = 1'b1;
always @(posedge i_clk)
if ((i_rst)||(i_clear_pf_cache))
new_pc <= 1'b1;
else if (w_switch_to_interrupt)
new_pc <= 1'b1;
else if (w_release_from_interrupt)
new_pc <= 1'b1;
else if ((wr_reg_ce)&&(wr_reg_id[4] == gie)&&(wr_write_pc))
new_pc <= 1'b1;
else
new_pc <= 1'b0;
 
`ifdef OPT_PIPELINED
reg r_clear_icache;
initial r_clear_icache = 1'b1;
always @(posedge i_clk)
if ((i_rst)||(i_clear_pf_cache))
r_clear_icache <= 1'b1;
else if ((wr_reg_ce)&&(wr_write_scc))
r_clear_icache <= wr_spreg_vl[`CPU_CLRCACHE_BIT];
else
r_clear_icache <= 1'b0;
assign w_clear_icache = r_clear_icache;
`else
assign w_clear_icache = 1'b0;
`endif
 
//
// The debug interface
generate
if (AW<32)
begin
always @(posedge i_clk)
begin
o_dbg_reg <= regset[i_dbg_reg];
if (i_dbg_reg[3:0] == `CPU_PC_REG)
o_dbg_reg <= {{(32-AW){1'b0}},(i_dbg_reg[4])?upc:ipc};
else if (i_dbg_reg[3:0] == `CPU_CC_REG)
begin
o_dbg_reg[14:0] <= (i_dbg_reg[4])?w_uflags:w_iflags;
o_dbg_reg[31:23] <= w_cpu_info;
o_dbg_reg[`CPU_GIE_BIT] <= gie;
end
end
end else begin
always @(posedge i_clk)
begin
o_dbg_reg <= regset[i_dbg_reg];
if (i_dbg_reg[3:0] == `CPU_PC_REG)
o_dbg_reg <= (i_dbg_reg[4])?upc:ipc;
else if (i_dbg_reg[3:0] == `CPU_CC_REG)
begin
o_dbg_reg[14:0] <= (i_dbg_reg[4])?w_uflags:w_iflags;
o_dbg_reg[31:23] <= w_cpu_info;
o_dbg_reg[`CPU_GIE_BIT] <= gie;
end
end
end endgenerate
 
always @(posedge i_clk)
o_dbg_cc <= { o_break, bus_err, gie, sleep };
 
always @(posedge i_clk)
r_halted <= (i_halt)&&(
// To be halted, any long lasting instruction must
// be completed.
(~pf_cyc)&&(~mem_busy)&&(~alu_busy)
&&(~div_busy)&&(~fpu_busy)
// Operations must either be valid, or illegal
&&((opvalid)||(i_rst)||(dcd_illegal))
// Decode stage must be either valid, in reset, or ill
&&((dcdvalid)||(i_rst)||(pf_illegal)));
assign o_dbg_stall = ~r_halted;
 
//
//
// Produce accounting outputs: Account for any CPU stalls, so we can
// later evaluate how well we are doing.
//
//
assign o_op_stall = (master_ce)&&(op_stall);
assign o_pf_stall = (master_ce)&&(~pf_valid);
assign o_i_count = (alu_pc_valid)&&(~clear_pipeline);
 
`ifdef DEBUG_SCOPE
reg [31:0] r_stack;
always @(posedge i_clk)
if ((wr_reg_ce)&&(wr_reg_id == 5'h0d))
r_stack <= wr_gpreg_vl;
reg r_stack_pre, r_stack_post;
always @(posedge i_clk)
r_stack_pre <= (r_stack == 32'h03fff);
always @(posedge i_clk)
r_stack_post <= (r_stack == 32'h03eeb);
 
always @(posedge i_clk)
o_debug <= {
/*
o_break, i_wb_err, pf_pc[1:0],
flags,
pf_valid, dcdvalid, opvalid, alu_valid, mem_valid,
op_ce, alu_ce, mem_ce,
//
master_ce, opvalid_alu, opvalid_mem,
//
alu_stall, mem_busy, op_pipe, mem_pipe_stalled,
mem_we,
// ((opvalid_alu)&&(alu_stall))
// ||((opvalid_mem)&&(~op_pipe)&&(mem_busy))
// ||((opvalid_mem)&&( op_pipe)&&(mem_pipe_stalled)));
// opA[23:20], opA[3:0],
gie, sleep, wr_reg_ce, wr_gpreg_vl[4:0]
*/
/*
i_rst, master_ce, (new_pc),
((dcd_early_branch)&&(dcdvalid)),
pf_valid, pf_illegal,
op_ce, dcd_ce, dcdvalid, dcd_stalled,
pf_cyc, pf_stb, pf_we, pf_ack, pf_stall, pf_err,
pf_pc[7:0], pf_addr[7:0]
*/
 
(i_wb_err)||(r_stack_post), (gie)||(r_stack_pre), (alu_illegal)||(r_stack_post),
(new_pc)||((dcd_early_branch)&&(~clear_pipeline)),
mem_busy,
(mem_busy)?{ (o_wb_gbl_stb|o_wb_lcl_stb), o_wb_we,
o_wb_addr[8:0] }
: { instruction[31:21] },
pf_valid, (pf_valid) ? alu_pc[14:0]
:{ pf_cyc, pf_stb, pf_pc[12:0] }
 
/*
i_wb_err, gie, new_pc, dcd_early_branch, // 4
pf_valid, pf_cyc, pf_stb, instruction_pc[0], // 4
instruction[30:27], // 4
dcd_gie, mem_busy, o_wb_gbl_cyc, o_wb_gbl_stb, // 4
dcdvalid,
((dcd_early_branch)&&(~clear_pipeline)) // 15
? dcd_branch_pc[14:0]:pf_pc[14:0]
*/
};
`endif
 
/*
always @(posedge i_clk)
o_debug <= {
// External control interaction (4b)
i_halt, i_rst, i_clear_cache, o_break,
// Bus interaction (8b)
pf_cyc,(o_wb_gbl_cyc|o_wb_lcl_cyc), o_wb_gbl_stb, o_wb_lcl_stb,
o_wb_we, i_wb_ack, i_wb_stall, i_wb_err,
// PC control (4b)
gie, new_pc, dcd_early_branch, 1'b0,
// Our list of pipeline stage values (8b)
pf_valid, pf_illegal, dcdvalid, opvalid, alu_valid, mem_valid,
alu_pc_valid, mem_pc_valid,
// Our list of circuit enables ... (8b)
(new_pc)||((dcd_early_branch)&&(~clear_pipeline)),
dcd_ce, op_ce, alu_ce, mem_ce, wr_reg_ce, wr_flags_ce,
1'b0,
// Useful PC values (64b)
((dcd_early_branch)&&(~clear_pipeline))
? dcd_branch_pc[15:0]:pf_pc[15:0],
(gie)?upc[15:0]:ipc[15:0], instruction_pc[15:0], instruction[31:16] };
*/
endmodule
/rtl/rtcdate.v
0,0 → 1,211
///////////////////////////////////////////////////////////////////////////
//
// Filename: rtcdate.v
//
// Project: A Wishbone Controlled Real--time Clock Core
//
// Purpose:
// This core provides a real-time date function that can be coupled with
// a real-time clock. The date provided is in Binary Coded Decimal (bcd)
// form, and available for reading and writing over the Wishbone Bus.
//
// WARNING: Race conditions exist when updating the date across the Wishbone
// bus at or near midnight. (This should be obvious, but it bears
// stating.) Specifically, if the update command shows up at the same
// clock as the ppd clock, then the ppd clock will be ignored and the
// new date will be the date of the day following midnight. However,
// if the update command shows up one clock before the ppd, then the date
// may be updated, but may have problems dealing with the last day of the
// month or year. To avoid race conditions, update the date sometime
// after the stroke of midnight and before 5 clocks before the next
// midnight. If you are concerned that you might hit a race condition,
// just read the clock again (5+ clocks later) to make certain you set
// it correctly.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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 rtcdate(i_clk, i_ppd, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_data,
o_wb_ack, o_wb_stall, o_wb_data);
input i_clk;
// A one part per day signal, i.e. basically a clock enable line that
// controls when the beginning of the day happens. This line should
// be high on the very last second of any day in order for the rtcdate
// module to always have the right date.
input i_ppd;
// Wishbone inputs
input i_wb_cyc, i_wb_stb, i_wb_we;
input [31:0] i_wb_data;
// Wishbone outputs
output reg o_wb_ack;
output wire o_wb_stall;
output wire [31:0] o_wb_data;
 
 
reg [5:0] r_day;
reg [4:0] r_mon;
reg [13:0] r_year;
 
reg last_day_of_month, last_day_of_year, is_leap_year;
reg [5:0] days_per_month;
initial days_per_month = 6'h31; // Remember, this is BCD
always @(posedge i_clk)
begin // Clock 3
case(r_mon)
5'h01: days_per_month <= 6'h31; // Jan
5'h02: days_per_month <= (is_leap_year)? 6'h29:6'h28;
5'h03: days_per_month <= 6'h31; // March
5'h04: days_per_month <= 6'h30; // April
5'h05: days_per_month <= 6'h31; // May
5'h06: days_per_month <= 6'h30; // June
5'h07: days_per_month <= 6'h31; // July
5'h08: days_per_month <= 6'h31; // August
5'h09: days_per_month <= 6'h30; // Sept
5'h10: days_per_month <= 6'h31; // October
5'h11: days_per_month <= 6'h30; // November
5'h12: days_per_month <= 6'h31; // December
default: days_per_month <= 6'h31; // Invalid month
endcase
end
initial last_day_of_month = 1'b0;
always @(posedge i_clk) // Clock 4
last_day_of_month <= (r_day >= days_per_month);
initial last_day_of_year = 1'b0;
always @(posedge i_clk) // Clock 5
last_day_of_year <= (last_day_of_month) && (r_mon == 5'h12);
 
reg year_divisible_by_four, century_year, four_century_year;
always @(posedge i_clk) // Clock 1
year_divisible_by_four<= ((~r_year[0])&&(r_year[4]==r_year[1]));
always @(posedge i_clk) // Clock 1
century_year <= (r_year[7:0] == 8'h00);
always @(posedge i_clk) // Clock 1
four_century_year <= ((~r_year[8])&&((r_year[12]==r_year[9])));
always @(posedge i_clk) // Clock 2
is_leap_year <= (year_divisible_by_four)&&((~century_year)
||((century_year)&&(four_century_year)));
 
 
// Adjust the day of month
reg [5:0] next_day, fixd_day;
always @(posedge i_clk)
if (last_day_of_month)
next_day <= 6'h01;
else if (r_day[3:0] != 4'h9)
next_day <= { r_day[5:4], (r_day[3:0]+4'h1) };
else
next_day <= { (r_day[5:4]+2'h1), 4'h0 };
always @(posedge i_clk)
if ((r_day == 0)||(r_day > 6'h31)||(r_day[3:0] > 4'h9))
fixd_day <= 6'h01;
else
fixd_day <= r_day;
 
initial r_day = 6'h01;
always @(posedge i_clk)
begin // Depends upon 9 inputs
if (i_ppd)
r_day <= next_day;
else if (~o_wb_ack)
r_day <= fixd_day;
 
if ((i_wb_stb)&&(i_wb_we)&&(~i_wb_data[7]))
r_day <= i_wb_data[5:0];
end
 
// Adjust the month of the year
reg [4:0] next_mon, fixd_mon;
always @(posedge i_clk)
if (last_day_of_year)
next_mon <= 5'h01;
else if ((last_day_of_month)&&(r_mon[3:0] != 4'h9))
next_mon <= { r_mon[4], (r_mon[3:0] + 4'h1) };
else if (last_day_of_month)
begin
next_mon[3:0] <= 4'h0;
next_mon[4] <= 1;
end else
next_mon <= r_mon;
always @(posedge i_clk)
if ((r_mon == 0)||(r_mon > 5'h12)||(r_mon[3:0] > 4'h9))
fixd_mon <= 5'h01;
else
fixd_mon <= r_mon;
initial r_mon = 5'h01;
always @(posedge i_clk)
begin // Depeds upon 9 inputs
if (i_ppd)
r_mon <= next_mon;
else if (~o_wb_ack)
r_mon <= fixd_mon;
 
if ((i_wb_stb)&&(i_wb_we)&&(~i_wb_data[15]))
r_mon <= i_wb_data[12:8];
end
 
// Adjust the year
reg [13:0] next_year;
reg [2:0] next_year_c;
always @(posedge i_clk)
begin // Takes 5 clocks to propagate
next_year_c[0] <= (r_year[ 3: 0]>=4'h9);
next_year_c[1] <= (r_year[ 7: 4]>4'h9)||((r_year[ 7: 4]==4'h9)&&(next_year_c[0]));
next_year_c[2] <= (r_year[11: 8]>4'h9)||((r_year[11: 8]==4'h9)&&(next_year_c[1]));
next_year[ 3: 0] <= (next_year_c[0])? 4'h0:(r_year[ 3: 0]+4'h1);
next_year[ 7: 4] <= (next_year_c[1])? 4'h0:
(next_year_c[0])?(r_year[ 7: 4]+4'h1)
: (r_year[7:4]);
next_year[11: 8] <= (next_year_c[2])? 4'h0:
(next_year_c[1])?(r_year[11: 8]+4'h1)
: (r_year[11: 8]);
next_year[13:12] <= (next_year_c[2])?(r_year[13:12]+2'h1):r_year[13:12];
end
 
initial r_year = 14'h2000;
always @(posedge i_clk)
begin // 11 inputs
// Deal with any out of bounds conditions
if (r_year[3:0] > 4'h9)
r_year[3:0] <= 4'h0;
if (r_year[7:4] > 4'h9)
r_year[7:4] <= 4'h0;
if (r_year[11:8] > 4'h9)
r_year[11:8] <= 4'h0;
if ((i_ppd)&&(last_day_of_year))
r_year <= next_year;
 
if ((i_wb_stb)&&(i_wb_we)&&(~i_wb_data[31]))
r_year <= i_wb_data[29:16];
end
 
always @(posedge i_clk)
o_wb_ack <= (i_wb_stb);
assign o_wb_stall = 1'b0;
assign o_wb_data = { 2'h0, r_year, 3'h0, r_mon, 2'h0, r_day };
endmodule
/rtl/xioddr.v
0,0 → 1,76
////////////////////////////////////////////////////////////////////////////////
//
// Filename: xioddr.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: For the DDR3 SDRAM, this handles the Xilinx specific portions
// of the IO necessary to make this happen for one pin only.
//
// 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 xioddr(i_clk, i_oe, i_v, o_v, io_w);
input i_clk, i_oe;
input [1:0] i_v;
output [1:0] o_v;
inout io_w;
 
wire w_internal;
 
ODDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"),
.INIT(1'b0),
.SRTYPE("SYNC")
) ODDRi(
.Q(w_internal),
.C(i_clk),
.CE(1'b1),
.D1(i_v[0]),
.D2(i_v[1]),
.R(1'b0),
.S(1'b0));
 
IDDR #(
.DDR_CLK_EDGE("OPPOSITE_EDGE"),
.INIT_Q1(1'b0),
.INIT_Q2(1'b0),
.SRTYPE("SYNC")
) IDDRi(
.Q1(o_v[0]),
.Q2(o_v[1]),
.C(i_clk),
.CE(1'b1),
.D(io_w),
.R(1'b0),
.S(1'b0));
 
assign io_w = (i_oe) ? w_internal:1'bz;
 
endmodule
/rtl/wbddrsdram.v
0,0 → 1,102
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wbddrsdram.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:
//
// 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 wbddrsdram(i_clk_200mhz,
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
o_wb_ack, o_wb_stb, o_wb_data,
o_ddr_reset_n, o_ddr_cke,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
o_ddr_dqs,
o_ddr_addr, o_ddr_ba, o_ddr_data, i_ddr_data);
input i_clk_200mhz;
// Wishbone inputs
input i_wb_cyc, i_wb_stb, i_wb_we;
input [25:0] i_wb_addr;
input [31:0] i_wb_data;
// Wishbone outputs
output reg o_wb_ack;
output reg o_wb_stall;
output reg [31:0] o_wb_data;
// DDR3 RAM Controller
output wire o_ddr_reset_n;
output wire o_ddr_reset_cke;
// Control outputs
output reg o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n,o_ddr_we_n;
// DQS outputs:set to 3'b010 when data is active, 3'b100 (i.e. 2'bzz) ow
output reg [2:0] o_ddr_dqs;
// Address outputs
output reg [13:0] o_ddr_addr;
output reg [2:0] o_ddr_ba;
// And the data inputs and outputs
output reg [31:0] o_ddr_data;
input i_ddr_data;
 
//
// tWTR = 7.5
// tRRD = 7.5
// tREFI= 7.8
// tFAW = 45
// tRTP = 7.5
// tCKE = 5.625
// tRFC = 160
// tRP = 13.5
// tRAS = 36
// tRCD = 13.5
//
// RESET:
// 1. Hold o_reset_n = 1'b0; for 200 us, or 40,000 clocks (65536 perhaps?)
// Hold cke low during this time as well
// The clock should be free running into the chip during this time
// Leave command in NOOP state: {cs,ras,cas,we} = 4'h7;
// ODT must be held low
// 2. Hold cke low for another 500us, or 100,000 clocks
// 3. Raise CKE, continue outputting a NOOP for
// tXPR, tDLLk, and tZQInit
// 4. Load MRS2, wait tMRD
// 4. Load MRS3, wait tMRD
// 4. Load MRS1, wait tMOD
// Before using the SDRAM, we'll need to program at least 3 of the mode
// registers, if not all 4.
// tMOD clocks are required to program the mode registers, during which
// time the RAM must be idle.
//
// NOOP: CS low, RAS, CAS, and WE high
 
// Need to set o_wb_dqs high one clock prior to any read.
// As per spec, ODT = 0 during reads
assign o_ddr_odt = ~o_ddr_we_n;
endmodule
/rtl/gpsclock_tb.v
0,0 → 1,137
////////////////////////////////////////////////////////////////////////////////
//
// Filename: gpsclock_tb.v
//
// Project: A GPS Schooled Clock Core
//
// Purpose: Provide a test bench, internal to an FPGA, whereby the GPS
// clock module can be tested.
//
//
// 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 gpsclock_tb(i_clk, i_lcl_pps, o_pps,
i_wb_cyc_stb, i_wb_we, i_wb_addr, i_wb_data,
o_wb_ack, o_wb_stall, o_wb_data,
i_err, i_count, i_step);
parameter DW=32, RW=64;
input i_clk, i_lcl_pps;
output reg o_pps; // To our local circuitry
// Wishbone Configuration interface
input i_wb_cyc_stb, i_wb_we;
input [2:0] i_wb_addr;
input [(DW-1):0] i_wb_data;
output reg o_wb_ack;
output wire o_wb_stall;
output reg [(DW-1):0] o_wb_data;
// Status and timing outputs
input [(RW-1):0] i_err, // Fraction of a second err
i_count, // Fraction of a second
i_step; // 2^RW / clock speed (in Hz)
 
 
reg [31:0] r_jump, r_maxcount;
reg r_halt;
 
 
//
//
//
// Wishbone access ...
//
//
//
always @(posedge i_clk)
if ((i_wb_cyc_stb)&&(i_wb_we))
begin
case(i_wb_addr)
3'b000: r_maxcount <= i_wb_data;
3'b001: r_jump <= i_wb_data;
// 2'b11: r_def_step <= i_wb_data;
default: begin end
// r_defstep <= i_wb_data;
endcase
end else
r_jump <= 32'h00;
 
reg [31:0] r_err, r_lcl;
reg [63:0] r_count, r_step;
 
initial r_lcl = 32'h000;
initial r_halt = 1'b0;
always @(posedge i_clk)
case (i_wb_addr)
3'b000: o_wb_data <= r_maxcount;
3'b001: begin o_wb_data <= r_lcl; r_halt <= 1'b1; end // { 31'h00, r_halt };
3'b010: begin o_wb_data <= i_err[63:32]; r_halt <= 1'b1; end
3'b011: o_wb_data <= r_err[31:0];
3'b100: o_wb_data <= r_count[63:32];
3'b101: o_wb_data <= r_count[31:0];
3'b110: o_wb_data <= r_step[63:32];
3'b111: begin o_wb_data <= r_step[31:0]; r_halt <= 1'b0; end
default: o_wb_data <= 0;
endcase
 
always @(posedge i_clk)
o_wb_ack <= i_wb_cyc_stb;
assign o_wb_stall = 1'b0;
 
//
//
// Generate a PPS signal
//
//
reg [31:0] r_ctr;
always @(posedge i_clk)
if (r_ctr >= r_maxcount-1)
r_ctr <= r_ctr+1-r_maxcount+r_jump;
else
r_ctr <= r_ctr+1+r_jump;
always @(posedge i_clk)
if (r_ctr >= r_maxcount-1)
o_pps <= 1'b1;
else
o_pps <= 1'b0;
 
reg [31:0] lcl_counter;
always @(posedge i_clk)
lcl_counter <= lcl_counter + 32'h001;
 
always @(posedge i_clk)
if ((~r_halt)&&(i_lcl_pps))
begin
r_err <= i_err[31:0];
r_count <= i_count;
r_step <= i_step;
r_lcl <= lcl_counter;
end
 
 
endmodule
 
/rtl/toplevel.v
0,0 → 1,459
////////////////////////////////////////////////////////////////////////////////
//
// Filename: toplevel.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: This is the top level Verilog file. It is to be contrasted
// with the other top level Verilog file in this same project in
// that *this* top level is designed to create a *safe*, low-speed
// (100MHz), configuration that can be used to test peripherals and other
// things on the way to building a full featured high speed configuration.
//
// Differences between this file and fasttop.v should be limited to speed
// related differences (such as the number of counts per UART baud), and
// the different daughter module: fastmaster.v (for 200MHz designs) vs
// busmaster.v (for 100MHz designs).
//
// 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_100mhz, i_reset_btn,
i_sw, // Switches
i_btn, // Buttons
o_led, // Single color LEDs
o_clr_led0, o_clr_led1, o_clr_led2, o_clr_led3, // Color LEDs
// RS232 UART
i_uart_rx, o_uart_tx,
// Quad-SPI Flash control
o_qspi_sck, o_qspi_cs_n, io_qspi_dat,
// Missing: Ethernet
o_eth_mdclk, io_eth_mdio,
// Memory
o_ddr_reset_n, o_ddr_cke, o_ddr_ck_p, o_ddr_ck_n,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
io_ddr_dqs_p, io_ddr_dqs_n,
o_ddr_addr, o_ddr_ba,
io_ddr_data, o_ddr_dm, o_ddr_odt,
// SD Card
o_sd_sck, io_sd_cmd, io_sd, i_sd_cs, i_sd_wp,
// GPS Pmod
i_gps_pps, i_gps_3df, i_gps_rx, o_gps_tx,
// OLED Pmod
o_oled_sck, o_oled_cs_n, o_oled_mosi, o_oled_dcn, o_oled_reset_n,
o_oled_vccen, o_oled_pmoden,
// PMod I/O
i_aux_rx, i_aux_rts, o_aux_tx, o_aux_cts
);
input i_clk_100mhz, i_reset_btn;
input [3:0] i_sw; // Switches
input [3:0] i_btn; // Buttons
output wire [3:0] o_led; // LED
output wire [2:0] o_clr_led0, o_clr_led1, o_clr_led2, o_clr_led3;
// UARTs
input i_uart_rx;
output wire o_uart_tx;
// Quad SPI flash
output wire o_qspi_sck, o_qspi_cs_n;
inout [3:0] io_qspi_dat;
// Ethernet // Not yet implemented
// Ethernet control (MDIO)
output wire o_eth_mdclk;
inout wire io_eth_mdio;
// DDR3 SDRAM
output wire o_ddr_reset_n;
output wire o_ddr_cke;
output wire o_ddr_ck_p, o_ddr_ck_n;
output wire o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n;
inout [1:0] io_ddr_dqs_p, io_ddr_dqs_n;
output wire [13:0] o_ddr_addr;
output wire [2:0] o_ddr_ba;
inout [15:0] io_ddr_data;
//
output wire [1:0] o_ddr_dm;
output wire o_ddr_odt;
// SD Card
output wire o_sd_sck;
inout io_sd_cmd;
inout [3:0] io_sd;
input i_sd_cs;
input i_sd_wp;
// GPS PMod
input i_gps_pps, i_gps_3df, i_gps_rx;
output wire o_gps_tx;
// OLEDRGB PMod
output wire o_oled_sck, o_oled_cs_n, o_oled_mosi,
o_oled_dcn, o_oled_reset_n, o_oled_vccen,
o_oled_pmoden;
// Aux UART
input i_aux_rx, i_aux_rts;
output wire o_aux_tx, o_aux_cts;
 
// Build our master clock
wire i_clk, clk_for_ddr, clk2_unused, enet_clk, clk5_unused,
clk_feedback, clk_locked;
PLLE2_BASE #(
.BANDWIDTH("OPTIMIZED"), // OPTIMIZED, HIGH, LOW
.CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB, (-360-360)
.CLKIN1_PERIOD(10.0), // Input clock period in ns to ps resolution
// CLKOUT0_DIVIDE - CLKOUT5_DIVIDE: divide amount for each CLKOUT(1-128)
.CLKFBOUT_MULT(8), // Multiply value for all CLKOUT (2-64)
.CLKOUT0_DIVIDE(8), // 100 MHz (Main clock)
.CLKOUT1_DIVIDE(8), // 100 MHz (DDR3 SDRAM clock)
.CLKOUT2_DIVIDE(16), // 50 MHz (Flash clock, should we need it)
.CLKOUT3_DIVIDE(32), // 25 MHz (Ethernet clock ?)
.CLKOUT4_DIVIDE(16), // 50 MHz (Unused clock?)
.CLKOUT5_DIVIDE(24),
// CLKOUT0_DUTY_CYCLE -- Duty cycle for each CLKOUT
.CLKOUT0_DUTY_CYCLE(0.5),
.CLKOUT1_DUTY_CYCLE(0.5),
.CLKOUT2_DUTY_CYCLE(0.5),
.CLKOUT3_DUTY_CYCLE(0.5),
.CLKOUT4_DUTY_CYCLE(0.5),
.CLKOUT5_DUTY_CYCLE(0.5),
// CLKOUT0_PHASE -- phase offset for each CLKOUT
.CLKOUT0_PHASE(0.0),
.CLKOUT1_PHASE(90.0),
.CLKOUT2_PHASE(0.0),
.CLKOUT3_PHASE(0.0),
.CLKOUT4_PHASE(0.0),
.CLKOUT5_PHASE(0.0),
.DIVCLK_DIVIDE(1), // Master division value , (1-56)
.REF_JITTER1(0.0), // Reference input jitter in UI (0.000-0.999)
.STARTUP_WAIT("FALSE") // Delayu DONE until PLL Locks, ("TRUE"/"FALSE")
) genclock(
// Clock outputs: 1-bit (each) output
.CLKOUT0(i_clk),
.CLKOUT1(clk_for_ddr),
.CLKOUT2(clk2_unused), // Reserved for flash, should we need it
.CLKOUT3(enet_clk),
.CLKOUT4(clk4_unused),
.CLKOUT5(clk5_unused),
.CLKFBOUT(clk_feedback), // 1-bit output, feedback clock
.LOCKED(clk_locked),
.CLKIN1(i_clk_100mhz),
.PWRDWN(1'b0),
.RST(1'b0),
.CLKFBIN(clk_feedback) // 1-bit input, feedback clock
);
// UART interface
wire [29:0] bus_uart_setup;
assign bus_uart_setup = 30'h10000019; // 4MBaud, 7 bits
 
wire [7:0] rx_data, tx_data;
wire rx_break, rx_parity_err, rx_frame_err, rx_stb;
wire tx_stb, tx_busy;
 
reg pwr_reset, pre_reset;
initial pwr_reset = 1'b1;
initial pre_reset = 1'b0;
always @(posedge i_clk)
pre_reset <= ~i_reset_btn;
always @(posedge i_clk)
pwr_reset <= pre_reset;
 
wire w_ck_uart, w_uart_tx;
rxuart rcv(i_clk, pwr_reset, bus_uart_setup, i_uart_rx,
rx_stb, rx_data, rx_break,
rx_parity_err, rx_frame_err, w_ck_uart);
txuart txv(i_clk, pwr_reset, bus_uart_setup, 1'b0,
tx_stb, tx_data, o_uart_tx, tx_busy);
 
 
 
 
 
 
//////
//
//
// The WB bus interconnect, herein called busmaster, which handles
// just about ... everything. It is in contrast to the other WB bus
// interconnect, fastmaster, in that the busmaster build permits
// peripherals that can *only* operate at 100MHz, no faster.
//
//
//////
wire w_qspi_sck;
wire [1:0] qspi_bmod;
wire [3:0] qspi_dat;
wire [3:0] i_qspi_dat;
 
//
wire [2:0] w_ddr_dqs;
wire [31:0] wo_ddr_data, wi_ddr_data;
//
wire w_mdio, w_mdwe;
//
wire w_sd_cmd;
wire [3:0] w_sd_data;
busmaster wbbus(i_clk, pwr_reset,
// External USB-UART bus control
rx_stb, rx_data, tx_stb, tx_data, tx_busy,
// Board lights and switches
i_sw, i_btn, o_led,
o_clr_led0, o_clr_led1, o_clr_led2, o_clr_led3,
// Board level PMod I/O
i_aux_rx, o_aux_tx, o_aux_cts, i_gps_rx, o_gps_tx,
// Quad SPI flash
o_qspi_cs_n, w_qspi_sck, qspi_dat, io_qspi_dat, qspi_bmod,
// DDR3 SDRAM
o_ddr_reset_n, o_ddr_cke,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
w_ddr_dqs, o_ddr_addr, o_ddr_ba, wo_ddr_data, wi_ddr_data,
// SD Card
o_sd_sck, w_sd_cmd, w_sd_data, io_sd_cmd, io_sd, i_sd_cs,
// Ethernet control (MDIO) lines
o_eth_mdclk, w_mdio, w_mdwe, io_eth_mdio,
// OLEDRGB PMod wires
o_oled_sck, o_oled_cs_n, o_oled_mosi, o_oled_dcn,
o_oled_reset_n, o_oled_vccen, o_oled_pmoden,
// GPS PMod
i_gps_pps, i_gps_3df
);
 
//////
//
//
// The rest of this file *should* be identical to fasttop.v. Any
// differences should be worked out with meld or some such program
// to keep them to a minimum.
//
//
// Some wires need special treatment, and so are not quite completely
// handled by the bus master. These are handled below.
//
//
//////
 
//
//
// QSPI)BMOD, Quad SPI bus mode, Bus modes are:
// 0? Normal serial mode, one bit in one bit out
// 10 Quad SPI mode, going out
// 11 Quad SPI mode coming from the device (read mode)
//
// ?? Dual mode in (not yet)
// ?? Dual mode out (not yet)
//
//
// assign io_qspi_dat = (~qspi_bmod[1])?({2'b11,1'bz,qspi_dat[0]})
// :((qspi_bmod[0])?(4'bzzzz):(qspi_dat[3:0]));
// assign i_qspi_dat = io_qspi_dat;
//
wire [3:0] i_qspi_dat_ign;
ODDR #(.DDR_CLK_EDGE("OPPOSITE_EDGE"), .INIT(1'b1), .SRTYPE("SYNC"))
qsck(
.Q(o_qspi_sck),
.C(i_clk),
.CE(1'b1),
.D1(w_qspi_sck),
.D2(w_qspi_sck),
.R(1'b0), .S(1'b0));
xioddr qd0(i_clk, (~qspi_bmod[1])|(~qspi_bmod[0]),
{ qspi_dat[0], qspi_dat[0] },
{ i_qspi_dat_ign[0], i_qspi_dat[0] }, io_qspi_dat[0]);
xioddr qd1(i_clk, (qspi_bmod == 2'b10),
{ qspi_dat[1], qspi_dat[1] },
{ i_qspi_dat_ign[1], i_qspi_dat[1] }, io_qspi_dat[1]);
xioddr qd2(i_clk, (~qspi_bmod[1])||(~qspi_bmod[0]),
{ qspi_dat[2], qspi_dat[2] },
{ i_qspi_dat_ign[2], i_qspi_dat[2] }, io_qspi_dat[2]);
xioddr qd3(i_clk, (~qspi_bmod[1])||(~qspi_bmod[0]),
{ qspi_dat[3], qspi_dat[3] },
{ i_qspi_dat_ign[3], i_qspi_dat[3] }, io_qspi_dat[3]);
 
//
// Proposed QSPI mode select, to allow dual I/O mode
// 000 Normal SPI mode
// 001 Dual mode input
// 010 Dual mode, output
// 101 Quad I/O mode input
// 110 Quad I/O mode output
//
//
// assign io_qspi_dat[3:2] = (~qspi_bmod[2]) ? 2'b11
// : (qspi_bmod[0])?2'bzz : qspi_dat[3:2];
// assign io_qspi_dat[1] = (~qspi_bmod[1])?qspi_dat[1]:1'bz;
// assign io_qspi_dat[0] = (qspi_bmod[0])?1'bz : qspi_dat[0];
 
//
//
// The following primitive is necessary in order to gain access
// to the o_qspi_sck pin.
//
//
/*
wire [3:0] su_nc; // Startup primitive, no connect
STARTUPE2 #(
// Leave PROG_USR false to avoid activating the program
// event security feature. Notes state that such a feature
// requires encrypted bitstreams.
.PROG_USR("FALSE"),
// Sets the configuration clock frequency (in ns) for
// simulation.
.SIM_CCLK_FREQ(0.0)
) STARTUPE2_inst (
// CFGCLK, 1'b output: Configuration main clock output -- no connect
.CFGCLK(su_nc[0]),
// CFGMCLK, 1'b output: Configuration internal oscillator clock output
.CFGMCLK(su_nc[1]),
// EOS, 1'b output: Active high output indicating the End Of Startup.
.EOS(su_nc[2]),
// PREQ, 1'b output: PROGRAM request to fabric output
// Only enabled if PROG_USR is set. This lets the fabric know
// that a request has been made (either JTAG or pin pulled low)
// to program the device
.PREQ(su_nc[3]),
// CLK, 1'b input: User start-up clock input
.CLK(1'b0),
// GSR, 1'b input: Global Set/Reset input
.GSR(1'b0),
// GTS, 1'b input: Global 3-state input
.GTS(1'b0),
// KEYCLEARB, 1'b input: Clear AES Decrypter Key input from BBRAM
.KEYCLEARB(1'b0),
// PACK, 1-bit input: PROGRAM acknowledge input
// This pin is only enabled if PROG_USR is set. This allows the
// FPGA to acknowledge a request for reprogram to allow the FPGA
// to get itself into a reprogrammable state first.
.PACK(1'b0),
// USRCLKO, 1-bit input: User CCLK input -- This is why I am using this
// module at all.
.USRCCLKO(qspi_sck),
// USRCCLKTS, 1'b input: User CCLK 3-state enable input
// An active high here places the clock into a high impedence
// state. Since we wish to use the clock as an active output
// always, we drive this pin low.
.USRCCLKTS(1'b0),
// USRDONEO, 1'b input: User DONE pin output control
// Set this to "high" to make sure that the DONE LED pin is
// high.
.USRDONEO(1'b1),
// USRDONETS, 1'b input: User DONE 3-state enable output
// This enables the FPGA DONE pin to be active. Setting this
// active high sets the DONE pin to high impedence, setting it
// low allows the output of this pin to be as stated above.
.USRDONETS(1'b1)
);
*/
 
 
 
//
//
// Wires for setting up the SD Card Controller
//
//
assign io_sd_cmd = w_sd_cmd ? 1'bz:1'b0;
assign io_sd[0] = w_sd_data[0]? 1'bz:1'b0;
assign io_sd[1] = w_sd_data[1]? 1'bz:1'b0;
assign io_sd[2] = w_sd_data[2]? 1'bz:1'b0;
assign io_sd[3] = w_sd_data[3]? 1'bz:1'b0;
assign o_sd_wp = 1'b0;
 
 
//
//
// Wire(s) for setting up the MDIO ethernet control structure
//
//
assign io_eth_mdio = (w_mdwe)?w_mdio : 1'bz;
 
//
//
// Wires for setting up the DDR3 memory
//
//
wire [31:0] r_ddr_data;
 
xioddr p0(i_clk, ~o_ddr_we_n, { wo_ddr_data[16], wo_ddr_data[0] },
{ wi_ddr_data[16], wi_ddr_data[0] }, io_ddr_data[0]);
 
xioddr p1(i_clk, ~o_ddr_we_n, { wo_ddr_data[17], wo_ddr_data[1] },
{ wi_ddr_data[17], wi_ddr_data[1] }, io_ddr_data[1]);
 
xioddr p2(i_clk, ~o_ddr_we_n, { wo_ddr_data[18], wo_ddr_data[2] },
{ wi_ddr_data[18], wi_ddr_data[2] }, io_ddr_data[2]);
 
xioddr p3(i_clk, ~o_ddr_we_n, { wo_ddr_data[19], wo_ddr_data[3] },
{ wi_ddr_data[19], wi_ddr_data[3] }, io_ddr_data[3]);
 
xioddr p4(i_clk, ~o_ddr_we_n, { wo_ddr_data[20], wo_ddr_data[4] },
{ wi_ddr_data[20], wi_ddr_data[4] }, io_ddr_data[4]);
 
xioddr p5(i_clk, ~o_ddr_we_n, { wo_ddr_data[21], wo_ddr_data[5] },
{ wi_ddr_data[21], wi_ddr_data[5] }, io_ddr_data[5]);
 
xioddr p6(i_clk, ~o_ddr_we_n, { wo_ddr_data[22], wo_ddr_data[6] },
{ wi_ddr_data[22], wi_ddr_data[6] }, io_ddr_data[6]);
 
xioddr p7(i_clk, ~o_ddr_we_n, { wo_ddr_data[23], wo_ddr_data[7] },
{ wi_ddr_data[23], wi_ddr_data[7] }, io_ddr_data[7]);
 
xioddr p8(i_clk, ~o_ddr_we_n, { wo_ddr_data[24], wo_ddr_data[8] },
{ wi_ddr_data[24], wi_ddr_data[8] }, io_ddr_data[8]);
 
xioddr p9(i_clk, ~o_ddr_we_n, { wo_ddr_data[25], wo_ddr_data[9] },
{ wi_ddr_data[25], wi_ddr_data[9] }, io_ddr_data[9]);
 
xioddr pa(i_clk, ~o_ddr_we_n, { wo_ddr_data[26], wo_ddr_data[10] },
{ wi_ddr_data[26], wi_ddr_data[10] }, io_ddr_data[10]);
 
xioddr pb(i_clk, ~o_ddr_we_n, { wo_ddr_data[27], wo_ddr_data[11] },
{ wi_ddr_data[27], wi_ddr_data[11] }, io_ddr_data[11]);
 
xioddr pc(i_clk, ~o_ddr_we_n, { wo_ddr_data[28], wo_ddr_data[12] },
{ wi_ddr_data[28], wi_ddr_data[12] }, io_ddr_data[12]);
 
xioddr pd(i_clk, ~o_ddr_we_n, { wo_ddr_data[29], wo_ddr_data[13] },
{ wi_ddr_data[29], wi_ddr_data[13] }, io_ddr_data[13]);
 
xioddr pe(i_clk, ~o_ddr_we_n, { wo_ddr_data[30], wo_ddr_data[14] },
{ wi_ddr_data[30], wi_ddr_data[14] }, io_ddr_data[14]);
 
xioddr pf(i_clk, ~o_ddr_we_n, { wo_ddr_data[31], wo_ddr_data[15] },
{ wi_ddr_data[31], wi_ddr_data[15] }, io_ddr_data[15]);
 
OBUFTDS #(.IOSTANDARD("DIFF_SSTL135"), .SLEW("FAST"))
dqsbuf0(.O(io_ddr_dqs_p[0]), .OB(io_ddr_dqs_n[0]),
.I(w_ddr_dqs[1]), .T(w_ddr_dqs[2]));
OBUFTDS #(.IOSTANDARD("DIFF_SSTL135"), .SLEW("FAST"))
dqsbuf1(.O(io_ddr_dqs_p[1]), .OB(io_ddr_dqs_n[1]),
.I(w_ddr_dqs[0]), .T(w_ddr_dqs[2]));
 
OBUFDS #(.IOSTANDARD("DIFF_SSTL135"), .SLEW("FAST"))
clkbuf(.O(o_ddr_ck_p), .OB(o_ddr_ck_n), .I(clk_for_ddr));
 
assign o_ddr_dm = 2'b00;
assign o_ddr_odt = 1'b0;
 
endmodule
 
/rtl/wbucompactlines.v
0,0 → 1,117
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wbucompactlines.v
//
// Project: FPGA library
//
// Purpose: Removes 'end of line' characters placed at the end of every
// deworded word, unless we're idle or the line is too long.
// This helps to format the output nicely to fit in an 80-character
// display, should you need to do so for debugging.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
// When to apply a new line?
// When no prior new line exists
// or when prior line length exceeds (72)
// Between codewords (need inserted newline)
// When bus has become idle (~wb_cyc)&&(~busys)
//
// So, if every codeword ends in a newline, what we
// really need to do is to remove newlines. Thus, if
// i_stb goes high while i_tx_busy, we skip the newline
// unless the line is empty. ... But i_stb will always
// go high while i_tx_busy. How about if the line
// length exceeds 72, we do nothing, but record the
// last word. If the last word was a <incomplete-thought>
//
//
module wbucompactlines(i_clk, i_stb, i_nl_hexbits, o_stb, o_nl_hexbits,
i_bus_busy, i_tx_busy, o_busy);
input i_clk, i_stb;
input [6:0] i_nl_hexbits;
output reg o_stb;
output reg [6:0] o_nl_hexbits;
input i_bus_busy;
input i_tx_busy;
output wire o_busy;
 
reg last_out_nl, last_in_nl;
initial last_out_nl = 1'b1;
initial last_in_nl = 1'b1;
always @(posedge i_clk)
if ((~i_tx_busy)&&(o_stb))
last_out_nl <= (o_nl_hexbits[6]);
always @(posedge i_clk)
if ((i_stb)&&(~o_busy))
last_in_nl <= (i_nl_hexbits[6]);
 
// Now, let's count how long our lines are
reg [6:0] linelen;
initial linelen = 7'h00;
always @(posedge i_clk)
if ((~i_tx_busy)&&(o_stb))
begin
if (o_nl_hexbits[6])
linelen <= 0;
else
linelen <= linelen + 7'h1;
end
 
reg full_line;
initial full_line = 1'b0;
always @(posedge i_clk)
full_line <= (linelen > 7'd72);
 
 
// Now that we know whether or not the last character was a newline,
// and indeed how many characters we have in any given line, we can
// selectively remove newlines from our output stream.
initial o_stb = 1'b0;
always @(posedge i_clk)
if ((i_stb)&&(~o_busy))
begin
o_stb <= (full_line)||(~i_nl_hexbits[6]);
o_nl_hexbits <= i_nl_hexbits;
end else if (~o_busy)
begin // Send an EOL if we are idle
o_stb <= (~i_tx_busy)&&(~i_bus_busy)&&(~last_out_nl)&&(last_in_nl);
o_nl_hexbits <= 7'h40;
end else if (~i_tx_busy)
o_stb <= 1'b0;
 
reg r_busy;
initial r_busy = 1'b0;
always @(posedge i_clk)
r_busy <= (o_stb);
assign o_busy = (r_busy)||(o_stb);
 
/*
output wire [27:0] o_dbg;
assign o_dbg = { o_stb, o_nl_hexbits, o_busy, r_busy, full_line,
i_bus_busy, linelen, i_tx_busy, i_stb, i_nl_hexbits };
*/
endmodule
/rtl/eqspiflash.v
0,0 → 1,1637
////////////////////////////////////////////////////////////////////////////////
//
// Filename: eqspiflash.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: Provide access to the flash device on an Arty, via the Extended
// SPI interface. Reads and writes will use the QuadSPI interface
// (4-bits at a time) all other commands (register and otherwise) will use
// the SPI interface (1 bit at a time).
//
// Registers:
// 0. Erase register control. Provides status of pending writes, erases,
// and commands (sub)sector erase operations.
// Bit-Fields:
// 31. WIP (Write-In-Progress), write a '1' to this bit to command
// an erase sequence.
// 30. WriteEnabled -- set to a '1' to disable write protection and
// to write a WRITE-ENABLE to the device. Set to a '0' to
// disable WRITE-ENABLE-LATCH. (Key is required to enable
// writes)
// 29. Quad mode read/writes enabled. (Rest of controller will use
// extended SPI mode, but reads and writes will use Quad
// mode.)
// 28. Subsector erase bit (set 1 to erase a subsector, 0 to
// erase a full sector, maintains last value written from
// an erase command, starts at '0')
// 27. SD ID loaded
// 26. Write protect violation--cleared upon any valid write
// 25. XIP enabled. (Leave read mode in XIP, so you can start
// next read faster.)
// 24. Unused
// 23..0: Address of erase sector upon erase command
// 23..14: Sector address (can only be changed w/ key)
// 23..10: Subsector address (can only be changed w/ key)
// 9.. 0: write protect KEY bits, always read a '0', write
// commands, such as WP disable or erase, must always
// write with a '1be' to activate.
// 0. WEL: All writes that do not command an erase will be used
// to set/clear the write enable latch.
// Send 0x06, return, if WP is clear (enable writes)
// Send 0x04, return
// 1. STATUS
// Send 0x05, read 1-byte
// Send 0x01, write 1-byte: i_wb_data[7:0]
// 2. NV-CONFIG (16-bits)
// Send 0xB5, read 2-bytes
// Send 0xB1, write 2-bytes: i_wb_data[15:0]
// 3. V-CONFIG (8-bits)
// Send 0x85, read 1-byte
// Send 0x81, write 1-byte: i_wb_data[7:0]
// 4. EV-CONFIG (8-bits)
// Send 0x65, read 1-byte
// Send 0x61, write 1-byte: i_wb_data[7:0]
// 5. Lock (send 32-bits, rx 1 byte)
// Send 0xE8, last-sector-addr (3b), read 1-byte
// Send 0xE5, last-sector-addr (3b), write 1-byte: i_wb_data[7:0]
// 6. Flag Status
// Send 0x70, read 1-byte
// Send 0x50, to clear, no bytes to write
// 7. Asynch Read-ID: Write here to cause controller to read ID into buffer
// 8.-12. ID buffer (20 bytes, 5 words)
// Attempted reads before buffer is full will stall bus until
// buffer is read. Writes act like the asynch-Read-ID command,
// and will cause the controller to read the buffer.
// 13.-14. Unused, mapped to Asynch-read-ID
// 15. OTP control word
// Write zero to permanently lock OTP
// Read to determine if OTP is permanently locked
// 16.-31. OTP (64-bytes, 16 words, buffered until write)
// (Send DWP before writing to clear write enable latch)
//
//
// 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
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
// `define QSPI_READ_ONLY
module eqspiflash(i_clk_200mhz, i_rst,
// Incoming wishbone connection(s)
// The two strobe lines allow the data to live on a
// separate part of the master bus from the control
// registers. Only one strobe will ever be active at any
// time, no strobes will ever be active unless i_wb_cyc
// is also active.
i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we,
i_wb_addr, i_wb_data,
// Outgoing wishbone data
o_wb_ack, o_wb_stall, o_wb_data,
// Quad SPI connections
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat,
// Interrupt the CPU
o_interrupt, o_cmd_accepted,
// Debug the interface
o_dbg);
 
input i_clk_200mhz, i_rst;
// Wishbone bus inputs
input i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we;
input [21:0] i_wb_addr; // 24 bits of addr space
input [31:0] i_wb_data;
// Wishbone bus outputs
output reg o_wb_ack;
output wire o_wb_stall;
output reg [31:0] o_wb_data;
// Quad SPI connections
output wire o_qspi_sck, o_qspi_cs_n;
output wire [1:0] o_qspi_mod;
output wire [3:0] o_qspi_dat;
input wire [3:0] i_qspi_dat;
//
output reg o_interrupt;
//
output reg o_cmd_accepted;
//
output wire [31:0] o_dbg;
 
initial o_cmd_accepted = 1'b0;
always @(posedge i_clk_200mhz)
o_cmd_accepted=((i_wb_data_stb)||(i_wb_ctrl_stb))&&(~o_wb_stall);
//
// lleqspi
//
// Providing the low-level SPI interface
//
reg spi_wr, spi_hold, spi_spd, spi_dir, spi_recycle;
reg [31:0] spi_word;
reg [1:0] spi_len;
wire [31:0] spi_out;
wire spi_valid, spi_busy, spi_stopped;
lleqspi lowlvl(i_clk_200mhz, spi_wr, spi_hold, spi_word, spi_len,
spi_spd, spi_dir, spi_recycle, spi_out, spi_valid, spi_busy,
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat);
assign spi_stopped = (o_qspi_cs_n)&&(~spi_busy)&&(~spi_wr);
 
 
//
// Bus module
//
// Providing a shared interface to the WB bus
//
// Wishbone data (returns)
wire bus_wb_ack, bus_wb_stall;
wire [31:0] bus_wb_data;
// Latched request data
wire bus_wr;
wire [21:0] bus_addr;
wire [31:0] bus_data;
wire [21:0] bus_sector;
// Strobe commands
wire bus_ack;
wire bus_readreq, bus_piperd, bus_ereq, bus_wreq,
bus_pipewr, bus_endwr, bus_ctreq, bus_idreq,
bus_other_req,
// Live parameters
w_xip, w_quad, w_idloaded;
reg bus_wip;
qspibus preproc(i_clk_200mhz, i_rst,
i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb,
i_wb_we, i_wb_addr, i_wb_data,
bus_wb_ack, bus_wb_stall, bus_wb_data,
bus_wr, bus_addr, bus_data, bus_sector,
bus_readreq, bus_piperd,
bus_wreq, bus_ereq,
bus_pipewr, bus_endwr,
bus_ctreq, bus_idreq, bus_other_req, bus_ack,
w_xip, w_quad, w_idloaded, bus_wip, spi_stopped);
 
//
// Read flash module
//
// Providing a means of (and the logic to support) reading from
// the flash
//
wire rd_data_ack;
wire [31:0] rd_data;
//
wire rd_bus_ack;
//
wire rd_qspi_req;
wire rd_qspi_grant;
//
wire rd_spi_wr, rd_spi_hold, rd_spi_spd, rd_spi_dir,
rd_spi_recycle;
wire [31:0] rd_spi_word;
wire [1:0] rd_spi_len;
//
readqspi rdproc(i_clk_200mhz, bus_readreq, bus_piperd,
bus_other_req,
bus_addr, rd_bus_ack,
rd_qspi_req, rd_qspi_grant,
rd_spi_wr, rd_spi_hold, rd_spi_word, rd_spi_len,
rd_spi_spd, rd_spi_dir, rd_spi_recycle,
spi_out, spi_valid,
spi_busy, spi_stopped, rd_data_ack, rd_data,
w_quad, w_xip);
 
//
// Write/Erase flash module
//
// Logic to write (program) and erase the flash.
//
// Wishbone bus return
wire ew_data_ack;
wire [31:0] ew_data;
// Arbiter interaction
wire ew_qspi_req;
wire ew_qspi_grant;
// Bus controller return
wire ew_bus_ack;
// SPI control wires
wire ew_spi_wr, ew_spi_hold, ew_spi_spd, ew_spi_dir;
wire [31:0] ew_spi_word;
wire [1:0] ew_spi_len;
//
wire w_ew_wip;
//
writeqspi ewproc(i_clk_200mhz, bus_wreq,bus_ereq,
bus_pipewr, bus_endwr,
bus_addr, bus_data,
ew_bus_ack, ew_qspi_req, ew_qspi_grant,
ew_spi_wr, ew_spi_hold, ew_spi_word, ew_spi_len,
ew_spi_spd, ew_spi_dir,
spi_out, spi_valid, spi_busy, spi_stopped,
ew_data_ack, w_quad, w_ew_wip);
 
//
// Control module
//
// Logic to read/write status and configuration registers
//
// Wishbone bus return
wire ct_data_ack;
wire [31:0] ct_data;
// Arbiter interaction
wire ct_qspi_req;
wire ct_grant;
// Bus controller return
wire ct_ack;
// SPI control wires
wire ct_spi_wr, ct_spi_hold, ct_spi_spd, ct_spi_dir;
wire [31:0] ct_spi_word;
wire [1:0] ct_spi_len;
//
ctrlspi ctproc(i_clk_200mhz,
bus_ctreq, bus_wr, bus_addr[2:0], bus_data, bus_sector,
ct_qspi_req, ct_grant,
ct_spi_wr, ct_spi_hold, ct_spi_word, ct_spi_len,
ct_spi_spd, ct_spi_dir,
spi_out, spi_valid, spi_busy, spi_stopped,
ct_ack, ct_data_ack, ct_data, w_xip, w_quad);
assign ct_spi_hold = 1'b0;
assign ct_spi_spd = 1'b0;
 
//
// ID/OTP module
//
// Access to ID and One-Time-Programmable registers, but to read
// and to program (the OTP), and to finally lock (OTP) registers.
//
// Wishbone bus return
wire id_data_ack;
wire [31:0] id_data;
// Arbiter interaction
wire id_qspi_req;
wire id_qspi_grant;
// Bus controller return
wire id_bus_ack;
// SPI control wires
wire id_spi_wr, id_spi_hold, id_spi_spd, id_spi_dir;
wire [31:0] id_spi_word;
wire [1:0] id_spi_len;
//
wire w_id_wip;
//
idotpqspi idotp(i_clk_200mhz, bus_idreq,
bus_wr, bus_pipewr, bus_addr[4:0], bus_data, id_bus_ack,
id_qspi_req, id_qspi_grant,
id_spi_wr, id_spi_hold, id_spi_word, id_spi_len,
id_spi_spd, id_spi_dir,
spi_out, spi_valid, spi_busy, spi_stopped,
id_data_ack, id_data, w_idloaded, w_id_wip);
 
// Arbitrator
reg owned;
reg [1:0] owner;
initial owned = 1'b0;
always @(posedge i_clk_200mhz) // 7 inputs (spi_stopped is the CE)
if ((~owned)&&(spi_stopped))
begin
casez({rd_qspi_req,ew_qspi_req,id_qspi_req,ct_qspi_req})
4'b1???: begin owned<= 1'b1; owner <= 2'b00; end
4'b01??: begin owned<= 1'b1; owner <= 2'b01; end
4'b001?: begin owned<= 1'b1; owner <= 2'b10; end
4'b0001: begin owned<= 1'b1; owner <= 2'b11; end
default: begin owned<= 1'b0; owner <= 2'b00; end
endcase
end else if ((owned)&&(spi_stopped))
begin
casez({rd_qspi_req,ew_qspi_req,id_qspi_req,ct_qspi_req,owner})
6'b0???00: owned<= 1'b0;
6'b?0??01: owned<= 1'b0;
6'b??0?10: owned<= 1'b0;
6'b???011: owned<= 1'b0;
default: begin ; end
endcase
end
 
assign rd_qspi_grant = (owned)&&(owner == 2'b00);
assign ew_qspi_grant = (owned)&&(owner == 2'b01);
assign id_qspi_grant = (owned)&&(owner == 2'b10);
assign ct_grant = (owned)&&(owner == 2'b11);
 
// Module controller
always @(posedge i_clk_200mhz)
case(owner)
2'b00: begin
spi_wr <= (owned)&&(rd_spi_wr);
spi_hold <= rd_spi_hold;
spi_word <= rd_spi_word;
spi_len <= rd_spi_len;
spi_spd <= rd_spi_spd;
spi_dir <= rd_spi_dir;
spi_recycle <= rd_spi_recycle;
end
2'b01: begin
spi_wr <= (owned)&&(ew_spi_wr);
spi_hold <= ew_spi_hold;
spi_word <= ew_spi_word;
spi_len <= ew_spi_len;
spi_spd <= ew_spi_spd;
spi_dir <= ew_spi_dir;
spi_recycle <= 1'b1; // Long recycle time
end
2'b10: begin
spi_wr <= (owned)&&(id_spi_wr);
spi_hold <= id_spi_hold;
spi_word <= id_spi_word;
spi_len <= id_spi_len;
spi_spd <= id_spi_spd;
spi_dir <= id_spi_dir;
spi_recycle <= 1'b1; // Long recycle time
end
2'b11: begin
spi_wr <= (owned)&&(ct_spi_wr);
spi_hold <= ct_spi_hold;
spi_word <= ct_spi_word;
spi_len <= ct_spi_len;
spi_spd <= ct_spi_spd;
spi_dir <= ct_spi_dir;
spi_recycle <= 1'b1; // Long recycle time
end
endcase
 
reg last_wip;
initial bus_wip = 1'b0;
initial last_wip = 1'b0;
initial o_interrupt = 1'b0;
always @(posedge i_clk_200mhz)
begin
bus_wip <= w_ew_wip || w_id_wip;
last_wip <= bus_wip;
o_interrupt <= ((~bus_wip)&&(last_wip));
end
 
 
// Now, let's return values onto the wb bus
always @(posedge i_clk_200mhz)
begin
// Ack our internal bus controller. This means the command was
// accepted, and the bus can go on to looking for the next
// command. It controls the i_wb_stall line, just not the
// i_wb_ack line.
 
// Ack the wishbone with any response
o_wb_ack <= (bus_wb_ack)|(rd_data_ack)|(ew_data_ack)|(id_data_ack)|(ct_data_ack);
o_wb_data <= (bus_wb_ack)?bus_wb_data
: (id_data_ack) ? id_data : spi_out;
end
 
assign o_wb_stall = bus_wb_stall;
assign bus_ack = (rd_bus_ack|ew_bus_ack|id_bus_ack|ct_ack);
assign o_dbg = {
i_wb_cyc, i_wb_ctrl_stb, i_wb_data_stb, o_wb_ack, bus_ack, //5
//
(spi_wr)&&(~spi_busy), spi_valid, spi_word[31:25],
spi_out[7:2],
//
o_qspi_cs_n, o_qspi_sck, o_qspi_mod, // 4 bits
o_qspi_dat, i_qspi_dat // 8 bits
};
endmodule
 
module qspibus(i_clk, i_rst, i_cyc, i_data_stb, i_ctrl_stb,
i_we, i_addr, i_data,
o_wb_ack, o_wb_stall, o_wb_data,
o_wr, o_addr, o_data, o_sector,
o_readreq, o_piperd, o_wrreq, o_erreq, o_pipewr, o_endwr,
o_ctreq, o_idreq, o_other,
i_ack, i_xip, i_quad, i_idloaded, i_wip, i_spi_stopped);
//
input i_clk, i_rst;
// Wishbone bus inputs
input i_cyc, i_data_stb, i_ctrl_stb, i_we;
input [21:0] i_addr;
input [31:0] i_data;
// Wishbone bus outputs
output reg o_wb_ack;
output reg o_wb_stall;
output wire [31:0] o_wb_data;
// Internal signals to the QSPI flash interface
output reg o_wr;
output reg [21:0] o_addr;
output reg [31:0] o_data;
output wire [21:0] o_sector;
output reg o_readreq, o_piperd, o_wrreq, o_erreq,
o_pipewr, o_endwr,
o_ctreq, o_idreq;
output wire o_other;
input i_ack, i_xip, i_quad, i_idloaded;
input i_wip, i_spi_stopped;
 
 
//
reg pending, lcl_wrreq, lcl_ctreq, lcl_ack, ack, wp_err, wp;
reg lcl_reg;
reg [14:0] esector;
reg [21:0] next_addr;
 
 
reg pipeable;
reg same_page;
always @(posedge i_clk)
same_page <= (i_data_stb)&&(i_we)
&&(i_addr[21:6] == o_addr[21:6])
&&(i_addr[5:0] == o_addr[5:0] + 6'h1);
 
initial pending = 1'b0;
initial o_readreq = 1'b0;
initial lcl_wrreq = 1'b0;
initial lcl_ctreq = 1'b0;
initial o_ctreq = 1'b0;
initial o_idreq = 1'b0;
 
initial ack = 1'b0;
always @(posedge i_clk)
ack <= (i_ack)||(lcl_ack);
 
// wire [9:0] key;
// assign key = 10'h1be;
reg lcl_key, set_sector, ctreg_stb;
initial lcl_key = 1'b0;
always @(posedge i_clk)
// Write protect "key" to enable the disabling of write protect
lcl_key<= (i_ctrl_stb)&&(~wp)&&(i_we)&&(i_addr[5:0]==6'h00)
&&(i_data[9:0] == 10'h1be)&&(i_data[31:30]==2'b11);
initial set_sector = 1'b0;
always @(posedge i_clk)
set_sector <= (i_ctrl_stb)&&(~o_wb_stall)
&&(i_we)&&(i_addr[5:0]==6'h00)
&&(i_data[9:0] == 10'h1be);
 
always @(posedge i_clk)
if (i_ctrl_stb)
lcl_reg <= (i_addr[3:0] == 4'h00);
 
initial ctreg_stb = 1'b0;
initial o_wb_stall = 1'b0;
always @(posedge i_clk)
begin // Inputs: rst, stb, stb, stall, ack, addr[4:0] -- 9
if (i_rst)
o_wb_stall <= 1'b0;
else
o_wb_stall <= (((i_data_stb)||(i_ctrl_stb))&&(~o_wb_stall))
||((pending)&&(~ack));
 
ctreg_stb <= (i_ctrl_stb)&&(~o_wb_stall)&&(i_addr[4:0]==5'h00)&&(~pending)
||(pending)&&(ctreg_stb)&&(~lcl_ack)&&(~i_ack);
if (~o_wb_stall)
begin // Bus command accepted!
if ((i_data_stb)||(i_ctrl_stb))
begin
pending <= 1'b1;
o_addr <= i_addr;
o_data <= i_data;
o_wr <= i_we;
next_addr <= i_addr + 22'h1;
end
 
if ((i_data_stb)&&(~i_we))
o_readreq <= 1'b1;
 
if ((i_data_stb)&&(i_we))
lcl_wrreq <= 1'b1;
if ((i_ctrl_stb)&&(~i_addr[4]))
begin
casez(i_addr[4:0])
5'h0: lcl_ctreq<= 1'b1;
5'h1: lcl_ctreq <= 1'b1;
5'h2: lcl_ctreq <= 1'b1;
5'h3: lcl_ctreq <= 1'b1;
5'h4: lcl_ctreq <= 1'b1;
5'h5: lcl_ctreq <= 1'b1;
5'h6: lcl_ctreq <= 1'b1;
5'h7: lcl_ctreq <= 1'b1;
5'h8: o_idreq <= 1'b1; // ID[0]
5'h9: o_idreq <= 1'b1; // ID[1]
5'ha: o_idreq <= 1'b1; // ID[2]
5'hb: o_idreq <= 1'b1; // ID[3]
5'hc: o_idreq <= 1'b1; // ID[4]
5'hd: o_idreq <= 1'b1; //
5'he: o_idreq <= 1'b1;
5'hf: o_idreq <= 1'b1; // Program OTP register
default: begin o_idreq <= 1'b1; end
endcase
end else if (i_ctrl_stb)
o_idreq <= 1'b1;
end else if (ack)
begin
pending <= 1'b0;
o_readreq <= 1'b0;
o_idreq <= 1'b0;
lcl_ctreq <= 1'b0;
lcl_wrreq <= 1'b0;
end
 
if(i_rst)
begin
pending <= 1'b0;
o_readreq <= 1'b0;
o_idreq <= 1'b0;
lcl_ctreq <= 1'b0;
lcl_wrreq <= 1'b0;
end
 
if ((i_data_stb)&&(~o_wb_stall))
o_piperd <= ((~i_we)&&(~o_wb_stall)&&(pipeable)&&(i_addr == next_addr));
else if ((i_ack)||(((i_ctrl_stb)||(i_data_stb))&&(~o_wb_stall)))
o_piperd <= 1'b0;
if ((i_data_stb)&&(~o_wb_stall))
pipeable <= (~i_we);
else if ((i_ctrl_stb)&&(~o_wb_stall))
pipeable <= 1'b0;
 
o_pipewr <= (same_page)||(pending)&&(o_pipewr);
end
 
reg r_other, last_wip;
 
reg last_pending;
always @(posedge i_clk)
last_pending <= pending;
always @(posedge i_clk)
last_wip <= i_wip;
wire new_req;
assign new_req = (pending)&&(~last_pending);
 
initial o_wrreq = 1'b0;
initial o_erreq = 1'b0;
initial wp_err = 1'b0;
initial lcl_ack = 1'b0;
initial r_other = 1'b0;
initial o_endwr = 1'b1;
initial wp = 1'b1;
always @(posedge i_clk)
begin
if (i_ack)
begin
o_erreq <= 1'b0;
o_wrreq <= 1'b0;
o_ctreq <= 1'b0;
r_other <= 1'b0;
end
 
if ((last_wip)&&(~i_wip))
wp <= 1'b1;
 
// o_endwr <= ((~i_cyc)||(~o_wr)||(o_pipewr))
// ||(~new_req)&&(o_endwr);
o_endwr <= ((pending)&&(~o_pipewr))||((~pending)&&(~i_cyc));
 
// Default ACK is always set to zero, unless the following ...
o_wb_ack <= 1'b0;
 
if (set_sector)
begin
esector[13:0] <= { o_data[23:14], 4'h0 };
wp <= (o_data[30])&&(new_req)||(wp)&&(~new_req);
if (o_data[28])
begin
esector[14] <= o_data[28];
esector[3:0] <= o_data[13:10];
end
end
 
lcl_ack <= 1'b0;
if ((i_wip)&&(new_req)&&(~same_page))
begin
o_wb_ack <= 1'b1;
lcl_ack <= 1'b1;
end else if ((ctreg_stb)&&(new_req))
begin // A request of the status register
// Always ack control register, even on failed attempts
// to erase.
o_wb_ack <= 1'b1;
lcl_ack <= 1'b1;
 
if (lcl_key)
begin
o_ctreq <= 1'b0;
o_erreq <= 1'b1;
r_other <= 1'b1;
lcl_ack <= 1'b0;
end else if ((o_wr)&&(~o_data[31]))
begin // WEL or WEL disable
o_ctreq <= (wp == o_data[30]);
r_other <= (wp == o_data[30]);
lcl_ack <= (wp != o_data[30]);
wp <= !o_data[30];
end else if (~o_wr)
lcl_ack <= 1'b1;
wp_err <= (o_data[31])&&(~lcl_key);
end else if ((lcl_ctreq)&&(new_req))
begin
o_ctreq <= 1'b1;
r_other <= 1'b1;
end else if ((lcl_wrreq)&&(new_req))
begin
if (~wp)
begin
o_wrreq <= 1'b1;
r_other <= 1'b1;
o_endwr <= 1'b0;
lcl_ack <= 1'b0;
end else begin
o_wb_ack <= 1'b1;
wp_err <= 1'b1;
lcl_ack <= 1'b1;
end
end
 
if (i_rst)
begin
o_ctreq <= 1'b0;
o_erreq <= 1'b0;
o_wrreq <= 1'b0;
r_other <= 1'b0;
end
 
end
 
 
assign o_wb_data[31:0] = { i_wip, ~wp, i_quad, esector[14],
i_idloaded, wp_err, i_xip, i_spi_stopped,
esector[13:0], 10'h00 };
assign o_sector = { esector[13:0], 8'h00 }; // 22 bits
assign o_other = (r_other)||(o_idreq);
 
endmodule
 
 
`define RD_IDLE 4'h0
`define RD_IDLE_GET_PORT 4'h1
`define RD_SLOW_DUMMY 4'h2
`define RD_SLOW_READ_DATA 4'h3
`define RD_QUAD_READ_DATA 4'h4
`define RD_QUAD_DUMMY 4'h5
`define RD_QUAD_ADDRESS 4'h6
`define RD_XIP 4'h7
`define RD_GO_TO_IDLE 4'h8
`define RD_GO_TO_XIP 4'h9
 
module readqspi(i_clk, i_readreq, i_piperd, i_other_req, i_addr, o_bus_ack,
o_qspi_req, i_grant,
o_spi_wr, o_spi_hold, o_spi_word, o_spi_len,
o_spi_spd, o_spi_dir, o_spi_recycle,
i_spi_data, i_spi_valid, i_spi_busy, i_spi_stopped,
o_data_ack, o_data, i_quad, i_xip);
input i_clk;
input i_readreq, i_piperd, i_other_req;
input [21:0] i_addr;
output reg o_bus_ack, o_qspi_req;
input wire i_grant;
output reg o_spi_wr;
output wire o_spi_hold;
output reg [31:0] o_spi_word;
output reg [1:0] o_spi_len;
output reg o_spi_spd, o_spi_dir, o_spi_recycle;
input [31:0] i_spi_data;
input i_spi_valid, i_spi_busy, i_spi_stopped;
output reg o_data_ack;
output reg [31:0] o_data;
input i_quad, i_xip;
 
reg accepted;
initial accepted = 1'b0;
always @(posedge i_clk)
accepted <= (~i_spi_busy)&&(i_grant)&&(o_spi_wr)&&(~accepted);
 
reg [3:0] rd_state;
reg r_leave_xip, r_xip, r_quad, r_requested;
initial rd_state = `RD_IDLE;
initial o_data_ack = 1'b0;
initial o_bus_ack = 1'b0;
initial o_qspi_req = 1'b0;
always @(posedge i_clk)
begin
o_data_ack <= 1'b0;
o_bus_ack <= 1'b0;
o_spi_recycle <= 1'b0;
if (i_spi_valid)
o_data <= i_spi_data;
case(rd_state)
`RD_IDLE: begin
r_requested <= 1'b0;
o_qspi_req <= 1'b0;
o_spi_word <= { ((i_quad)? 8'h6B: 8'h0b), i_addr, 2'b00 };
o_spi_wr <= 1'b0;
o_spi_dir <= 1'b0;
o_spi_spd <= 1'b0;
o_spi_len <= 2'b11;
r_xip <= (i_xip)&&(i_quad);
r_leave_xip <= 1'b0; // Not in it, so can't leave it
r_quad <= i_quad;
if (i_readreq)
begin
rd_state <= `RD_IDLE_GET_PORT;
o_bus_ack <= 1'b1;
end end
`RD_IDLE_GET_PORT: begin
o_spi_wr <= 1'b1; // Write the address
o_qspi_req <= 1'b1;
if (accepted)
rd_state <= `RD_SLOW_DUMMY;
end
`RD_SLOW_DUMMY: begin
o_spi_wr <= 1'b1; // Write 8 dummy clocks
o_qspi_req <= 1'b1;
o_spi_dir <= 1'b0;
o_spi_spd <= 1'b0;
o_spi_word[31:24] <= (r_xip) ? 8'h00 : 8'hff;
o_spi_len <= 2'b00; // 8 clocks = 8-bits
if (accepted)
rd_state <= (r_quad)?`RD_QUAD_READ_DATA
: `RD_SLOW_READ_DATA;
end
`RD_SLOW_READ_DATA: begin
o_qspi_req <= 1'b1;
o_spi_dir <= 1'b1;
o_spi_spd <= 1'b0;
o_spi_len <= 2'b11;
o_spi_wr <= (~r_requested)||(i_piperd);
// if (accepted)
// o_spi_wr <= (i_piperd);
o_data_ack <= (r_requested)&&(i_spi_valid);
o_bus_ack <= (r_requested)&&(accepted)&&(i_piperd);
r_requested <= (r_requested)||(accepted);
if ((i_spi_valid)&&(~o_spi_wr))
rd_state <= `RD_GO_TO_IDLE;
end
`RD_QUAD_READ_DATA: begin
o_qspi_req <= 1'b1;
o_spi_dir <= 1'b1;
o_spi_spd <= 1'b1;
o_spi_len <= 2'b11;
o_spi_recycle <= (r_leave_xip)? 1'b1: 1'b0;
r_requested <= (r_requested)||(accepted);
o_data_ack <= (r_requested)&&(i_spi_valid)&&(~r_leave_xip);
o_bus_ack <= (r_requested)&&(accepted)&&(i_piperd)&&(~r_leave_xip);
o_spi_wr <= (~r_requested)||(i_piperd);
// if (accepted)
// o_spi_wr <= (i_piperd);
if (accepted)
o_data <= i_spi_data;
if ((i_spi_valid)&&(~o_spi_wr))
rd_state <= ((r_leave_xip)||(~r_xip))?`RD_GO_TO_IDLE:`RD_GO_TO_XIP;
end
`RD_QUAD_ADDRESS: begin
o_qspi_req <= 1'b1;
o_spi_wr <= 1'b1;
o_spi_dir <= 1'b0; // Write the address
o_spi_spd <= 1'b1; // High speed
o_spi_word[31:0] <= { i_addr, 2'b00, 8'h00 };
o_spi_len <= 2'b10; // 24 bits, High speed, 6 clocks
if (accepted)
rd_state <= `RD_QUAD_DUMMY;
end
`RD_QUAD_DUMMY: begin
o_qspi_req <= 1'b1;
o_spi_wr <= 1'b1;
o_spi_dir <= 1'b0; // Write the dummy
o_spi_spd <= 1'b1; // High speed
o_spi_word[31:0] <= (r_xip)? 32'h00 : 32'hffffffff;
o_spi_len <= 2'b11; // 8 clocks = 32-bits, quad speed
if (accepted)
rd_state <= (r_quad)?`RD_QUAD_READ_DATA
: `RD_SLOW_READ_DATA;
end
`RD_XIP: begin
r_requested <= 1'b0;
o_qspi_req <= 1'b1;
o_spi_word <= { i_addr, 2'b00, 8'h00 };
o_spi_wr <= 1'b0;
o_spi_dir <= 1'b0; // Write to SPI
o_spi_spd <= 1'b1; // High speed
o_spi_len <= 2'b11;
r_leave_xip <= i_other_req;
r_xip <= (~i_other_req);
o_bus_ack <= 1'b0;
if ((i_readreq)||(i_other_req))
begin
rd_state <= `RD_QUAD_ADDRESS;
o_bus_ack <= i_readreq;
end end
`RD_GO_TO_IDLE: begin
o_qspi_req <= 1'b0;
o_spi_wr <= 1'b0;
if ((i_spi_stopped)&&(~i_grant))
rd_state <= `RD_IDLE;
end
`RD_GO_TO_XIP: begin
o_qspi_req <= 1'b1;
o_spi_wr <= 1'b0;
if (i_spi_stopped)
rd_state <= `RD_XIP;
end
default: begin
// rd_state <= (i_grant)?`RD_BREAK;
o_qspi_req <= 1'b0;
o_spi_wr <= 1'b0;
if ((i_spi_stopped)&&(~i_grant))
rd_state <= `RD_IDLE;
end
endcase
end
 
assign o_spi_hold = 1'b0;
 
endmodule
 
module writeqspi(i_clk, i_wreq, i_ereq, i_pipewr, i_endpipe, i_addr, i_data,
o_bus_ack, o_qspi_req, i_qspi_grant,
o_spi_wr, o_spi_hold, o_spi_word, o_spi_len,
o_spi_spd, o_spi_dir, i_spi_data, i_spi_valid,
i_spi_busy, i_spi_stopped,
o_data_ack, i_quad, o_wip);
input i_clk;
//
input i_wreq, i_ereq, i_pipewr, i_endpipe;
input [21:0] i_addr;
input [31:0] i_data;
output reg o_bus_ack, o_qspi_req;
input i_qspi_grant;
output reg o_spi_wr, o_spi_hold;
output reg [31:0] o_spi_word;
output reg [1:0] o_spi_len;
output reg o_spi_spd, o_spi_dir;
input [31:0] i_spi_data;
input i_spi_valid;
input i_spi_busy, i_spi_stopped;
output reg o_data_ack;
input i_quad;
output reg o_wip;
 
`ifdef QSPI_READ_ONLY
always @(posedge i_clk)
o_data_ack <= (i_wreq)||(i_ereq);
always @(posedge i_clk)
o_bus_ack <= (i_wreq)||(i_ereq);
 
always @(posedge i_clk)
begin
o_qspi_req <= 1'b0;
o_spi_wr <= 1'b0;
o_spi_hold <= 1'b0;
o_spi_dir <= 1'b1; // Read
o_spi_spd <= i_quad;
o_spi_len <= 2'b00;
o_spi_word <= 32'h00;
o_wip <= 1'b0;
end
`else
 
`define WR_IDLE 4'h0
`define WR_START_WRITE 4'h1
`define WR_START_QWRITE 4'h2
`define WR_PROGRAM 4'h3
`define WR_PROGRAM_GETNEXT 4'h4
`define WR_START_ERASE 4'h5
`define WR_WAIT_ON_STOP 4'h6
`define WR_REQUEST_STATUS 4'h7
`define WR_REQUEST_STATUS_NEXT 4'h8
`define WR_READ_STATUS 4'h9
`define WR_WAIT_ON_FINAL_STOP 4'ha
 
reg accepted;
initial accepted = 1'b0;
always @(posedge i_clk)
accepted <= (~i_spi_busy)&&(i_qspi_grant)&&(o_spi_wr)&&(~accepted);
 
 
reg cyc, chk_wip;
reg [3:0] wr_state;
initial wr_state = `WR_IDLE;
initial cyc = 1'b0;
always @(posedge i_clk)
begin
chk_wip <= 1'b0;
o_bus_ack <= 1'b0;
o_data_ack <= 1'b0;
cyc <= (cyc)&&(~i_endpipe);
case(wr_state)
`WR_IDLE: begin
o_qspi_req <= 1'b0;
cyc <= 1'b0;
if (i_ereq)
wr_state <= `WR_START_ERASE;
else if (i_wreq)
wr_state <= (i_quad)?`WR_START_QWRITE
: `WR_START_WRITE;
end
`WR_START_WRITE: begin
o_wip <= 1'b1;
o_qspi_req <= 1'b1;
o_spi_wr <= 1'b1;
o_spi_dir <= 1'b0;
o_spi_len <= 2'b11;
o_spi_spd <= 1'b0;
o_spi_hold <= 1'b1;
o_spi_word <= { 8'h02, i_addr, 2'b00 };
cyc <= 1'b1;
if (accepted)
begin
o_bus_ack <= 1'b1;
o_data_ack <= 1'b1;
wr_state <= `WR_PROGRAM;
o_spi_word <= i_data;
end end
`WR_START_QWRITE: begin
o_wip <= 1'b1;
o_qspi_req <= 1'b1;
o_spi_wr <= 1'b1;
o_spi_dir <= 1'b0;
o_spi_len <= 2'b11;
o_spi_spd <= 1'b0;
o_spi_hold <= 1'b1;
o_spi_word <= { 8'h32, i_addr, 2'b00 };
cyc <= 1'b1;
if (accepted)
begin
o_bus_ack <= 1'b1;
o_data_ack <= 1'b1;
wr_state <= `WR_PROGRAM;
o_spi_word <= i_data;
end end
`WR_PROGRAM: begin
o_wip <= 1'b1;
o_qspi_req <= 1'b1;
o_spi_wr <= 1'b1;
o_spi_dir <= 1'b0;
o_spi_len <= 2'b11;
o_spi_spd <= i_quad;
o_spi_hold <= 1'b1;
// o_spi_word <= i_data;
if (accepted)
wr_state <= `WR_PROGRAM_GETNEXT;
end
`WR_PROGRAM_GETNEXT: begin
o_wip <= 1'b1;
o_qspi_req <= 1'b1;
o_spi_wr <= 1'b0;
o_spi_dir <= 1'b0;
o_spi_len <= 2'b11;
o_spi_spd <= i_quad;
o_spi_hold <= 1'b1;
o_spi_word <= i_data;
if (~cyc)
wr_state <= `WR_WAIT_ON_STOP;
else if (i_pipewr)
begin
o_bus_ack <= 1'b1;
o_data_ack <= 1'b1;
wr_state <= `WR_PROGRAM;
end end
`WR_START_ERASE: begin
o_wip <= 1'b1;
o_qspi_req <= 1'b1;
o_spi_wr <= 1'b1;
o_spi_dir <= 1'b0;
o_spi_spd <= 1'b0;
o_spi_len <= 2'b11;
if (i_data[28])
// Subsector erase
o_spi_word[31:24] <= 8'h20;
else
// Sector erase
o_spi_word[31:24] <= 8'hd8;
o_spi_word[23:0] <= { i_data[21:10], 12'h0 };
// Data has already been ack'd, so no need to ack
// it again. However, we can now free the QSPI
// bus processor to accept another command from the
// bus.
o_bus_ack <= accepted;
if (accepted)
wr_state <= `WR_WAIT_ON_STOP;
end
`WR_WAIT_ON_STOP: begin
o_wip <= 1'b1;
o_qspi_req <= 1'b0;
o_spi_wr <= 1'b0;
o_spi_hold <= 1'b0;
if (i_spi_stopped)
wr_state <= `WR_REQUEST_STATUS;
end
`WR_REQUEST_STATUS: begin
o_wip <= 1'b1;
o_qspi_req <= 1'b1;
o_spi_hold <= 1'b0;
o_spi_wr <= 1'b1;
o_spi_spd <= 1'b0; // Slow speed
o_spi_len <= 2'b00; // 8 bytes
o_spi_dir <= 1'b0; // Write
o_spi_word <= { 8'h05, 24'h00 };
if (accepted)
wr_state <= `WR_REQUEST_STATUS_NEXT;
end
`WR_REQUEST_STATUS_NEXT: begin
o_wip <= 1'b1;
o_qspi_req <= 1'b1;
o_spi_hold <= 1'b0;
o_spi_wr <= 1'b1;
o_spi_spd <= 1'b0; // Slow speed
o_spi_len <= 2'b00; // 8 bytes
o_spi_dir <= 1'b1; // Read
o_spi_word <= 32'h00;
if (accepted)
wr_state <= `WR_READ_STATUS;
end
`WR_READ_STATUS: begin
o_wip <= 1'b1;
o_qspi_req <= 1'b1;
o_spi_hold <= 1'b0;
o_spi_wr <= 1'b1;
o_spi_spd <= 1'b0; // Slow speed
o_spi_len <= 2'b00; // 8 bytes
o_spi_dir <= 1'b1; // Read
o_spi_word <= 32'h00;
if (i_spi_valid)
chk_wip <= 1'b1;
if ((chk_wip)&&(~i_spi_data[0]))
wr_state <= `WR_WAIT_ON_FINAL_STOP;
end
// `WR_WAIT_ON_FINAL_STOP: // Same as the default
default: begin
o_qspi_req <= 1'b0;
o_spi_wr <= 1'b0;
o_wip <= 1'b0;
if (i_spi_stopped)
wr_state <= `WR_IDLE;
end
endcase
end
`endif
 
endmodule
 
 
`define CT_SAFE
`define CT_IDLE 3'h0
`define CT_NEXT 3'h1
`define CT_GRANTED 3'h2
`define CT_DATA 3'h3
`define CT_READ_DATA 3'h4
`define CT_WAIT_FOR_IDLE 3'h5
 
// CTRL commands:
// WEL (write-enable latch)
// Read Status
module ctrlspi(i_clk, i_req, i_wr, i_addr, i_data, i_sector_address,
o_spi_req, i_grant,
o_spi_wr, o_spi_hold, o_spi_word, o_spi_len,
o_spi_spd, o_spi_dir,
i_spi_data, i_spi_valid, i_spi_busy,
i_spi_stopped,
o_bus_ack, o_data_ack, o_data, o_xip, o_quad);
input i_clk;
// From the WB bus controller
input i_req;
input i_wr;
input [2:0] i_addr;
input [31:0] i_data;
input [21:0] i_sector_address;
// To/from the arbiter
output reg o_spi_req;
input i_grant;
// To/from the low-level SPI driver
output reg o_spi_wr;
output wire o_spi_hold;
output reg [31:0] o_spi_word;
output reg [1:0] o_spi_len;
output wire o_spi_spd;
output reg o_spi_dir;
input [31:0] i_spi_data;
input i_spi_valid;
input i_spi_busy, i_spi_stopped;
// Return data to the bus controller, and the wishbone bus
output reg o_bus_ack, o_data_ack;
output reg [31:0] o_data;
// Configuration items that we may have configured.
output reg o_xip;
output wire o_quad;
 
// Command registers
reg [1:0] ctcmd_len;
reg [31:0] ctcmd_word;
// Data stage registers
reg ctdat_skip, // Skip the data phase?
ctdat_wr; // Write during data? (or not read)
wire [1:0] ctdat_len;
reg [31:0] ctdat_word;
 
reg [2:0] ctstate;
reg accepted;
 
 
initial accepted = 1'b0;
always @(posedge i_clk)
accepted <= (~i_spi_busy)&&(i_grant)&&(o_spi_wr)&&(~accepted);
 
reg r_ctdat_len, ctbus_ack;
assign ctdat_len = { 1'b0, r_ctdat_len };
 
// First step, calculate the values for our state machine
initial o_xip = 1'b0;
// initial o_quad = 1'b0;
always @(posedge i_clk)
if (i_req) // A request for us to act from the bus controller
begin
ctdat_skip <= 1'b0;
ctbus_ack <= 1'b1;
ctcmd_word[23:0] <= { i_sector_address, 2'b00 };
ctdat_word <= { i_data[7:0], 24'h00 };
ctcmd_len <= 2'b00; // 8bit command (for all but Lock regs)
r_ctdat_len <= 1'b0; // 8bit data (read or write)
ctdat_wr <= i_wr;
casez({ i_addr[2:0], i_wr, i_data[30] })
5'b00010: begin // Write Disable
ctcmd_word[31:24] <= 8'h04;
ctdat_skip <= 1'b1;
ctbus_ack <= 1'b0;
end
5'b00011: begin // Write enable
ctcmd_word[31:24] <= 8'h06;
ctdat_skip <= 1'b1;
ctbus_ack <= 1'b0;
end
// 4'b0010?: begin // Read Status register
// Moved to defaults section
5'b0011?: begin // Write Status register (Requires WEL)
ctcmd_word[31:24] <= 8'h01;
`ifdef CT_SAFE
ctdat_word <= { 6'h00, i_data[1:0], 24'h00 };
`else
ctdat_word <= { i_data[7:0], 24'h00 };
`endif
end
5'b0100?: begin // Read NV-Config register (two bytes)
ctcmd_word[31:24] <= 8'hB5;
r_ctdat_len <= 1'b1; // 16-bit data
end
5'b0101?: begin // Write NV-Config reg (2 bytes, Requires WEL)
ctcmd_word[31:24] <= 8'hB1;
r_ctdat_len <= 1'b1; // 16-bit data
`ifdef CT_SAFE
ctdat_word <= { 4'h8, 3'h7, 3'h7, i_data[5:1], 1'b1, 16'h00 };
`else
ctdat_word <= { i_data[15:0], 16'h00 };
`endif
end
5'b0110?: begin // Read V-Config register
ctcmd_word[31:24] <= 8'h85;
end
5'b0111?: begin // Write V-Config register (Requires WEL)
ctcmd_word[31:24] <= 8'h81;
r_ctdat_len <= 1'b0; // 8-bit data
`ifdef CT_SAFE
ctdat_word <= { 4'h8, i_data[3:2], 2'b11, 24'h00 };
`else
ctdat_word <= { i_data[7:0], 24'h00 };
`endif
o_xip <= i_data[3];
end
5'b1000?: begin // Read EV-Config register
ctcmd_word[31:24] <= 8'h65;
end
5'b1001?: begin // Write EV-Config register (Requires WEL)
ctcmd_word[31:24] <= 8'h61;
// o_quad <= (~i_data[7]);
`ifdef CT_SAFE
ctdat_word <= { 1'b1, 3'h5, 4'hf, 24'h00 };
`else
ctdat_word <= { i_data[7:0], 24'h00 };
`endif
end
5'b1010?: begin // Read Lock register
ctcmd_word[31:0] <= { 8'he8, i_sector_address, 2'b00 };
ctcmd_len <= 2'b11;
ctdat_wr <= 1'b0; // Read, not write
end
5'b1011?: begin // Write Lock register (Requires WEL)
ctcmd_word[31:0] <= { 8'he5, i_sector_address, 2'b00 };
ctcmd_len <= 2'b11;
ctdat_wr <= 1'b1; // Write
end
5'b1100?: begin // Read Flag Status register
ctcmd_word[31:24] <= 8'h70;
ctdat_wr <= 1'b0; // Read, not write
end
5'b1101?: begin // Write/Clear Flag Status register (No WEL required)
ctcmd_word[31:24] <= 8'h50;
ctdat_skip <= 1'b1;
end
default: begin // Default to reading the status register
ctcmd_word[31:24] <= 8'h05;
ctdat_wr <= 1'b0; // Read, not write
r_ctdat_len <= 1'b0; // 8-bit data
end
endcase
end
 
assign o_quad = 1'b1;
 
reg nxt_data_ack;
 
// Second step, actually drive the state machine
initial ctstate = `CT_IDLE;
always @(posedge i_clk)
begin
o_spi_wr <= 1'b1;
o_bus_ack <= 1'b0;
o_data_ack <= 1'b0;
if (i_spi_valid)
o_data <= i_spi_data;
case(ctstate)
`CT_IDLE: begin
o_spi_req <= 1'b0;
o_spi_wr <= 1'b0;
if (i_req) // Need a clock to let the digestion
ctstate <= `CT_NEXT; // process complete
end
`CT_NEXT: begin
o_spi_wr <= 1'b1;
o_spi_req <= 1'b1;
o_spi_word <= ctcmd_word;
o_spi_len <= ctcmd_len;
o_spi_dir <= 1'b0; // Write
if (accepted)
begin
ctstate <= (ctdat_skip)?`CT_WAIT_FOR_IDLE:`CT_DATA;
o_bus_ack <= (ctdat_skip);
o_data_ack <= (ctdat_skip)&&(ctbus_ack);
end end
`CT_GRANTED: begin
o_spi_wr <= 1'b1;
if ((accepted)&&(ctdat_skip))
ctstate <= `CT_WAIT_FOR_IDLE;
else if (accepted)//&&(~ctdat_skip)
ctstate <= `CT_DATA;
end
`CT_DATA: begin
o_spi_wr <= 1'b1;
o_spi_len <= ctdat_len;
o_spi_dir <= ~ctdat_wr;
o_spi_word <= ctdat_word;
if (accepted)
o_bus_ack <= 1'b1;
if (accepted)
ctstate <= (ctdat_wr)?`CT_WAIT_FOR_IDLE:`CT_READ_DATA;
if ((accepted)&&(ctdat_wr))
o_data_ack <= 1'b1;
end
`CT_READ_DATA: begin
o_spi_wr <= 1'b0; // No more words to go, just to wait
o_spi_req <= 1'b1;
if (i_spi_valid) // for a value to read
begin
o_data_ack <= 1'b1;
o_data <= i_spi_data;
ctstate <= `CT_WAIT_FOR_IDLE;
end end
default: begin // `CT_WAIT_FOR_IDLE
o_spi_wr <= 1'b0;
o_spi_req <= 1'b0;
if (i_spi_stopped)
ctstate <= `CT_IDLE;
end
endcase
end
// All of this is done in straight SPI mode, so our speed will always be zero
assign o_spi_hold = 1'b0;
assign o_spi_spd = 1'b0;
 
endmodule
 
`define ID_IDLE 5'h00
`define ID_WAIT_ON_START_ID 5'h01
`define ID_WAIT_ON_START_OTP 5'h02
`define ID_WAIT_ON_START_OTP_WRITE 5'h03
`define ID_READ_DATA_COMMAND 5'h04
`define ID_GET_DATA 5'h05
`define ID_LOADED 5'h06
`define ID_LOADED_NEXT 5'h07
`define ID_OTP_SEND_DUMMY 5'h08
`define ID_OTP_CLEAR 5'h09
`define ID_OTP_GET_DATA 5'h0a
`define ID_OTP_WRITE 5'h0b
`define ID_WAIT_ON_STOP 5'h0c
`define ID_REQ_STATUS 5'h0d
`define ID_REQ_STATUS_NEXT 5'h0e
`define ID_READ_STATUS 5'h0f
//
`define ID_FINAL_STOP 5'h10
 
module idotpqspi(i_clk, i_req, i_wr, i_pipewr, i_addr, i_data, o_bus_ack,
o_qspi_req, i_qspi_grant,
o_spi_wr, o_spi_hold, o_spi_word, o_spi_len,
o_spi_spd, o_spi_dir, i_spi_data, i_spi_valid,
i_spi_busy, i_spi_stopped, o_data_ack, o_data, o_loaded,
o_wip);
input i_clk;
input i_req, i_wr, i_pipewr;
input [4:0] i_addr;
input [31:0] i_data;
output reg o_bus_ack, o_qspi_req;
input i_qspi_grant;
output reg o_spi_wr, o_spi_hold;
output reg [31:0] o_spi_word;
output reg [1:0] o_spi_len;
output wire o_spi_spd;
output reg o_spi_dir;
input [31:0] i_spi_data;
input i_spi_valid, i_spi_busy, i_spi_stopped;
output reg o_data_ack;
output reg [31:0] o_data;
output wire o_loaded;
output reg o_wip;
 
reg id_loaded;
initial id_loaded = 1'b0;
assign o_loaded= id_loaded;
 
/*
// Only the ID register will be kept in memory, OTP will be read
// or written upon request
always @(posedge i_clk)
if (i_addr[4])
o_data <= otpmem[i_addr[3:0]];
else
o_data <= idmem[i_addr[2:0]];
 
always @(posedge i_clk)
if ((otp_loaded)&&(i_req)&&(i_addr[4]))
o_data_ack <= 1'b1;
else if ((id_loaded)&&(i_req)&&(~i_addr[4]))
o_data_ack <= idmem[i_addr[2:0]];
else
o_data_ack <= 1'b0;
*/
 
reg otp_read_request, id_read_request, accepted, otp_wr_request,
id_read_device, last_id_read;
reg [4:0] req_addr;
reg [2:0] lcl_id_addr;
reg [4:0] id_state;
always @(posedge i_clk)
begin
otp_read_request <= (i_req)&&(~i_wr)&&((i_addr[4])||(i_addr[3:0]==4'hf));
last_id_read <= (i_req)&&(~i_addr[4])&&(i_addr[3:0]!=4'hf);
id_read_request <= (i_req)&&(~i_addr[4])&&(i_addr[3:0]!=4'hf)&&(~last_id_read);
id_read_device <= (i_req)&&(~i_addr[4])&&(i_addr[3:0]!=4'hf)&&(~id_loaded);
accepted <= (~i_spi_busy)&&(i_qspi_grant)&&(o_spi_wr)&&(~accepted);
 
otp_wr_request <= (i_req)&&(i_wr)&&((i_addr[4])||(i_addr[3:0]==4'hf));
 
if (id_state == `ID_IDLE)
req_addr <= (i_addr[4:0]==5'h0f) ? 5'h10
: { 1'b0, i_addr[3:0] };
end
 
reg last_addr;
always @(posedge i_clk)
last_addr <= (lcl_id_addr >= 3'h4);
 
reg [31:0] idmem[0:5];
reg [31:0] r_data;
 
// Now, quickly, let's deal with the fact that the data from the
// bus comes one clock later ...
reg nxt_data_ack, nxt_data_spi;
reg [31:0] nxt_data;
 
reg set_val, chk_wip;
reg [2:0] set_addr;
 
always @(posedge i_clk)
begin // Depends upon state[4], otp_rd, otp_wr, otp_pipe, id_req, accepted, last_addr
o_bus_ack <= 1'b0;
// o_data_ack <= 1'b0;
o_spi_hold <= 1'b0;
nxt_data_ack <= 1'b0;
nxt_data_spi <= 1'b0;
chk_wip <= 1'b0;
set_val <= 1'b0;
if ((id_loaded)&&(id_read_request))
begin
nxt_data_ack <= 1'b1;
o_bus_ack <= 1'b1;
end
nxt_data <= idmem[i_addr[2:0]];
o_spi_wr <= 1'b0; // By default, we send nothing
case(id_state)
`ID_IDLE: begin
o_qspi_req <= 1'b0;
o_spi_dir <= 1'b0; // Write to SPI
lcl_id_addr <= 3'h0;
o_spi_word[23:7] <= 17'h00;
o_spi_word[6:0] <= { req_addr[4:0], 2'b00 };
r_data <= i_data;
o_wip <= 1'b0;
if (otp_read_request)
begin
// o_spi_word <= { 8'h48, 8'h00, 8'h00, 8'h00 };
id_state <= `ID_WAIT_ON_START_OTP;
o_bus_ack <= 1'b1;
end else if (otp_wr_request)
begin
o_bus_ack <= 1'b1;
// o_data_ack <= 1'b1;
nxt_data_ack <= 1'b1;
id_state <= `ID_WAIT_ON_START_OTP_WRITE;
end else if (id_read_device)
begin
id_state <= `ID_WAIT_ON_START_ID;
o_bus_ack <= 1'b0;
o_spi_word[31:24] <= 8'h9f;
end end
`ID_WAIT_ON_START_ID: begin
o_spi_wr <= 1'b1;
o_qspi_req <= 1'b1;
o_spi_len <= 2'b0; // 8 bits
if (accepted)
id_state <= `ID_READ_DATA_COMMAND;
end
`ID_WAIT_ON_START_OTP: begin
o_spi_wr <= 1'b1;
o_spi_word[31:24] <= 8'h4B;
o_qspi_req <= 1'b1;
o_spi_len <= 2'b11; // 32 bits
o_spi_word[6:0] <= { req_addr[4:0], 2'b00 };
if (accepted) // Read OTP command was just sent
id_state <= `ID_OTP_SEND_DUMMY;
end
`ID_WAIT_ON_START_OTP_WRITE: begin
o_spi_wr <= 1'b1;
o_qspi_req <= 1'b1;
o_wip <= 1'b1;
o_spi_len <= 2'b11; // 32 bits
o_spi_word[31:24] <= 8'h42;
if (accepted) // Read OTP command was just sent
id_state <= `ID_OTP_WRITE;
end
`ID_READ_DATA_COMMAND: begin
o_spi_len <= 2'b11; // 32-bits
o_spi_wr <= (~last_addr); // Still transmitting
o_spi_dir <= 1'b1; // Read from SPI
o_qspi_req <= 1'b1;
if (accepted)
id_state <= `ID_GET_DATA;
end
`ID_GET_DATA: begin
o_spi_len <= 2'b11; // 32-bits
o_spi_wr <= (~last_addr); // Still transmitting
o_spi_dir <= 1'b1; // Read from SPI
o_qspi_req <= 1'b1;
if (i_spi_valid) // same as accepted
begin
set_val <= 1'b1;
set_addr <= lcl_id_addr[2:0];
// idmem[lcl_id_addr[2:0]] <= i_spi_data;
lcl_id_addr <= lcl_id_addr + 3'h1;
if (last_addr)
id_state <= `ID_LOADED;
end end
`ID_LOADED: begin
id_loaded <= 1'b1;
o_bus_ack <= 1'b1;
o_spi_wr <= 1'b0;
nxt_data_ack <= 1'b1;
id_state <= `ID_LOADED_NEXT;
end
`ID_LOADED_NEXT: begin
o_spi_len <= 2'b11; // 32-bits
o_bus_ack <= 1'b0;
o_spi_wr <= 1'b0;
nxt_data_ack <= 1'b1;
id_state <= `ID_IDLE;
end
`ID_OTP_SEND_DUMMY: begin
o_spi_len <= 2'b00; // 1 byte
o_spi_wr <= 1'b1; // Still writing
o_spi_dir <= 1'b0; // Write to SPI
if (accepted) // Wait for the command to be accepted
id_state <= `ID_OTP_CLEAR;
end
`ID_OTP_CLEAR: begin
o_spi_wr <= 1'b1; // Still writing
o_spi_dir <= 1'b1; // Read from SPI
o_spi_len <= 2'b11; // Read from SPI
if (accepted)
id_state <= `ID_OTP_GET_DATA;
end
`ID_OTP_GET_DATA: begin
if (i_spi_valid)
begin
id_state <= `ID_FINAL_STOP;
nxt_data_ack <= 1'b1;
nxt_data_spi <= 1'b1;
end end
`ID_OTP_WRITE: begin
o_spi_wr <= 1'b1;
o_spi_len <= 2'b11;
o_spi_dir <= 1'b0; // Write to SPI
o_spi_word <= r_data;
// o_bus_ack <= (otp_wr_request)&&(accepted)&&(i_pipewr);
// o_data_ack <= (otp_wr_request)&&(accepted);
if (accepted) // &&(~i_pipewr)
id_state <= `ID_WAIT_ON_STOP;
else if(accepted)
begin
o_spi_word <= i_data;
r_data <= i_data;
end end
`ID_WAIT_ON_STOP: begin
o_spi_wr <= 1'b0;
if (i_spi_stopped)
id_state <= `ID_REQ_STATUS;
end
`ID_REQ_STATUS: begin
o_spi_wr <= 1'b1;
o_spi_hold <= 1'b0;
o_spi_word[31:24] <= 8'h05;
o_spi_dir <= 1'b0;
o_spi_len <= 2'b00;
if (accepted)
id_state <= `ID_REQ_STATUS_NEXT;
end
`ID_REQ_STATUS_NEXT: begin
o_spi_wr <= 1'b1;
o_spi_hold <= 1'b0;
o_spi_dir <= 1'b1; // Read
o_spi_len <= 2'b00; // 8 bits
// o_spi_word <= dont care
if (accepted)
id_state <= `ID_READ_STATUS;
end
`ID_READ_STATUS: begin
o_spi_wr <= 1'b1;
o_spi_hold <= 1'b0;
o_spi_dir <= 1'b1; // Read
o_spi_len <= 2'b00; // 8 bits
// o_spi_word <= dont care
if (i_spi_valid)
chk_wip <= 1'b1;
if ((chk_wip)&&(~i_spi_data[0]))
begin
o_wip <= 1'b0;
id_state <= `ID_FINAL_STOP;
end end
default: begin // ID_FINAL_STOP
o_bus_ack <= 1'b0;
nxt_data_ack <= 1'b0;
o_qspi_req <= 1'b0;
o_spi_wr <= 1'b0;
o_spi_hold <= 1'b0;
o_spi_dir <= 1'b1; // Read
o_spi_len <= 2'b00; // 8 bits
// o_spi_word <= dont care
if (i_spi_stopped)
id_state <= `ID_IDLE;
end
endcase
end
 
always @(posedge i_clk)
begin
if (nxt_data_ack)
o_data <= (nxt_data_spi)?i_spi_data : nxt_data;
o_data_ack <= nxt_data_ack;
end
 
always @(posedge i_clk)
if (set_val)
idmem[set_addr] <= i_spi_data;
 
assign o_spi_spd = 1'b0; // Slow, 1-bit at a time
 
endmodule
 
 
 
/rtl/wbufifo.v
0,0 → 1,132
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wbufifo.v
//
// Project: FPGA library
//
// Purpose: This was once a FIFO for a UART ... but now it works as a
// synchronous FIFO for JTAG-wishbone conversion 36-bit codewords.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
module wbufifo(i_clk, i_rst, i_wr, i_data, i_rd, o_data, o_empty_n, o_err);
parameter BW=66, LGFLEN=10, FLEN=(1<<LGFLEN);
input i_clk, i_rst;
input i_wr;
input [(BW-1):0] i_data;
input i_rd;
output reg [(BW-1):0] o_data;
output reg o_empty_n;
output wire o_err;
 
reg [(BW-1):0] fifo[0:(FLEN-1)];
reg [(LGFLEN-1):0] r_first, r_last;
 
reg will_overflow;
initial will_overflow = 1'b0;
always @(posedge i_clk)
if (i_rst)
will_overflow <= 1'b0;
else if (i_rd)
will_overflow <= (will_overflow)&&(i_wr);
else if (i_wr)
will_overflow <= (r_first+2 == r_last);
else if (r_first+1 == r_last)
will_overflow <= 1'b1;
 
// Write
initial r_first = 0;
always @(posedge i_clk)
if (i_rst)
r_first <= { (LGFLEN){1'b0} };
else if (i_wr)
begin // Cowardly refuse to overflow
if ((i_rd)||(~will_overflow)) // (r_first+1 != r_last)
r_first <= r_first+{{(LGFLEN-1){1'b0}},1'b1};
// else o_ovfl <= 1'b1;
end
always @(posedge i_clk)
if (i_wr) // Write our new value regardless--on overflow or not
fifo[r_first] <= i_data;
 
// Reads
// Following a read, the next sample will be available on the
// next clock
// Clock ReadCMD ReadAddr Output
// 0 0 0 fifo[0]
// 1 1 0 fifo[0]
// 2 0 1 fifo[1]
// 3 0 1 fifo[1]
// 4 1 1 fifo[1]
// 5 1 2 fifo[2]
// 6 0 3 fifo[3]
// 7 0 3 fifo[3]
reg will_underflow;
initial will_underflow = 1'b0;
always @(posedge i_clk)
if (i_rst)
will_underflow <= 1'b0;
else if (i_wr)
will_underflow <= (will_underflow)&&(i_rd);
else if (i_rd)
will_underflow <= (r_last+1==r_first);
else
will_underflow <= (r_last == r_first);
 
initial r_last = 0;
always @(posedge i_clk)
if (i_rst)
r_last <= { (LGFLEN){1'b0} };
else if (i_rd)
begin
if ((i_wr)||(~will_underflow)) // (r_first != r_last)
r_last <= r_last+{{(LGFLEN-1){1'b0}},1'b1};
// Last chases first
// Need to be prepared for a possible two
// reads in quick succession
// o_data <= fifo[r_last+1];
// else o_unfl <= 1'b1;
end
always @(posedge i_clk)
o_data <= fifo[(i_rd)?(r_last+{{(LGFLEN-1){1'b0}},1'b1})
:(r_last)];
 
wire [(LGFLEN-1):0] nxt_first;
assign nxt_first = r_first+{{(LGFLEN-1){1'b0}},1'b1};
assign o_err = ((i_wr)&&(will_overflow)&&(~i_rd))
||((i_rd)&&(will_underflow)&&(~i_wr));
 
// wire [(LGFLEN-1):0] fill;
// assign fill = (r_first-r_last);
wire [(LGFLEN-1):0] nxt_last;
assign nxt_last = r_last+{{(LGFLEN-1){1'b0}},1'b1};
always @(posedge i_clk)
if (i_rst)
o_empty_n <= 1'b0;
else
o_empty_n <= (~i_rd)&&(r_first != r_last)
||(i_rd)&&(r_first != nxt_last);
endmodule
/rtl/rtcgps.v
0,0 → 1,464
///////////////////////////////////////////////////////////////////////////
//
// Filename: rtcgps.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: Implement a real time clock, including alarm, count--down
// timer, stopwatch, variable time frequency, and more.
//
// This particular version has hooks for a GPS 1PPS, as well as a
// finely tracked clock speed output, to allow for fine clock precision
// and good freewheeling even if/when GPS is lost.
//
//
// 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 rtcgps(i_clk,
// Wishbone interface
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
// o_wb_ack, o_wb_stb, o_wb_data, // no reads here
// Output registers
o_data, // multiplexed based upon i_wb_addr
// Output controls
o_interrupt,
// A once-per-day strobe on the last clock of the day
o_ppd,
// GPS interface
i_gps_valid, i_gps_pps, i_gps_ckspeed,
// Our personal timing, for debug purposes
o_rtc_pps);
parameter DEFAULT_SPEED = 32'd2814750; //2af31e = 2^48 / 100e6 MHz
input i_clk;
input i_wb_cyc, i_wb_stb, i_wb_we;
input [1:0] i_wb_addr;
input [31:0] i_wb_data;
// input i_btn;
output reg [31:0] o_data;
output wire o_interrupt, o_ppd;
// GPS interface
input i_gps_valid, i_gps_pps;
input [31:0] i_gps_ckspeed;
// Personal PPS
output wire o_rtc_pps;
 
reg [21:0] clock;
reg [31:0] stopwatch, ckspeed;
reg [25:0] timer;
reg ck_wr, tm_wr, sw_wr, al_wr, r_data_zero_byte;
reg [25:0] r_data;
always @(posedge i_clk)
begin
ck_wr <= ((i_wb_stb)&&(i_wb_addr==2'b00)&&(i_wb_we));
tm_wr <= ((i_wb_stb)&&(i_wb_addr==2'b01)&&(i_wb_we));
sw_wr <= ((i_wb_stb)&&(i_wb_addr==2'b10)&&(i_wb_we));
al_wr <= ((i_wb_stb)&&(i_wb_addr==2'b11)&&(i_wb_we));
r_data <= i_wb_data[25:0];
r_data_zero_byte <= (i_wb_data[7:0] == 8'h00);
end
 
reg [39:0] ck_counter;
reg ck_carry, ck_sub_carry;
always @(posedge i_clk)
if ((i_gps_valid)&&(i_gps_pps))
begin
ck_carry <= 0;
// Start our counter 2 clocks into the future.
// Why? Because if we hit the PPS, we'll be delayed
// one clock from true time. This (hopefully) locks
// us back onto true time. Further, if we end up
// off (i.e., go off before the GPS tick ...) then
// the GPS tick will put us back on track ... likewise
// we've got code following that should keep us from
// ever producing two PPS's per second.
ck_counter <= { 7'h00, ckspeed, 1'b0 };
ck_sub_carry <= ckspeed[31];
end else begin
{ ck_sub_carry, ck_counter[31:0] }
<= ck_counter[31:0] + ckspeed;
{ ck_carry, ck_counter[39:32] }
<= ck_counter[39:32] + { 7'h0, ck_sub_carry };
end
 
reg ck_pps;
reg ck_ppm, ck_pph, ck_ppd;
reg [7:0] ck_sub;
initial clock = 22'h00000000;
always @(posedge i_clk)
if ((i_gps_pps)&&(i_gps_valid)&&(ck_sub[7]))
ck_pps <= 1'b1;
else if ((ck_carry)&&(ck_sub == 8'hff))
ck_pps <= 1'b1;
else
ck_pps <= 1'b0;
 
reg [6:0] next_clock_secs;
always @(posedge i_clk)
begin
next_clock_secs[3:0] <= (clock[3:0] >= 4'h9) ? 4'h0 // clk 1
: (clock[3:0] + 4'h1);
next_clock_secs[6:4] <= (ck_ppm) ? 3'h0 // clk 2
: (clock[3:0] >= 4'h9)
? (clock[6:4] + 3'h1)
: clock[6:4];
end
 
reg [6:0] next_clock_mins;
always @(posedge i_clk)
begin
next_clock_mins[3:0] <= (clock[11:8] >= 4'h9) ? 4'h0
: (clock[11:8] + 4'h1);
next_clock_mins[6:4] <= (ck_pph) ? 3'h0
: (clock[11:8] >= 4'h9)
? (clock[14:12] + 3'h1)
: clock[14:12];
end
 
reg [5:0] next_clock_hrs;
always @(posedge i_clk)
begin
next_clock_hrs[3:0] <= (clock[19:16] >= 4'h9) ? 4'h0
: (clock[19:16] + 4'h1);
next_clock_hrs[5:4] <= (ck_ppd) ? 2'h0
: (clock[19:16] >= 4'h9)
? (clock[21:20] + 2'h1)
: (clock[21:20]);
end
 
reg [4:0] ck_pending;
assign o_rtc_pps = ck_pps;
always @(posedge i_clk)
begin
if ((i_gps_valid)&&(i_gps_pps))
ck_sub <= 0;
else if (ck_carry)
ck_sub <= ck_sub + 1;
 
if ((ck_pps)&&(~ck_pending[4])) // advance the seconds
clock[6:0] <= next_clock_secs;
clock[7] <= 1'b0;
ck_ppm <= (clock[6:0] == 7'h59);
 
if ((ck_pps)&&(ck_ppm)&&(~ck_pending[4])) // advance the minutes
clock[14:8] <= next_clock_mins;
clock[15] <= 1'b0;
ck_pph <= (clock[14:8] == 7'h59)&&(ck_ppm);
 
if ((ck_pps)&&(ck_pph)&&(~ck_pending[4])) // advance the hours
clock[21:16] <= next_clock_hrs;
ck_ppd <= (clock[21:16] == 6'h23)&&(ck_pph);
 
clock[ 7] <= 1'b0;
clock[15] <= 1'b0;
 
if (ck_wr)
begin
if (~r_data[7])
clock[6:0] <= i_wb_data[6:0];
if (~r_data[15])
clock[14:8] <= i_wb_data[14:8];
if (~r_data[22])
clock[21:16] <= i_wb_data[21:16];
if ((~i_gps_valid)&&(r_data_zero_byte))
ck_sub <= 8'h00;
ck_pending <= 5'h1f;
end else
ck_pending <= { ck_pending[3:0], 1'b0 };
end
 
reg [21:0] ck_last_clock;
always @(posedge i_clk)
ck_last_clock <= clock[21:0];
 
 
 
//
reg [23:0] next_timer;
reg ztimer;
reg [4:0] tmr_carry;
always @(posedge i_clk)
begin
tmr_carry[0] <= (timer[ 3: 0]== 4'h0);
tmr_carry[1] <= (timer[ 6: 4]== 3'h0)&&(tmr_carry[0]);
tmr_carry[2] <= (timer[11: 8]== 4'h0)&&(tmr_carry[1]);
tmr_carry[3] <= (timer[14:12]== 3'h0)&&(tmr_carry[2]);
tmr_carry[4] <= (timer[19:16]== 4'h0)&&(tmr_carry[3]);
ztimer <= (timer[23:0]== 24'h0);
 
// Keep unused bits at zero
next_timer <= 24'h00;
// Seconds
next_timer[ 3: 0] <= (tmr_carry[0])? 4'h9: (timer[ 3: 0]-4'h1);
next_timer[ 6: 4] <= (tmr_carry[1])? 3'h5: (timer[ 6: 4]-3'h1);
// Minutes
next_timer[11: 8] <= (tmr_carry[2])? 4'h9: (timer[11: 8]-4'h1);
next_timer[14:12] <= (tmr_carry[3])? 3'h5: (timer[14:12]-3'h1);
// Hours
next_timer[19:16] <= (tmr_carry[4])? 4'h9: (timer[19:16]-4'h1);
next_timer[23:20] <= (timer[23:20]-4'h1);
end
 
reg new_timer, new_timer_set, new_timer_last, tm_pending_start;
reg [23:0] new_timer_val;
 
reg tm_pps, tm_ppm, tm_int;
wire tm_stopped, tm_running, tm_alarm;
assign tm_stopped = ~timer[24];
assign tm_running = timer[24];
assign tm_alarm = timer[25];
reg [23:0] tm_start;
reg [7:0] tm_sub;
initial tm_start = 24'h00;
initial timer = 26'h00;
initial tm_int = 1'b0;
initial tm_pps = 1'b0;
initial tm_pending_start = 1'b0;
always @(posedge i_clk)
begin
if (ck_carry)
begin
tm_sub <= tm_sub + 1;
tm_pps <= (tm_sub == 8'hff);
end else
tm_pps <= 1'b0;
if (new_timer_set) // Conclude a write
timer[23:0] <= new_timer_val;
else if ((~tm_alarm)&&(tm_running)&&(tm_pps))
begin // Otherwise, if we are running ...
timer[25] <= 1'b0; // Clear any alarm
if (ztimer) // unless we've hit zero
timer[25] <= 1'b1;
else if (~new_timer)
timer[23:0] <= next_timer;
end
 
tm_int <= (tm_running)&&(tm_pps)&&(~tm_alarm)&&(ztimer);
 
if (tm_alarm) // Stop the timer on an alarm
timer[24] <= 1'b0;
 
new_timer <= 1'b0;
tm_pending_start <= 1'b0;
if ((tm_wr)&&(tm_running)) // Writes while running
// Only allow the timer to stop, nothing more
timer[24] <= r_data[24];
else if ((tm_wr)&&(tm_stopped)) // Writes while off
begin
// We're going to pipeline this change by a couple
// of clocks, to get it right
new_timer <= 1'b1;
new_timer_val <= r_data[23:0];
tm_pending_start <= r_data[24];
 
// Still ... any write clears the alarm
timer[25] <= 1'b0;
end
 
new_timer_set <= (new_timer)&&(new_timer_val != 24'h000);
new_timer_last <= (new_timer)&&(new_timer_val == 24'h000);
if (new_timer_last)
begin
new_timer_val <= tm_start;
tm_sub <= 8'h00;
new_timer_set <= 1'b1;
tm_pending_start <= 1'b1;
end else if (new_timer_set)
begin
tm_start <= new_timer_val;
tm_sub <= 8'h00;
tm_pending_start <= 1'b1;
timer[24] <= 1'b1;
end
end
 
//
// Stopwatch functionality
//
// Setting bit '0' starts the stop watch, clearing it stops it.
// Writing to the register with bit '1' high will clear the stopwatch,
// and return it to zero provided that the stopwatch is stopped either
// before or after the write. Hence, writing a '2' to the device
// will always stop and clear it, whereas writing a '3' to the device
// will only clear it if it was already stopped.
reg [6:0] next_sw_secs;
always @(posedge i_clk)
begin
next_sw_secs[3:0] <= (stopwatch[11:8] >= 4'h9) ? 4'h0
: (stopwatch[11:8] + 4'h1);
next_sw_secs[6:4] <= (stopwatch[14:8] == 7'h59) ? 3'h0
: (stopwatch[11:8] == 4'h9)
? (stopwatch[14:12]+3'h1)
: stopwatch[14:12];
end
 
reg [6:0] next_sw_mins;
always @(posedge i_clk)
begin
next_sw_mins[3:0] <= (stopwatch[19:16] >= 4'h9) ? 4'h0
: (stopwatch[19:16] + 4'h1);
next_sw_mins[6:4] <= (stopwatch[22:16] == 7'h59) ? 3'h0
: (stopwatch[19:16]==4'h9)
? (stopwatch[22:20]+3'h1)
: stopwatch[22:20];
end
 
reg [5:0] next_sw_hrs;
always @(posedge i_clk)
begin
next_sw_hrs[3:0] <= (stopwatch[27:24] >= 4'h9) ? 4'h0
: (stopwatch[27:24] + 4'h1);
next_sw_hrs[5:4] <= (stopwatch[29:24] >= 6'h23) ? 2'h0
: (stopwatch[27:24]==4'h9)
? (stopwatch[29:28]+2'h1)
: stopwatch[29:28];
end
 
reg sw_pps, sw_ppm, sw_pph;
reg [7:0] sw_sub;
wire sw_running;
assign sw_running = stopwatch[0];
initial stopwatch = 32'h00000;
always @(posedge i_clk)
begin
sw_pps <= 1'b0;
if ((sw_running)&&(ck_carry))
begin
sw_sub <= sw_sub + 1;
sw_pps <= (sw_sub == 8'hff);
end
 
stopwatch[7:1] <= sw_sub[7:1];
 
if (sw_pps) // Second hand
stopwatch[14:8] <= next_sw_secs;
sw_ppm <= (stopwatch[14:8] == 7'h59);
 
if ((sw_pps)&&(sw_ppm)) // Minutes
stopwatch[22:16] <= next_sw_mins;
sw_pph <= (stopwatch[23:16] == 8'h59)&&(sw_ppm);
 
if ((sw_pps)&&(sw_pph)) // And hours
stopwatch[29:24] <= next_sw_hrs;
 
if (sw_wr)
begin
stopwatch[0] <= r_data[0];
if((r_data[1])&&((~stopwatch[0])||(~r_data[0])))
begin
stopwatch[31:1] <= 31'h00;
sw_sub <= 8'h00;
sw_pps <= 1'b0;
sw_ppm <= 1'b0;
sw_pph <= 1'b0;
end
end
end
 
//
// The alarm code
//
// Set the alarm register to the time you wish the board to "alarm".
// The "alarm" will take place once per day at that time. At that
// time, the RTC code will generate a clock interrupt, and the CPU/host
// can come and see that the alarm tripped.
//
//
reg [21:0] alarm_time;
reg al_int, // The alarm interrupt line
al_enabled, // Whether the alarm is enabled
al_tripped; // Whether the alarm has tripped
initial al_enabled= 1'b0;
initial al_tripped= 1'b0;
always @(posedge i_clk)
begin
if (al_wr)
begin
// Only adjust the alarm hours if the requested hours
// are valid. This allows writes to the register,
// without a prior read, to leave these configuration
// bits alone.
if (r_data[21:20] != 2'h3)
alarm_time[21:16] <= i_wb_data[21:16];
// Here's the same thing for the minutes: only adjust
// the alarm minutes if the new bits are not all 1's.
if (~r_data[15])
alarm_time[15:8] <= i_wb_data[15:8];
// Here's the same thing for the seconds: only adjust
// the alarm seconds if the new bits are not all 1's.
if (~r_data[7])
alarm_time[7:0] <= i_wb_data[7:0];
al_enabled <= i_wb_data[24];
// Reset the alarm if a '1' is written to the tripped
// register, or if the alarm is disabled.
if ((r_data[25])||(~r_data[24]))
al_tripped <= 1'b0;
end
 
al_int <= ((ck_last_clock != alarm_time)
&&(clock[21:0] == alarm_time)&&(al_enabled));
if (al_int)
al_tripped <= 1'b1;
end
 
//
// The ckspeed register is equal to 2^48 divded by the number of
// clock ticks you expect per second. Adjust high for a slower
// clock, lower for a faster clock. In this fashion, a single
// real time clock RTL file can handle tracking the clock in any
// device. Further, because this is only the lower 32 bits of a
// 48 bit counter per seconds, the clock jitter is kept below
// 1 part in 65 thousand.
//
initial ckspeed = DEFAULT_SPEED;
// In the case of verilator, comment the above and uncomment the line
// below. The clock constant below is "close" to simulation time,
// meaning that my verilator simulation is running about 300x slower
// than board time.
// initial ckspeed = 32'd786432000;
always @(posedge i_clk)
if (i_gps_valid)
ckspeed <= i_gps_ckspeed;
 
assign o_interrupt = tm_int || al_int;
 
// A once-per day strobe, on the last second of the day so that the
// the next clock is the first clock of the day. This is useful for
// connecting this module to a year/month/date date/calendar module.
assign o_ppd = (ck_ppd)&&(ck_pps);
 
always @(posedge i_clk)
case(i_wb_addr)
2'b00: o_data <= { ~i_gps_valid, 7'h0, 2'b00, clock[21:0] };
2'b01: o_data <= { 6'h00, timer };
2'b10: o_data <= stopwatch;
2'b11: o_data <= { 6'h00, al_tripped, al_enabled, 2'b00, alarm_time };
endcase
 
endmodule
/rtl/wbuexec.v
0,0 → 1,362
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wbuexec.v
//
// Project: FPGA library
//
// Purpose: This is the part of the USB-JTAG to wishbone conversion that
// actually conducts a wishbone transaction. Transactions are
// requested via codewords that come in, and the results recorded on
// codewords that are sent out. Compression and/or decompression, coding
// etc. all take place external to this routine.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`define WB_IDLE 3'b000
`define WB_READ_REQUEST 3'b001
`define WB_WRITE_REQUEST 3'b010
`define WB_ACK 3'b011
`define WB_WAIT_ON_NEXT_WRITE 3'b100
`define WB_FLUSH_WRITE_REQUESTS 3'b101
 
module wbuexec(i_clk, i_rst, i_stb, i_codword, o_busy,
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,
o_stb, o_codword);
input i_clk, i_rst;
// The command inputs
input i_stb;
input [35:0] i_codword;
output wire o_busy;
// Wishbone outputs
output reg o_wb_cyc;
output reg o_wb_stb;
output reg o_wb_we;
output reg [31:0] o_wb_addr, o_wb_data;
// Wishbone inputs
input i_wb_ack, i_wb_stall, i_wb_err;
input [31:0] i_wb_data;
// And our codeword outputs
output reg o_stb;
output reg [35:0] o_codword;
// output wire o_dbg;
 
 
wire w_accept, w_eow, w_newwr, w_new_err;
// wire w_newad, w_newrd;
assign w_accept = (i_stb)&&(~o_busy);
// assign w_newad = (w_accept)&&(i_codword[35:34] == 2'b00);
assign w_newwr = (w_accept)&&(i_codword[35:34] == 2'b01);
assign w_eow = (w_accept)&&(i_codword[35:30] == 6'h2e);
// assign w_newrd = (w_accept)&&(i_codword[35:34] == 2'b11);
wire [31:0] w_cod_data;
assign w_cod_data={ i_codword[32:31], i_codword[29:0] };
assign w_new_err = ((w_accept)
&&(i_codword[35:33] != 3'h3)
&&(i_codword[35:30] != 6'h2e));
 
reg [2:0] wb_state;
reg [9:0] r_acks_needed, r_len;
reg r_inc, r_new_addr, last_read_request, last_ack, zero_acks;
reg single_read_request;
 
initial r_new_addr = 1'b1;
initial wb_state = `WB_IDLE;
initial o_stb = 1'b0;
always @(posedge i_clk)
if (i_rst)
begin
wb_state <= `WB_IDLE;
o_stb <= 1'b1;
o_codword <= { 6'h3, i_wb_data[29:0] }; // BUS Reset
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
end else case(wb_state)
`WB_IDLE: begin
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
// Now output codewords while we're idle,
// ... unless we get an address command (later).
o_stb <= 1'b0;
 
// The new instruction. The following
// don't matter if we're not running,
// so set them any time in this state,
// and if we move then they'll still be
// set right.
//
// Increment addresses?
r_inc <= i_codword[30];
// Will this be a write?
o_wb_we <= (~i_codword[35]);
//
// Our next codeword will be the new address (if there
// is one). Set it here. The o_stb line will determine
// if this codeword is actually sent out.
//
o_codword <= { 4'h2, o_wb_addr };
o_wb_we <= (i_codword[35:34] != 2'b11);
//
// The output data is a don't care, unless we are
// starting a write. Hence, let's always set it as
// though we were about to start a write.
//
o_wb_data <= w_cod_data;
//
if (i_stb)
begin
// Default is not to send any codewords
// Do we need to broadcast a new address?
// r_new_addr <= 1'b0;
//
casez(i_codword[35:32])
4'b0000: begin // Set a new (arbitrary) address
// r_new_addr <= 1'b1;
o_wb_addr <= i_codword[31:0]; //w_cod_data
end
4'b001?: begin // Set a new relative address
// r_new_addr <= 1'b1;
o_wb_addr <= o_wb_addr // + w_cod_data;
 
+ { i_codword[32:31], i_codword[29:0] };
end
4'b01??: begin // Start a write transaction,
// address is alrdy set
// r_new_addr <= 1'b1;
wb_state <= `WB_WRITE_REQUEST;
o_wb_cyc <= 1'b1;
o_wb_stb <= 1'b1;
end
4'b11??: begin // Start a vector read
// Address is already set ...
// This also depends upon the decoder working
if (r_new_addr)
o_stb <= 1'b1;
wb_state <= `WB_READ_REQUEST;
o_wb_cyc <= 1'b1;
o_wb_stb <= 1'b1;
end
default:
;
endcase
end end
`WB_READ_REQUEST: begin
o_wb_cyc <= 1'b1;
o_wb_stb <= 1'b1;
 
if (i_wb_err)
wb_state <= `WB_IDLE;
 
o_stb <= (i_wb_err)||(i_wb_ack);
 
if (i_wb_err) // Bus Error
o_codword <= { 6'h5, i_wb_data[29:0] };
else // Read data on ack
o_codword <= { 3'h7, i_wb_data[31:30], r_inc,
i_wb_data[29:0] };
 
if ((r_inc)&&(~i_wb_stall))
o_wb_addr <= o_wb_addr + 32'h001;
 
 
if (~i_wb_stall) // Deal with the strobe line
begin // Strobe was accepted, busy should be '1' here
if ((single_read_request)||(last_read_request)) // (r_len != 0) // read
begin
wb_state <= `WB_ACK;
o_wb_stb <= 1'b0;
end
end end
`WB_WRITE_REQUEST: begin
o_wb_cyc <= 1'b1;
o_wb_stb <= 1'b1;
//
 
if (i_wb_err) // Bus Err
o_codword <= { 6'h5, i_wb_data[29:0] };
else // Write acknowledgement
o_codword <= { 6'h2, i_wb_data[29:0] };
 
if ((r_inc)&&(~i_wb_stall))
o_wb_addr <= o_wb_addr + 32'h001;
 
o_stb <= (i_wb_err)||(~i_wb_stall);
 
// Don't need to worry about accepting anything new
// here, since we'll always be busy while in this state.
// Hence, we cannot accept new write requests.
//
 
if (i_wb_err)
begin
wb_state <= `WB_FLUSH_WRITE_REQUESTS;
//
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
end else if (~i_wb_stall)
begin
wb_state <= `WB_WAIT_ON_NEXT_WRITE;
o_wb_stb <= 1'b0;
end end
`WB_ACK: begin
o_wb_cyc <= 1'b1;
o_wb_stb <= 1'b0;
//
// No strobes are being sent out. No further
// bus transactions are requested. We only need
// to finish processing the last one(s) by waiting
// for (and recording?) their acks.
//
// Process acknowledgements
if (i_wb_err) // Bus error
o_codword <= { 6'h5, i_wb_data[29:0] };
else // Read data
o_codword <= { 3'h7, i_wb_data[31:30], r_inc,
i_wb_data[29:0] };
 
// Return a read result, or (possibly) an error
// notification
o_stb <= (((i_wb_ack)&&(~o_wb_we)) || (i_wb_err));
 
if (((last_ack)&&(i_wb_ack))||(zero_acks)||(i_wb_err))
begin
o_wb_cyc <= 1'b0;
wb_state <= `WB_IDLE;
end end
`WB_WAIT_ON_NEXT_WRITE: begin
 
o_codword <= { 6'h5, i_wb_data[29:0] };
o_stb <= (i_wb_err)||(w_new_err);
 
o_wb_data <= w_cod_data;
o_wb_cyc <= 1'b1;
o_wb_stb <= 1'b0;
 
if (w_new_err) // Something other than a write or EOW
begin
o_wb_cyc <= 1'b0;
wb_state <= `WB_IDLE;
end else if (i_wb_err) // Bus returns an error
begin
o_wb_cyc <= 1'b0;
wb_state <= `WB_FLUSH_WRITE_REQUESTS;
end
else if (w_newwr) // Need to make a new write request
begin
wb_state <= `WB_WRITE_REQUEST;
o_wb_stb <= 1'b1;
end
else if (w_eow) // All done writing, wait for last ack
wb_state <= `WB_ACK;
end
`WB_FLUSH_WRITE_REQUESTS: begin
// We come in here after an error within a write
// We need to wait until the command cycle finishes
// issuing all its write commands before we can go back
// to idle.
//
// In the off chance that we are in here in error, or
// out of sync, we'll transition to WB_IDLE and just
// issue a second error token.
 
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
o_codword <= { 6'h5, i_wb_data[29:0] };
o_stb <= (w_new_err);
 
if ((w_eow)||(w_new_err))
wb_state <= `WB_IDLE;
end
default: begin
o_stb <= 1'b1;
o_codword <= { 6'h3, i_wb_data[29:0] };
wb_state <= `WB_IDLE;
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
end
endcase
 
assign o_busy = (wb_state != `WB_IDLE)
&&(wb_state != `WB_WAIT_ON_NEXT_WRITE)
&&(wb_state != `WB_FLUSH_WRITE_REQUESTS);
//assign o_wb_cyc = (wb_state == `WB_READ_REQUEST)
//||(wb_state == `WB_WRITE_REQUEST)
//||(wb_state == `WB_ACK)
//||(wb_state == `WB_WAIT_ON_NEXT_WRITE);
//assign o_wb_stb = (wb_state == `WB_READ_REQUEST)
// ||(wb_state == `WB_WRITE_REQUEST);
 
always @(posedge i_clk)
if (i_rst)
r_new_addr <= 1'b1;
else if ((~o_wb_cyc)&&(i_stb)&&(~i_codword[35]))
r_new_addr <= 1'b1;
else if (o_wb_cyc)
r_new_addr <= 1'b0;
 
always @(posedge i_clk)
if (~o_wb_cyc)
r_acks_needed <= 10'h00; // (i_codword[35])?i_codword[9:0]:10'h00;
else if ((o_wb_stb)&&(~i_wb_stall)&&(~i_wb_ack))
r_acks_needed <= r_acks_needed + 10'h01;
else if (((~o_wb_stb)||(i_wb_stall))&&(i_wb_ack))
r_acks_needed <= r_acks_needed - 10'h01;
 
always @(posedge i_clk)
last_ack <= (~o_wb_stb)&&(r_acks_needed == 10'h01)
||(o_wb_stb)&&(r_acks_needed == 10'h00);
 
always @(posedge i_clk)
zero_acks <= (~o_wb_stb)&&(r_acks_needed == 10'h00);
 
always @(posedge i_clk)
if (~o_wb_stb) // (~o_wb_cyc)&&(i_codword[35:34] == 2'b11))
r_len <= i_codword[9:0];
else if ((o_wb_stb)&&(~i_wb_stall)&&(|r_len))
r_len <= r_len - 10'h01;
 
always @(posedge i_clk)
begin
single_read_request <= (~o_wb_cyc)&&(i_codword[9:0] == 10'h01);
// When there is one read request left, it will be the last one
// will be the last one
last_read_request <= (o_wb_stb)&&(r_len[9:2] == 8'h00)
&&((~r_len[1])
||((~r_len[0])&&(~i_wb_stall)));
end
 
/*
reg [5:0] count;
always @(posedge i_clk)
if (~o_wb_cyc)
count <= 0;
else
count <= count+1;
assign o_dbg = (count > 6'd10);
*/
// assign o_dbg = (wb_state == `WB_ACK);
 
endmodule
/rtl/wbudeword.v
0,0 → 1,96
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wbudeword.v
//
// Project: FPGA library
//
// Purpose: Once a word has come from the bus, undergone compression, had
// idle cycles and interrupts placed in it, this routine converts
// that word form a 36-bit single word into a series of 6-bit words
// that can head to the output routine. Hence, it 'deword's the value:
// unencoding the 36-bit word encoding.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
module wbudeword(i_clk, i_stb, i_word, i_tx_busy, o_stb, o_nl_hexbits, o_busy);
input i_clk, i_stb;
input [35:0] i_word;
input i_tx_busy;
output reg o_stb;
output reg [6:0] o_nl_hexbits;
output reg o_busy;
 
 
wire [2:0] w_len;
assign w_len = (i_word[35:33]==3'b000)? 3'b001
: (i_word[35:32]==4'h2)? 3'b110
: (i_word[35:32]==4'h3)? (3'b010+{1'b0,i_word[31:30]})
: (i_word[35:34]==2'b01)? 3'b010
: (i_word[35:34]==2'b10)? 3'b001
: 3'b110;
 
reg r_dly;
reg [2:0] r_len;
reg [29:0] r_word;
initial o_stb = 1'b0;
initial o_busy = 1'b0;
initial r_dly = 1'b0;
always @(posedge i_clk)
if ((i_stb)&&(~o_busy)) // Only accept when not busy
begin
r_len <= w_len-3'b001;
r_word <= i_word[29:0];
o_stb <= 1'b1;
o_nl_hexbits <= { 1'b0, i_word[35:30] }; // No newline ... yet
o_busy <= 1'b1;
r_dly <= 1'b1;
end else if ((o_stb)&&(i_tx_busy))
begin
o_busy <= 1'b1; // wait and do nothing
r_dly <= 1'b1;
end else if (o_stb) // and (~i_tx_busy) means ours was accepted
o_stb <= 1'b0; // Delay one clock
else if (r_len > 0)
begin
o_stb <= 1'b1;
o_nl_hexbits <= { 1'b0, r_word[29:24] };
r_word[29:6] <= r_word[23:0];
r_len <= r_len - 3'b001;
o_busy <= 1'b1; // wait and do nothing
r_dly <= 1'b1;
end else if (~o_nl_hexbits[6])
begin
o_stb <= 1'b1;
o_nl_hexbits <= 7'h40;
o_busy <= 1'b1; // wait and do nothing
r_dly <= 1'b1;
end else begin
r_dly <= 1'b0;
o_busy <= (r_dly);
end
 
endmodule
 
/rtl/wbutohex.v
0,0 → 1,78
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wbutohex.v
//
// Project: FPGA library
//
// Purpose: Supports a printable character conversion from a printable
// ASCII character to six bits of valid data. The encoding is
// as follows:
//
// 0-9 -> 0-9
// A-Z -> 10-35
// a-z -> 36-61
// @ -> 62
// % -> 63
//
// Note that decoding is stateless, yet requires one clock.
//
//
// 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 wbutohex(i_clk, i_stb, i_byte, o_stb, o_valid, o_hexbits);
input i_clk, i_stb;
input [7:0] i_byte;
output reg o_stb, o_valid;
output reg [5:0] o_hexbits;
 
always @(posedge i_clk)
o_stb <= i_stb;
 
always @(posedge i_clk)
begin
// These are the defaults, to be overwridden by the ifs below
o_valid <= 1'b1;
o_hexbits <= 6'h00;
 
if ((i_byte >= 8'h30)&&(i_byte <= 8'h39)) // A digit
o_hexbits <= { 2'b0, i_byte[3:0] };
else if ((i_byte >= 8'h41)&&(i_byte <= 8'h5a)) // Upper case
o_hexbits <= (i_byte[5:0] - 6'h01 + 6'h0a);// -'A'+10
else if ((i_byte >= 8'h61)&&(i_byte <= 8'h7a))
o_hexbits <= (i_byte[5:0] +6'h03); // -'a'+(10+26)
else if (i_byte == 8'h40) // An '@' sign
o_hexbits <= 6'h3e;
else if (i_byte == 8'h25) // A '%' sign
o_hexbits <= 6'h3f;
else
o_valid <= 1'b0;
end
endmodule
 
/rtl/gpsclock.v
0,0 → 1,505
////////////////////////////////////////////////////////////////////////////////
//
// Filename: gpsclock.v
//
// Project: A GPS Schooled Clock Core
//
// Purpose: The purpose of this module is to school a counter, run off of
// the FPGA's local oscillator, to match a GPS 1PPS signal. Should
// the GPS 1PPS vanish, the result will flywheel with its last
// solution (both frequency and phase) until GPS is available
// again.
//
// This approach can be used to measure the speed of the
// local oscillator, although there may be other more appropriate
// means to do this.
//
// Note that this core does not produce anything more than
// subsecond timing resolution.
//
// Parameters: This core needs two parameters set below, the DEFAULT_STEP
// and the DEFAULT_WORD_STEP. The first must be set to
// 2^RW / (nominal local clock rate), whereas the second must be
// set to 2^(RW/2) / (nominal clock rate), where RW is the register
// width used for our computations. (64 is sufficient for up to
// 4 GHz clock speeds, 56 is minimum for 100 MHz.) Although
// RW is listed as a variable parameter, I have no plans to
// test values other than 64. So your mileage might vary there.
//
// Other parameters, alpha, beta, and gamma are specific to the
// loop bandwidth you would like to choose. Please see the
// accompanying specification for a selection of what values
// may be useful.
//
// Inputs:
// i_clk A synchronous clock signal for all logic. Must be slow enough
// that the FPGA can accomplish 64 bit math.
//
// i_rst Resets the clock speed / counter step to be the nominal
// value given by our parameter. This is useful in case the
// control loop has gone off into never never land and doesn't
// seem to be returning.
//
// i_pps The 1PPS signal from the GPS chip.
//
// Wishbone bus
//
// Outputs:
// o_led No circuit would be complete without a properly blinking LED.
// This one blinks an LED at the top of the GPS 1PPS and the
// internal 1PPS. When the two match, the LED will be on for
// 1/16th of a second. When no GPS 1PPS is present, the LED
// will blink with a 50% duty cycle.
//
// o_tracking A boolean value indicating whether the control loop
// is open (0) or closed (1). Does not indicate performance.
//
// o_count A counter, from zero to 2^RW-1, indicating the position
// of the current clock within a second. (This'll be off by
// two clocks due to internal latencies.)
//
// o_step The amount the counter, o_count, is stepped each clock.
// This is related to the actual speed of the oscillator (when
// locked) by f_XO = 2^(RW) / o_step.
//
// o_err For those interested in how well this device is performing,
// this is the error signal coming out of the device.
//
// o_locked Indicates a locked condition. While it should work,
// it isn't the best and most versatile lock indicator. A better
// indicator should be based upon how good the user wants the
// lock indicator to be. This isn't that.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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 gpsclock(i_clk, i_rst, i_pps, o_pps, o_led,
i_wb_cyc_stb, i_wb_we, i_wb_addr, i_wb_data,
o_wb_ack, o_wb_stall, o_wb_data,
o_tracking, o_count, o_step, o_err, o_locked, o_dbg);
parameter RW=64, // Needs to be 2ceil(Log_2(i_clk frequency))
DW=32, // The width of our data bus
ONE_SECOND = 0,
NPW=RW-DW, // Width of non-parameter data
HRW=RW/2; // Half of RW
input i_clk, i_rst;
input i_pps; // From the GPS device
output reg o_pps; // To our local circuitry
output reg o_led; // A blinky light showing how well we're doing
// Wishbone Configuration interface
input i_wb_cyc_stb, i_wb_we;
input [1:0] i_wb_addr;
input [(DW-1):0] i_wb_data;
output reg o_wb_ack;
output wire o_wb_stall;
output reg [(DW-1):0] o_wb_data;
// Status and timing outputs
output reg o_tracking; // 1=closed loop, 0=open
output reg [(RW-1):0] o_count, // Fraction of a second
o_step, // 2^RW / clock speed (in Hz)
o_err; // Fraction of a second err
output reg o_locked; // 1 if Locked, 0 o.w.
output wire [1:0] o_dbg;
 
 
// Clock resynchronization variables
reg pps_d, ck_pps, lst_pps;
wire tick; // And a variable indicating the top of GPS 1PPS
 
//
// Configuration variables. These control the loop bandwidth, the speed
// of convergence, the speed of adaptation to changes, and more. If
// you adjust these outside of what the specification recommends,
// be careful that the control loop still synchronizes!
reg new_config;
reg [5:0] r_alpha;
reg [(DW-1):0] r_beta, r_gamma, r_def_step;
reg [(RW-1):0] pre_step;
 
//
// This core really operates rather slowly, in FPGA time. Of the
// millions of ticks per second, we only do things on about less than
// a handful. These timing signals below help us to determine when
// our data is valid during those handful.
//
// Timing
reg err_tick, mpy_aux, mpy_sync_two, delay_step_clk;
wire sub_tick, fltr_tick;
 
//
// When tracking, each second we'll produce a lowpass filtered_err
// (via a recursive average), a count_correction and a step_correction.
// The two _correction terms then get applied at the top of the second.
// Here's the declaration of those parameters. The
// 'pre_count_correction' parameter allows us to avoid adding three
// 64-bit numbers in a single clock, splitting part of that amount into
// an earlier clock.
//
// Tracking
reg [(RW-1):0] count_correction, pre_count_correction;
reg [(HRW-1):0] step_correction;
reg [(HRW-1):0] delayed_step_correction, delayed_step;
reg signed [(HRW-1):0] mpy_input;
wire [(RW-1):0] w_mpy_out;
wire signed [(RW-1):0] filter_sub_count, filtered_err;
 
 
 
//
//
//
// Wishbone access ... adjust our tracking parameters
//
//
//
// DEFAULT_STEP = 64'h0000_002a_f31d_c461, // 2^64 / 100 MHz
initial r_def_step = 32'h8_2af_31dc;
always @(posedge i_clk)
pre_step <= { 16'h00,
(({ r_def_step[27:0], 20'h00 })>>r_def_step[31:28])};
 
initial new_config = 1'b0;
always @(posedge i_clk)
if ((i_wb_cyc_stb)&&(i_wb_we))
begin
new_config = 1'b1;
case(i_wb_addr)
2'b00: r_alpha <= i_wb_data[5:0];
2'b01: r_beta <= i_wb_data;
2'b10: r_gamma <= i_wb_data;
2'b11: r_def_step <= i_wb_data;
default: begin end
// r_defstep <= i_wb_data;
endcase
end else
new_config = 1'b0;
always @(posedge i_clk)
case (i_wb_addr)
2'b00: o_wb_data <= { 26'h00, r_alpha };
2'b01: o_wb_data <= r_beta;
2'b10: o_wb_data <= r_gamma;
2'b11: o_wb_data <= r_def_step;
default: o_wb_data <= 0;
endcase
 
reg dly_config;
initial dly_config = 1'b0;
always @(posedge i_clk)
dly_config <= new_config;
always @(posedge i_clk)
o_wb_ack <= i_wb_cyc_stb;
assign o_wb_stall = 1'b0;
 
//
//
// Deal with the realities of an unsynchronized 1PPS signal:
// register it with two flip flops to avoid metastability issues.
// Create a 'tick' variable to note the top of a second.
//
//
always @(posedge i_clk)
begin
pps_d <= i_pps;
ck_pps <= pps_d;
lst_pps <= ck_pps;
end
 
// Provide a touch of debounce protection ... equal to about
// one quarter of a second.
reg [(RW-3):0] tick_enable_counter;
wire [(RW-1):0] w_tick_enable_sum;
wire w_tick_enable, w_tick_enable_unused;
bigadd enabler(i_clk, 1'b0, o_step, { 2'b0, tick_enable_counter },
w_tick_enable_sum, w_tick_enable_unused);
initial tick_enable_counter = 0;
always @(posedge i_clk)
begin
if (tick)
tick_enable_counter <= 0;
else if (|w_tick_enable_sum[(RW-1):(RW-2)])
tick_enable_counter <= {(RW-2){1'b1}};
else
tick_enable_counter <= w_tick_enable_sum[(RW-3):0];
end
assign w_tick_enable = tick_enable_counter[(RW-3)];
 
assign tick= (ck_pps)&&(~lst_pps)&&(w_tick_enable);
assign o_dbg[0] = tick;
assign o_dbg[1] = w_tick_enable;
 
//
//
// Here's our counter proper: Add o_step to o_count each clock tick
// to have a current time value. Corrections are applied at the top
// of the second if we are in tracking mode. The 'o_pps' signal is
// generated from the carry/overflow of the o_count addition.
//
//
reg cnt_carry;
reg [31:0] p_count;
initial o_count = 0;
initial o_pps = 1'b0;
always @(posedge i_clk)
if ((o_tracking)&&(tick))
begin
{ cnt_carry, p_count } <= p_count[31:0] + count_correction[31:0];
if (~count_correction[(RW-1)])
begin
// Note that we don't create an o_pps just
// because the gps_pps states that there should
// be one. Instead, we hold to the normal
// means of business. At the tick, however,
// we add both the step and the correction to
// the current count.
{ o_pps, o_count[63:32] } <= o_count[63:32] +count_correction[63:32]+ { 31'h00, cnt_carry };
end else begin
// If the count correction is negative, it means
// we need to go backwards. In this case,
// there shouldn't be any o_pps, least we get
// two of them.
o_pps <= 1'b0;
o_count[63:32] <= o_count[63:32] + count_correction[63:32];
end
end else begin
// The difference between count_correction and
// o_step is the phase correction from the last tick.
// If we aren't tracking, we don't want to use the
// correction. Likewise, even if we are, we only
// want to use it on the ticks.
{ cnt_carry, p_count } <= p_count + o_step[31:0];
{ o_pps, o_count[63:32] } <= o_count[63:32] + o_step[63:32];
end
always @(posedge i_clk)
o_count[31:0] <= p_count;
 
reg [(HRW):0] step_correction_plus_carry;
always @(posedge i_clk)
step_correction_plus_carry = step_correction + { 31'h00, delayed_carry };
 
wire w_step_correct_unused;
wire [(RW-1):0] new_step;
bigadd getnewstep(i_clk, 1'b0, o_step,
{ { (HRW-1){step_correction_plus_carry[HRW]} },
step_correction_plus_carry},
new_step, w_step_correct_unused);
 
reg delayed_carry;
initial delayed_carry = 0;
initial o_step = 64'h002af31dc461;
always @(posedge i_clk)
if ((i_rst)||(dly_config))
o_step <= pre_step;
else if ((o_tracking) && (tick))
o_step <= new_step;
 
initial delayed_step = 0;
always @(posedge i_clk)
if ((i_rst)||(dly_config))
delayed_step <= 0;
else if (delay_step_clk)
{ delayed_carry, delayed_step } <= delayed_step
+ delayed_step_correction;
 
 
//
//
// Now to start our tracking loop. The steps are:
// 1. Measure our error
// 2. Filter our error (lowpass, recursive averager)
// 3. Multiply the filtered error by two user-supplied constants
// (beta and gamma)
// 4. The results of this multiply then become the new
// count and step corrections.
//
//
// A negative error means we were too fast ... the count rolled over
// and is near zero, the o_err is then the negation of this when the
// tick does show up.
//
initial o_err = 0;
always @(posedge i_clk)
if (tick)
o_err <= ONE_SECOND - o_count;
 
initial err_tick = 1'b0;
always @(posedge i_clk)
err_tick <= tick;
 
bigsub suberri(i_clk, err_tick, o_err,
filtered_err, filter_sub_count, sub_tick);
 
//
// This shouldn't be required: We only want to shift our
// filter_sub_count by r_alpha bits, why the extra struggles?
// Why is because Verilator decides that these values are unsigned,
// and so despite being told that they are signed values, verilator
// doesn't sign extend them upon shifting. Put together,
// { shift_hi[low-bits], shift_lo[low-bits] } make up a full RW
// bit correction factor.
reg signed [(RW-1):0] shift_hi, shift_lo;
always @(posedge i_clk)
begin
shift_hi <= { {(HRW){filter_sub_count[(RW-1)]}},
filter_sub_count[(RW-1):HRW] }>>r_alpha;
shift_lo <= filter_sub_count[(RW-1):0]>>r_alpha;
end
 
bigadd adderr(i_clk, sub_tick, filtered_err,
{ shift_hi[(HRW-1):0], shift_lo[(HRW-1):0] },
filtered_err, fltr_tick);
/*
always @(posedge i_clk)
if ((o_tracking)&&(sub_tick))
filtered_err<= filtered_err
+ { shift_hi[(HRW-1):0], shift_lo[(HRW-1):0] };
*/
 
always @(posedge i_clk)
if (fltr_tick)
mpy_input <= r_beta;
else
mpy_input <= r_gamma;
always @(posedge i_clk)
mpy_aux <= fltr_tick;
 
//
// The multiply
//
wire mpy_sync;
wire [(RW-1):0] mpy_out;
initial mpy_sync_two = 1'b0;
// Sign extend all inputs to RW bits
wire signed [(RW-1):0] w_mpy_input, w_mpy_err;
assign w_mpy_input = { {(RW-DW){mpy_input[(DW-1)]}}, mpy_input[(DW-1):0]};
assign w_mpy_err = { {(RW-NPW){filtered_err[(RW-1)]}}, filtered_err[(RW-1):(RW-NPW)]};
bigsmpy mpyi(i_clk, mpy_aux, 1'b1, w_mpy_input[31:0], w_mpy_err[31:0],
mpy_out, mpy_sync);
always @(posedge i_clk)
mpy_sync_two <= mpy_sync;
assign w_mpy_out = mpy_out;
 
// The post-multiply
initial pre_count_correction = 0;
initial step_correction = 0;
initial delayed_step_correction = 0;
always @(posedge i_clk)
if (mpy_sync)
pre_count_correction <= w_mpy_out;
else if (mpy_sync_two) begin
step_correction <= w_mpy_out[(RW-1):HRW];
delayed_step_correction <= w_mpy_out[(HRW-1):0];
end
always @(posedge i_clk)
count_correction <= pre_count_correction + o_step;
 
initial delay_step_clk = 1'b0;
always @(posedge i_clk)
delay_step_clk <= mpy_sync_two;
 
//
//
// LED Logic -- Note that this is where we tell if we've had a GPS
// 1PPS pulse or not. To have had such a pulse, it needs to have
// been within the last two seconds.
//
//
reg no_pulse;
reg [32:0] time_since_pps;
initial no_pulse = 1'b1;
initial time_since_pps = 33'hffffffff;
always @(posedge i_clk)
if (tick)
begin
time_since_pps <= 0;
no_pulse <= 0;
end else if (time_since_pps[32:29] == 4'hf)
begin
time_since_pps <= 33'hffffffff;
no_pulse <= 1'b1;
end else
time_since_pps <= time_since_pps + pre_step[(RW-1):HRW];
 
//
// 1. Pulse with a 50% duty cycle every second if no GPS is available.
// 2. Pulse with a 6% duty cycle any time a pulse is present, and any
// time we think (when a pulse is present) that we have time.
//
// This should produce a set of conflicting pulses when out of lock,
// and a nice short once per second pulse when locked. Further, you
// should be able to tell when the core is flywheeling by the duration
// of the pulses (50% vs 6%).
//
always @(posedge i_clk)
if (no_pulse)
o_led <= o_count[(RW-1)];
else
o_led <= ((time_since_pps[31:28] == 4'h0)
||(o_count[(RW-1):(RW-4)]== 4'h0));
 
//
//
// Now, are we tracking or not?
// We'll attempt to close the loop after seeing 7 valid GPS 1PPS
// rising edges.
//
//
reg [2:0] count_valid_ticks;
initial count_valid_ticks = 3'h0;
always @(posedge i_clk)
if ((tick)&&(count_valid_ticks < 3'h7))
count_valid_ticks <= count_valid_ticks+1;
else if (no_pulse)
count_valid_ticks <= 3'h0;
initial o_tracking = 1'b0;
always @(posedge i_clk)
if ((tick)&&(&count_valid_ticks))
o_tracking <= 1'b1;
else if ((tick)||(count_valid_ticks == 0))
o_tracking <= 1'b0;
 
//
//
// Are we locked or not?
// We'll use the top eight bits of our error to tell. If the top eight
// bits are all ones or all zeros, then we'll call ourselves locked.
// This is equivalent to calling ourselves locked if, at the top of
// the second, we are within 1/128th of a second of the GPS 1PPS.
//
initial o_locked = 1'b0;
always @(posedge i_clk)
if ((o_tracking)&&(tick)&&(
(( o_err[(RW-1)])&&(o_err[(RW-1):(RW-8)]==8'hff))
||((~o_err[(RW-1)])&&(o_err[(RW-1):(RW-8)]==8'h00))))
o_locked <= 1'b1;
else if (tick)
o_locked <= 1'b0;
 
endmodule
 
/rtl/wbubus.v
0,0 → 1,138
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wbubus.v
//
// Project: FPGA library
//
// Purpose: This is the top level file for the entire JTAG-USB to Wishbone
// bus conversion. (It's also the place to start debugging, should
// things not go as planned.) Bytes come into this routine, bytes go out,
// and the wishbone bus (external to this routine) is commanded in between.
//
//
//
// 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.
//
// 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;
// output wire o_dbg;
 
 
reg r_wdt_reset;
 
// Decode ASCII input requests into WB bus cycle requests
wire in_stb;
wire [35:0] in_word;
wbuinput getinput(i_clk, i_rx_stb, i_rx_data, in_stb, in_word);
 
wire w_bus_busy, fifo_in_stb, exec_stb, w_bus_reset;
wire [35:0] fifo_in_word, exec_word;
// `define NO_INPUT_FIFO
`ifdef NO_INPUT_FIFO
assign fifo_in_stb = in_stb;
assign fifo_in_word = in_word;
assign w_bus_reset = 1'b0;
`else
wire ififo_empty_n, ififo_err;
assign fifo_in_stb = (~w_bus_busy)&&(ififo_empty_n);
assign w_bus_reset = r_wdt_reset;
wbufifo #(36,6) padififo(i_clk, w_bus_reset,
in_stb, in_word, fifo_in_stb, fifo_in_word,
ififo_empty_n, ififo_err);
`endif
 
// assign o_dbg = (i_wb_ack)&&(i_wb_cyc);
 
// Take requests in, Run the bus, send results out
// This only works if no requests come in while requests
// are pending.
wbuexec runwb(i_clk, r_wdt_reset, fifo_in_stb, fifo_in_word, w_bus_busy,
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,
exec_stb, exec_word);
 
/*
wire [31:0] cyc_debug;
assign cyc_debug = { 1'b0, o_wb_cyc, o_wb_stb, o_wb_we, i_wb_ack, i_wb_stall,
(i_wb_err||r_wdt_reset), o_wb_addr[14:0],
o_wb_data[4:0], i_wb_data[4:0] };
assign o_dbg = cyc_debug;
*/
/*
wire [31:0] fif_debug;
assign fif_debug = {
(exec_stb)&&(exec_word[35:30] == 6'h05),// 1
fifo_in_stb, fifo_in_word[35:30], // 7
exec_stb, exec_word[35:30], // 7
o_wb_cyc, o_wb_stb, o_wb_we,
i_wb_ack, i_wb_stall, // 5
w_bus_busy, ififo_empty_n, w_bus_reset, // 3
i_rx_stb, o_wb_addr[7:0] }; // 9
assign o_dbg = fif_debug;
*/
wire ofifo_err;
// wire [30:0] out_dbg;
wbuoutput wroutput(i_clk, w_bus_reset,
exec_stb, exec_word,
o_wb_cyc, i_interrupt, exec_stb,
o_tx_stb, o_tx_data, i_tx_busy, ofifo_err);
 
// Add in a watchdog timer to the bus
reg [(LGWATCHDOG-1):0] r_wdt_timer;
initial r_wdt_reset = 1'b0;
initial r_wdt_timer = 0;
always @(posedge i_clk)
if ((~o_wb_cyc)||(i_wb_ack))
begin
r_wdt_timer <= 0;
r_wdt_reset <= 1'b0;
end else if (&r_wdt_timer)
begin
r_wdt_reset <= 1'b1;
r_wdt_timer <= 0;
end else begin
r_wdt_timer <= r_wdt_timer+{{(LGWATCHDOG-1){1'b0}},1'b1};
r_wdt_reset <= 1'b0;
end
 
endmodule
 
/rtl/Makefile
0,0 → 1,96
##########################################################################/
##
## Filename: Makefile
##
## Project: OpenArty, an entirely open SoC based upon the Arty platform
##
## Purpose: To direct the Verilator build of the SoC sources. The result
## is C++ code (built by Verilator), that is then built (herein)
## into a library.
##
##
## Creator: Dan Gisselquist, Ph.D.
## Gisselquist Technology, LLC
##
##########################################################################/
##
## Copyright (C) 2015, 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.
##
## License: GPL, v3, as defined and found on www.gnu.org,
## http:##www.gnu.org/licenses/gpl.html
##
##
##########################################################################/
##
##
all: test
YYMMDD=`date +%Y%m%d`
CXX := g++
FBDIR := .
VDIRFB:= $(FBDIR)/obj_dir
 
.PHONY: test
test: $(VDIRFB)/Veqspiflash__ALL.a
test: $(VDIRFB)/Venetctrl__ALL.a
test: $(VDIRFB)/Vfastmaster__ALL.a
# test: $(VDIRFB)/Vfastmaster__ALL.a
 
CPUDR := cpu
CPUSOURCESnD := zipcpu.v fastops.v pfcache.v pipemem.v \
pfcache.v ifastdec.v wbpriarbiter.v zipbones.v \
zipsystem.v zipcounter.v zipjiffies.v ziptimer.v \
wbdmac.v icontrol.v wbwatchdog.v
CPUSOURCES := $(addprefix $(CPUDR)/,$(CPUSOURCESnD))
 
JTAGBUS := wbufifo.v wbubus.v wbucompactlines.v \
wbucompress.v wbudecompress.v wbudeword.v wbuexec.v \
wbuidleint.v wbuinput.v wbuoutput.v wbureadcw.v wbusixchar.v \
wbutohex.v
PERIPHERALS:= enetctrl.v fastio.v icontrol.v rtcdate.v rtcgps.v \
rxuart.v txuart.v eqspiflash.v llqspi.v flash_config.v \
wbicapetwo.v sdspi.v gpsclock_tb.v gpsclock.v wboled.v lloled.v \
wbscopc.v wbscope.v memdev.v wbddrsdram.v
BIGMATH:= bigadd.v bigsmpy.v bigsub.v
SOURCES := fastmaster.v builddate.v \
$(CPUSOURCES) $(JTAGBUS) $(PERIPHERALS) $(BIGMATH)
SLOWSRC := busmaster.v builddate.v \
$(CPUSOURCES) $(JTAGBUS) $(PERIPHERALS) $(BIGMATH)
 
$(VDIRFB)/Vfastmaster__ALL.a: $(VDIRFB)/Vfastmaster.h $(VDIRFB)/Vfastmaster.cpp
$(VDIRFB)/Vfastmaster__ALL.a: $(VDIRFB)/Vfastmaster.mk
$(VDIRFB)/Vfastmaster.h $(VDIRFB)/Vfastmaster.cpp $(VDIRFB)/Vfastmaster.mk: $(SOURCES)
 
$(VDIRFB)/Vbusmaster__ALL.a: $(VDIRFB)/Vbusmaster.h $(VDIRFB)/Vbusmaster.cpp
$(VDIRFB)/Vbusmaster__ALL.a: $(VDIRFB)/Vbusmaster.mk
$(VDIRFB)/Vbusmaster.h $(VDIRFB)/Vbusmaster.cpp $(VDIRFB)/Vbusmaster.mk: $(SLOWSRC)
 
$(VDIRFB)/Venetctrl.h $(VDIRFB)/Venetctrl.cpp $(VDIRFB)/Venetctrl.mk: enetctrl.v
$(VDIRFB)/Veqspiflash.h $(VDIRFB)/Veqspiflash.cpp $(VDIRFB)/Veqspiflash.mk: eqspiflash.v llqspi.v
$(VDIRFB)/V%.cpp $(VDIRFB)/V%.h $(VDIRFB)/V%.mk: $(FBDIR)/%.v
verilator -cc -y $(CPUDR) $*.v
 
 
$(VDIRFB)/V%__ALL.a: $(VDIRFB)/V%.mk
cd $(VDIRFB); make -f V$*.mk
 
.PHONY:
archive:
tar --transform s,^,$(YYMMDD)-rtl/, -chjf $(YYMMDD)-rtl.tjz Makefile *.v cpu/*.v
 
.PHONY: clean
clean:
rm -rf $(VDIRFB)/*.mk
rm -rf $(VDIRFB)/*.cpp
rm -rf $(VDIRFB)/*.h
rm -rf $(VDIRFB)/
 
/rtl/fastmaster.v
0,0 → 1,1076
////////////////////////////////////////////////////////////////////////////////
//
// Filename: fastmaster.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: On other projects, this file would be called the "bus
// interconnect". This module connects all the devices on the
// Wishbone bus within this project together. It is created by hand, not
// automatically.
//
// 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
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`define NO_ZIP_WBU_DELAY
// `define ZIPCPU
`ifdef ZIPCPU
//`define ZIP_SYSTEM
`ifndef ZIP_SYSTEM
`define ZIP_BONES
`endif // ZIP_SYSTEM
`endif // ZipCPU
//
//
`define SDCARD_ACCESS
`define ETHERNET_ACCESS
`ifndef VERILATOR
`define ICAPE_ACCESS
`endif
`define FLASH_ACCESS
//`define SDRAM_ACCESS
`define GPS_CLOCK
// UART_ACCESS and GPS_UART have both been placed within fastio
// `define UART_ACCESS
// `define GPS_UART
`define RTC_ACCESS
`define OLEDRGB_ACCESS
//
// `define CPU_SCOPE
// `define GPS_SCOPE
`define FLASH_SCOPE
// `define SDRAM_SCOPE
// `define ENET_SCOPE
//
//
module fastmaster(i_clk, i_rst,
// CNC
i_rx_stb, i_rx_data, o_tx_stb, o_tx_data, i_tx_busy,
// Boad I/O
i_sw, i_btn, o_led,
o_clr_led0, o_clr_led1, o_clr_led2, o_clr_led3,
// PMod I/O
i_aux_rx, o_aux_tx, o_aux_cts, i_gps_rx, o_gps_tx,
// The Quad SPI Flash
o_qspi_cs_n, o_qspi_sck, o_qspi_dat, i_qspi_dat, o_qspi_mod,
// The DDR3 SDRAM
o_ddr_reset_n, o_ddr_cke,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
o_ddr_dqs, o_ddr_addr, o_ddr_ba, o_ddr_data, i_ddr_data,
// The SD Card
o_sd_sck, o_sd_cmd, o_sd_data, i_sd_cmd, i_sd_data, i_sd_detect,
// Ethernet control (MDIO) lines
o_mdclk, o_mdio, o_mdwe, i_mdio,
// OLED Control interface (roughly SPI)
o_oled_sck, o_oled_cs_n, o_oled_mosi, o_oled_dcn,
o_oled_reset_n, o_oled_vccen, o_oled_pmoden,
// The GPS PMod
i_gps_pps, i_gps_3df
);
parameter ZA=24, ZIPINTS=13;
input i_clk, i_rst;
// The bus commander, via an external uart port
input i_rx_stb;
input [7:0] i_rx_data;
output wire o_tx_stb;
output wire [7:0] o_tx_data;
input i_tx_busy;
// I/O to/from board level devices
input [3:0] i_sw; // 16 switch bus
input [3:0] i_btn; // 5 Buttons
output wire [3:0] o_led; // 16 wide LED's
output wire [2:0] o_clr_led0, o_clr_led1, o_clr_led2, o_clr_led3;
// PMod UARTs
input i_aux_rx;
output wire o_aux_tx, o_aux_cts;
input i_gps_rx;
output wire o_gps_tx;
// Quad-SPI flash control
output wire o_qspi_cs_n, o_qspi_sck;
output wire [3:0] o_qspi_dat;
input [3:0] i_qspi_dat;
output wire [1:0] o_qspi_mod;
// DDR3 RAM controller
output wire o_ddr_reset_n, o_ddr_cke,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n,o_ddr_we_n;
output wire [2:0] o_ddr_dqs;
output wire [13:0] o_ddr_addr;
output wire [2:0] o_ddr_ba;
output wire [31:0] o_ddr_data;
input [31:0] i_ddr_data;
// The SD Card
output wire o_sd_sck;
output wire o_sd_cmd;
output wire [3:0] o_sd_data;
input i_sd_cmd;
input [3:0] i_sd_data;
input i_sd_detect;
// Ethernet control (MDIO)
output wire o_mdclk, o_mdio, o_mdwe;
input i_mdio;
// OLEDRGB interface
output wire o_oled_sck, o_oled_cs_n, o_oled_mosi,
o_oled_dcn, o_oled_reset_n, o_oled_vccen,
o_oled_pmoden;
// GPS PMod (GPS UART above)
input i_gps_pps;
input i_gps_3df;
 
//
//
// Master wishbone wires
//
//
wire wb_cyc, wb_stb, wb_we, wb_stall, wb_err;
wire [31:0] wb_data, wb_addr;
reg wb_ack;
reg [31:0] wb_idata;
 
// Interrupts
wire gpio_int, oled_int, flash_int, scop_int;
wire enet_tx_int, enet_rx_int, sdcard_int, rtc_int, rtc_pps,
auxrx_int, auxtx_int, gpsrx_int, sw_int, btn_int;
 
//
//
// First BUS master source: The UART
//
//
wire [31:0] dwb_idata;
 
// Wires going to devices
wire wbu_cyc, wbu_stb, wbu_we;
wire [31:0] wbu_addr, wbu_data;
// and then coming from devices
wire wbu_ack, wbu_stall, wbu_err;
wire [31:0] wbu_idata;
// And then headed back home
wire w_interrupt;
// Oh, and the debug control for the ZIP CPU
wire wbu_zip_sel, zip_dbg_ack, zip_dbg_stall;
wire [31:0] zip_dbg_data;
wbubus genbus(i_clk, i_rx_stb, i_rx_data,
wbu_cyc, wbu_stb, wbu_we, wbu_addr, wbu_data,
(wbu_zip_sel)?zip_dbg_ack:wbu_ack,
(wbu_zip_sel)?zip_dbg_stall:wbu_stall,
wbu_err,
(wbu_zip_sel)?zip_dbg_data:wbu_idata,
w_interrupt,
o_tx_stb, o_tx_data, i_tx_busy);
 
// assign o_dbg = (wbu_ack)&&(wbu_cyc);
 
wire zip_cpu_int; // True if the CPU suddenly halts
`ifdef ZIPCPU
// Are we trying to access the ZipCPU? Such accesses must be special,
// because they must succeed regardless of whether or not the ZipCPU
// is on the bus. Hence, we trap them here.
assign wbu_zip_sel = (wbu_addr[27]);
 
//
//
// Second BUS master source: The ZipCPU
//
//
wire zip_cyc, zip_stb, zip_we;
wire [(ZA-1):0] w_zip_addr;
wire [31:0] zip_data, zip_scope_data;
// and then coming from devices
wire zip_ack, zip_stall, zip_err;
 
`ifdef ZIP_SYSTEM
wire [(ZIPINTS-1):0] zip_interrupt_vec = {
// Lazy(ier) interrupts
oled_int, gpio_int, rtc_int, scop_int, flash_int, sw_int, btn_int,
// Fast interrupts
sdcard_int, auxtx_int, auxrx_int, enet_tx_int, enet_rx_int,
gpsrx_int, rtc_pps
};
 
zipsystem #( .RESET_ADDRESS(24'h08000),
.ADDRESS_WIDTH(ZA),
.LGICACHE(10),
.START_HALTED(1),
.EXTERNAL_INTERRUPTS(ZIPINTS),
.HIGHSPEED_CPU(1))
zippy(i_clk, i_rst,
// Zippys wishbone interface
zip_cyc, zip_stb, zip_we, w_zip_addr, zip_data,
zip_ack, zip_stall, dwb_idata, zip_err,
zip_interrupt_vec, zip_cpu_int,
// Debug wishbone interface
((wbu_cyc)&&(wbu_zip_sel)),
((wbu_stb)&&(wbu_zip_sel)),wbu_we, wbu_addr[0],
wbu_data,
zip_dbg_ack, zip_dbg_stall, zip_dbg_data
`ifdef CPU_DEBUG
, zip_scope_data
`endif
);
`else // ZIP_SYSTEM
wire w_zip_cpu_int_ignored;
zipbones #( .RESET_ADDRESS(24'h08000),
.ADDRESS_WIDTH(ZA),
.LGICACHE(10),
.START_HALTED(1),
.HIGHSPEED_CPU(1))
zippy(i_clk, i_rst,
// Zippys wishbone interface
zip_cyc, zip_stb, zip_we, w_zip_addr, zip_data,
zip_ack, zip_stall, dwb_idata, zip_err,
w_interrupt, w_zip_cpu_int_ignored,
// Debug wishbone interface
((wbu_cyc)&&(wbu_zip_sel)),
((wbu_stb)&&(wbu_zip_sel)),wbu_we, wbu_addr[0],
wbu_data,
zip_dbg_ack, zip_dbg_stall, zip_dbg_data
`ifdef CPU_DEBUG
, zip_scope_data
`endif
);
assign zip_cpu_int = 1'b0;
`endif // ZIP_SYSTEM v ZIP_BONES
 
wire [31:0] zip_addr;
generate
if (ZA < 32)
assign zip_addr = { {(32-ZA){1'b0}}, w_zip_addr};
else
assign zip_addr = w_zip_addr;
endgenerate
 
//
//
// And an arbiter to decide who gets to access the bus
//
//
wire dwb_we, dwb_stb, dwb_cyc, dwb_ack, dwb_stall, dwb_err;
wire [31:0] dwb_addr, dwb_odata;
wbpriarbiter #(32,32) wbu_zip_arbiter(i_clk,
// The ZIP CPU Master -- Gets the priority slot
zip_cyc, zip_stb, zip_we, zip_addr, zip_data,
zip_ack, zip_stall, zip_err,
// The UART interface Master
(wbu_cyc)&&(~wbu_zip_sel), (wbu_stb)&&(~wbu_zip_sel), wbu_we,
wbu_addr, wbu_data,
wbu_ack, wbu_stall, wbu_err,
// Common bus returns
dwb_cyc, dwb_stb, dwb_we, dwb_addr, dwb_odata,
dwb_ack, dwb_stall, dwb_err);
 
//
//
// And because the ZIP CPU and the Arbiter create an unacceptable
// delay, we fail timing. So we add in a delay cycle ...
//
//
assign wbu_idata = dwb_idata;
busdelay wbu_zip_delay(i_clk,
dwb_cyc, dwb_stb, dwb_we, dwb_addr, dwb_odata,
dwb_ack, dwb_stall, dwb_idata, dwb_err,
wb_cyc, wb_stb, wb_we, wb_addr, wb_data,
wb_ack, wb_stall, wb_idata, wb_err);
 
`else // ZIPCPU
assign zip_cpu_int = 1'b0; // No CPU here to halt
assign wbu_zip_sel = 1'b0;
 
// If there's no ZipCPU, there's no need for a Zip/WB-Uart bus delay.
// We can go directly from the WB-Uart master bus to the master bus
// itself.
assign wb_cyc = wbu_cyc;
assign wb_stb = wbu_stb;
assign wb_we = wbu_we;
assign wb_addr = wbu_addr;
assign wb_data = wbu_data;
assign wbu_idata = wb_idata;
assign wbu_ack = wb_ack;
assign wbu_stall = wb_stall;
assign wbu_err = wb_err;
 
// The CPU never halts if it doesn't exist, so set this interrupt to
// zero.
assign zip_cpu_int= 1'b0;
`endif // ZIPCPU
 
 
//
// Peripheral select lines.
//
// These lines will be true during any wishbone cycle whose address
// line selects the given I/O peripheral. The none_sel and many_sel
// lines are used to detect problems, such as when no device is
// selected or many devices are selected. Such problems will lead to
// bus errors (below).
//
wire io_sel, scop_sel, netb_sel,
flctl_sel, rtc_sel, sdcard_sel, netp_sel,
oled_sel, gps_sel, mio_sel, cfg_sel,
mem_sel, flash_sel, ram_sel,
none_sel, many_sel;
 
wire [4:0] skipaddr;
assign skipaddr = { wb_addr[26], wb_addr[22], wb_addr[15], wb_addr[11],
~wb_addr[8] };
assign ram_sel = (skipaddr[4]);
assign flash_sel = (skipaddr[4:3]==2'b01);
assign mem_sel = (skipaddr[4:2]==3'b001);
assign netb_sel = (skipaddr[4:1]==4'b0001);
assign io_sel = (~|skipaddr)&&(wb_addr[7:5]==3'b000);
assign scop_sel = (~|skipaddr)&&(wb_addr[7:3]==5'b00100);
assign rtc_sel = (~|skipaddr)&&(wb_addr[7:2]==6'b001010);
assign sdcard_sel= (~|skipaddr)&&(wb_addr[7:2]==6'b001011);
assign netp_sel = (~|skipaddr)&&(wb_addr[7:2]==6'b001101);
assign oled_sel = (~|skipaddr)&&(wb_addr[7:2]==6'b001110);
assign gps_sel = (~|skipaddr)&&( (wb_addr[7:2]==6'b001100)
|| (wb_addr[7:3]==5'b01000));
assign mio_sel = (~|skipaddr)&&(wb_addr[7:5]==3'b101);
assign flctl_sel = (~|skipaddr)&&(wb_addr[7:5]==3'b110);
assign cfg_sel = (~|skipaddr)&&(wb_addr[7:5]==3'b111);
 
wire skiperr;
assign skiperr = (|wb_addr[31:27])
||(~skipaddr[4])&&(|wb_addr[25:23])
||(skipaddr[4:3]==2'b00)&&(|wb_addr[21:16])
||(skipaddr[4:2]==3'b000)&&(|wb_addr[14:12])
||(skipaddr[4:1]==4'b0000)&&(|wb_addr[10:9]);
 
 
//
// Peripheral acknowledgement lines
//
// These are only a touch more confusing, since the flash device will
// ACK for both flctl_sel (the control line select), as well as the
// flash_sel (the memory line select). Hence we have one fewer ack
// line.
wire io_ack, oled_ack,
rtc_ack, sdcard_ack,
netp_ack, gps_ack, mio_ack, cfg_ack, netb_ack,
mem_ack, flash_ack, ram_ack;
reg many_ack, slow_many_ack;
reg slow_ack, scop_ack;
wire [4:0] ack_list;
assign ack_list = { ram_ack, flash_ack, mem_ack, netb_ack, cfg_ack };
initial many_ack = 1'b0;
always @(posedge i_clk)
many_ack <= ((ack_list != 5'h10)
&&(ack_list != 5'h8)
&&(ack_list != 5'h4)
&&(ack_list != 5'h2)
&&(ack_list != 5'h1)
&&(ack_list != 5'h0));
/*
assign many_ack = ( { 2'h0, ram_ack}
+{2'h0, flash_ack }
+{2'h0, mem_ack }
+{2'h0, netb_ack }
+{2'h0, slow_ack } > 3'h1 );
*/
 
wire [7:0] slow_ack_list;
assign slow_ack_list = { mio_ack, gps_ack, netp_ack,
sdcard_ack, rtc_ack, scop_ack, oled_ack, io_ack };
initial slow_many_ack = 1'b0;
always @(posedge i_clk)
slow_many_ack <= ((slow_ack_list != 8'h80)
&&(slow_ack_list != 8'h40)
&&(slow_ack_list != 8'h20)
&&(slow_ack_list != 8'h10)
&&(slow_ack_list != 8'h08)
&&(slow_ack_list != 8'h04)
&&(slow_ack_list != 8'h02)
&&(slow_ack_list != 8'h01)
&&(slow_ack_list != 8'h00));
 
always @(posedge i_clk)
wb_ack <= (wb_cyc)&&(|{ ram_ack, flash_ack, mem_ack,
netb_ack, cfg_ack, slow_ack });
always @(posedge i_clk)
slow_ack <= (wb_cyc)&&(|{oled_ack, mio_ack, gps_ack,
netp_ack, sdcard_ack, rtc_ack, scop_ack,
oled_ack, io_ack});
 
//
// Peripheral data lines
//
wire [31:0] io_data, oled_data,
rtc_data, sdcard_data,
netp_data, gps_data, mio_data, cfg_data, netb_data,
mem_data, flash_data, ram_data;
reg [31:0] slow_data, scop_data;
 
// 4 control lines, 5x32 data lines ...
always @(posedge i_clk)
if ((ram_ack)||(flash_ack))
wb_idata <= (ram_ack)?ram_data:flash_data;
else if ((mem_ack)||(netb_ack))
wb_idata <= (mem_ack)?mem_data:netb_data;
else
wb_idata <= slow_data;
 
// 7 control lines, 8x32 data lines
always @(posedge i_clk)
if ((cfg_ack)||(mio_ack))
slow_data <= (cfg_ack) ? cfg_data : mio_data;
else if ((gps_ack)||(netp_ack))
slow_data <= (gps_ack) ? gps_data : netp_data;
else if ((sdcard_ack)||(rtc_ack))
slow_data <= (sdcard_ack)?sdcard_data : rtc_data;
else if ((scop_ack)|(oled_ack))
slow_data <= (scop_ack)?scop_data:oled_data;
else
slow_data <= io_data;
 
//
// Peripheral stall lines
//
// As per the wishbone spec, these cannot be clocked or delayed. They
// *must* be done via combinatorial logic.
//
wire io_stall, scop_stall, oled_stall,
rtc_stall, sdcard_stall,
netp_stall, gps_stall, mio_stall, cfg_stall, netb_stall,
mem_stall, flash_stall, ram_stall,
many_stall;
assign wb_stall = (wb_cyc)&&(
((io_sel)&&(io_stall)) // Never stalls
||((scop_sel)&&(scop_stall)) // Never stalls
||((rtc_sel)&&(rtc_stall)) // Never stalls
||((sdcard_sel)&&(sdcard_stall))// Never stalls
||((netp_sel)&&(netp_stall))
||((gps_sel)&&(gps_stall)) //(maybe? never stalls?)
||((oled_sel)&&(oled_stall))
||((mio_sel)&&(mio_stall))
||((cfg_sel)&&(cfg_stall))
||((netb_sel)&&(netb_stall)) // Never stalls
||((mem_sel)&&(mem_stall)) // Never stalls
||((flash_sel|flctl_sel)&&(flash_stall))
||((ram_sel)&&(ram_stall)));
 
 
//
// Bus Error calculation(s)
//
 
// Selecting nothing is only an error if the strobe line is high as well
// as the cycle line. However, this is captured within the wb_err
// logic itself, so we can ignore it for a line or two.
assign none_sel = ( //(skiperr)||
(~|{ io_sel, scop_sel, flctl_sel, rtc_sel,
sdcard_sel, netp_sel, gps_sel,
oled_sel,
mio_sel, cfg_sel, netb_sel, mem_sel,
flash_sel,ram_sel }));
//
// Selecting multiple devices at once is a design flaw that should
// never happen. Hence, if this logic won't build, we won't include
// it. Still, having this logic in place has saved my tush more than
// once.
//
reg [31:0] sel_addr;
always @(posedge i_clk)
sel_addr <= wb_addr;
 
reg many_sel_a, many_sel_b, single_sel_a, single_sel_b, last_stb;
always @(posedge i_clk)
begin
last_stb <= wb_stb;
 
single_sel_a <= (wb_stb)&&((ram_sel)|(flash_sel)
|(mem_sel)|(netb_sel)|(cfg_sel));
many_sel_a <= 1'b0;
if ((ram_sel)&&((flash_sel)||(mem_sel)||(netb_sel)||cfg_sel))
many_sel_a <= 1'b1;
else if ((flash_sel)&&((mem_sel)||(netb_sel)||cfg_sel))
many_sel_a <= 1'b1;
else if ((mem_sel)&&((netb_sel)||cfg_sel))
many_sel_a <= 1'b1;
else if ((netb_sel)&&(cfg_sel))
many_sel_a <= 1'b1;
 
single_sel_b <= (wb_stb)&&((mio_sel)||(gps_sel)||(netp_sel)
||(sdcard_sel)||(rtc_sel)||(flctl_sel)
||(oled_sel)||(scop_sel)||(io_sel));
many_sel_b <= 1'b0;
if ((mio_sel)&&((gps_sel)||(netp_sel)||(sdcard_sel)||(rtc_sel)
||(flctl_sel)||(scop_sel)||(oled_sel)||(io_sel)))
many_sel_b <= 1'b1;
else if ((gps_sel)&&((netp_sel)||(sdcard_sel)||(rtc_sel)
||(flctl_sel)||(scop_sel)||(oled_sel)||(io_sel)))
many_sel_b <= 1'b1;
else if ((netp_sel)&&((sdcard_sel)||(rtc_sel)
||(flctl_sel)||(scop_sel)||(oled_sel)||(io_sel)))
many_sel_b <= 1'b1;
else if ((sdcard_sel)&&((rtc_sel)
||(flctl_sel)||(scop_sel)||(oled_sel)||(io_sel)))
many_sel_b <= 1'b1;
else if ((rtc_sel)&&((flctl_sel)||(scop_sel)||(oled_sel)||(io_sel)))
many_sel_b <= 1'b1;
else if ((flctl_sel)&&((scop_sel)||(oled_sel)||(io_sel)))
many_sel_b <= 1'b1;
else if ((scop_sel)&&((oled_sel)||(io_sel)))
many_sel_b <= 1'b1;
else if ((oled_sel)&&(io_sel))
many_sel_b <= 1'b1;
end
 
wire sel_err; // 5 inputs
assign sel_err = ( (last_stb)&&(~single_sel_a)&&(~single_sel_b))
||((single_sel_a)&&(single_sel_b))
||((single_sel_a)&&(many_sel_a))
||((single_sel_b)&&(many_sel_b));
assign wb_err = (wb_cyc)&&(sel_err || many_ack || slow_many_ack);
 
 
// Finally, if we ever encounter a bus error, knowing the address of
// the error will be important to figuring out how to fix it. Hence,
// we grab it here. Be aware, however, that this might not truly be
// the address that caused an error: in the case of none_sel it will
// be, but if many_ack or slow_many_ack are true then we might just be
// looking at an address on the bus that was nearby the one requested.
reg [31:0] bus_err_addr;
initial bus_err_addr = 32'h00;
always @(posedge i_clk)
if (wb_err)
bus_err_addr <= sel_addr;
 
//
// I/O peripheral
//
// The I/O processor, herein called an fastio. This is a unique
// set of peripherals--these are all of the peripherals that can answer
// in a single clock--or, rather, they are the peripherals that can
// answer the bus before their clock. Hence, the fastio simply consists
// of a mux that selects between various peripheral responses. Further,
// these peripherals are not allowed to stall the bus.
//
// There is no option for turning these off--they will always be on.
wire [8:0] master_ints;
assign master_ints = { zip_cpu_int, oled_int, rtc_int, sdcard_int,
enet_tx_int, enet_rx_int,
scop_int, flash_int, rtc_pps };
wire [5:0] board_ints;
wire [3:0] w_led;
wire rtc_ppd;
fastio #(
.AUXUART_SETUP(30'hd50),
.GPSUART_SETUP(30'hd20833)
) runio(i_clk, i_sw, i_btn,
w_led, o_clr_led0, o_clr_led1, o_clr_led2, o_clr_led3,
i_aux_rx, o_aux_tx, o_aux_cts, i_gps_rx, o_gps_tx,
wb_cyc, (io_sel)&&(wb_stb), wb_we, wb_addr[4:0],
wb_data, io_ack, io_stall, io_data,
rtc_ppd,
bus_err_addr, master_ints, w_interrupt,
board_ints);
assign { gpio_int, auxrx_int, auxtx_int, gpsrx_int, sw_int, btn_int } = board_ints;
 
/*
reg [25:0] dbg_counter_err, dbg_counter_cyc, dbg_counter_sel,
dbg_counter_many;
// assign wb_err = (wb_cyc)&&(sel_err || many_ack || slow_many_ack);
always @(posedge i_clk)
if (wbu_cyc)
dbg_counter_cyc <= 0;
else if (!dbg_counter_cyc[25])
dbg_counter_cyc <= dbg_counter_cyc+26'h1;
always @(posedge i_clk)
if (wbu_err)
dbg_counter_err <= 0;
else if (!dbg_counter_err[25])
dbg_counter_err <= dbg_counter_err+26'h1;
always @(posedge i_clk)
if ((wb_cyc)&&(sel_err))
dbg_counter_sel <= 0;
else if (!dbg_counter_sel[25])
dbg_counter_sel <= dbg_counter_sel+26'h1;
always @(posedge i_clk)
if ((wb_cyc)&&(many_ack))
dbg_counter_many <= 0;
else if (!dbg_counter_many[25])
dbg_counter_many <= dbg_counter_many+26'h1;
assign o_led = {
(!dbg_counter_many[25])|w_led[3],
(!dbg_counter_sel[25])|w_led[2],
(!dbg_counter_cyc[25])|w_led[1],
(!dbg_counter_err[25])|w_led[0] };
*/
assign o_led = w_led;
 
 
//
//
// Real Time Clock (RTC) device level access
//
//
wire gps_tracking, ck_pps;
wire [63:0] gps_step;
`ifdef RTC_ACCESS
rtcgps #(32'h15798f) // 2^48 / 200MHz
thertc(i_clk,
wb_cyc, (wb_stb)&&(rtc_sel), wb_we,
wb_addr[1:0], wb_data,
rtc_data, rtc_int, rtc_ppd,
gps_tracking, ck_pps, gps_step[47:16], rtc_pps);
`else
assign rtc_data = 32'h00;
assign rtc_int = 1'b0;
assign rtc_pps = 1'b0;
assign rtc_ppd = 1'b0;
`endif
reg r_rtc_ack;
initial r_rtc_ack = 1'b0;
always @(posedge i_clk)
r_rtc_ack <= (wb_stb)&&(rtc_sel);
assign rtc_ack = r_rtc_ack;
assign rtc_stall = 1'b0;
 
//
//
// SDCard device level access
//
//
`ifdef SDCARD_ACCESS
wire [31:0] sd_dbg;
// SPI mapping
wire w_sd_cs_n, w_sd_mosi, w_sd_miso;
 
sdspi sdctrl(i_clk,
wb_cyc, (wb_stb)&&(sdcard_sel), wb_we,
wb_addr[1:0], wb_data,
sdcard_ack, sdcard_stall, sdcard_data,
w_sd_cs_n, o_sd_sck, w_sd_mosi, w_sd_miso,
sdcard_int, 1'b1, sd_dbg);
assign w_sd_miso = i_sd_data[0];
assign o_sd_data = { w_sd_cs_n, 3'b111 };
assign o_sd_cmd = w_sd_mosi;
`else
reg r_sdcard_ack;
always @(posedge i_clk)
r_sdcard_ack <= (wb_stb)&&(sdcard_sel);
assign sdcard_ack = r_sdcard_ack;
 
assign sdcard_data = 32'h00;
assign sdcard_stall= 1'b0;
assign sdcard_int = 1'b0;
`endif
 
//
//
// OLEDrgb device control
//
//
`ifdef OLEDRGB_ACCESS
wboled rgbctrl(i_clk,
wb_cyc, (wb_stb)&&(oled_sel), wb_we,
wb_addr[1:0], wb_data,
oled_ack, oled_stall, oled_data,
o_oled_sck, o_oled_cs_n, o_oled_mosi, o_oled_dcn,
{ o_oled_reset_n, o_oled_vccen, o_oled_pmoden },
oled_int);
`else
assign o_oled_cs_n = 1'b1;
assign o_oled_sck = 1'b1;
assign o_oled_mosi = 1'b1;
assign o_oled_dcn = 1'b1;
assign o_oled_reset_n = 1'b0;
assign o_oled_vccen = 1'b0;
assign o_oled_pmoden = 1'b0;
 
reg r_oled_ack;
always @(posedge i_clk)
r_oled_ack <= (wb_stb)&&(oled_sel);
assign oled_ack = r_oled_ack;
 
assign oled_data = 32'h00;
assign oled_stall= 1'b0;
assign oled_int = 1'b0;
`endif
 
//
//
// GPS CLOCK CONTROLS, BOTH THE TEST BENCH AND THE CLOCK ITSELF
//
//
wire [63:0] gps_now, gps_err;
wire [31:0] gck_data, gtb_data;
wire gck_ack, gck_stall, gtb_ack, gtb_stall;
`ifdef GPS_CLOCK
//
// GPS CLOCK SCHOOL TESTING
//
wire gps_pps, tb_pps, gps_locked;
wire [1:0] gps_dbg_tick;
 
gpsclock_tb ppscktb(i_clk, ck_pps, tb_pps,
(wb_stb)&&(gps_sel)&&(wb_addr[3]),
wb_we, wb_addr[2:0],
wb_data, gtb_ack, gtb_stall, gtb_data,
gps_err, gps_now, gps_step);
`ifdef GPSTB
assign gps_pps = tb_pps; // Let the truth come from our test bench
`else
assign gps_pps = i_gps_pps;
`endif
wire gps_led;
 
//
// GPS CLOCK CONTROL
//
gpsclock ppsck(i_clk, 1'b0, gps_pps, ck_pps, gps_led,
(wb_stb)&&(gps_sel)&&(~wb_addr[3]),
wb_we, wb_addr[1:0],
wb_data, gck_ack, gck_stall, gck_data,
gps_tracking, gps_now, gps_step, gps_err, gps_locked,
gps_dbg_tick);
`else
 
assign gps_err = 64'h0;
assign gps_now = 64'h0;
assign gck_data = 32'h0;
assign gtb_data = 32'h0;
assign gtb_stall = 1'b0;
assign gck_stall = 1'b0;
assign ck_pps = 1'b0;
 
assign gps_tracking = 1'b0;
// Appropriate step for a 200MHz clock
assign gps_step = { 16'h00, 32'h015798e, 16'h00 };
 
reg r_gck_ack;
always @(posedge i_clk)
r_gck_ack <= (wb_stb)&&(gps_sel);
assign gck_ack = r_gck_ack;
assign gtb_ack = r_gck_ack;
 
`endif
 
assign gps_ack = (gck_ack | gtb_ack);
assign gps_stall = (gck_stall | gtb_stall);
assign gps_data = (gck_ack) ? gck_data : gtb_data;
 
 
//
// ETHERNET DEVICE ACCESS
//
`ifdef ETHERNET_ACCESS
reg r_mio_ack, r_netb_ack, r_netp_ack;
always @(posedge i_clk)
r_mio_ack <= (wb_stb)&&(mio_sel);
always @(posedge i_clk)
r_netp_ack <= (wb_stb)&&(netp_sel);
assign mio_ack = r_mio_ack;
assign netp_ack = r_netp_ack;
 
assign mio_data = 32'h00;
assign netp_data = 32'h00;
assign mio_stall = 1'b0;
assign netp_stall= 1'b0;
assign enet_rx_int = 1'b0;
assign enet_tx_int = 1'b0;
 
enetctrl #(3)
mdio(i_clk, i_rst, wb_cyc, (wb_stb)&&(netb_sel), wb_we,
wb_addr[4:0], wb_data[15:0],
netb_ack, netb_stall, netb_data,
o_mdclk, o_mdio, i_mdio, o_mdwe);
`else
reg r_mio_ack, r_netb_ack, r_netp_ack;
always @(posedge i_clk)
r_mio_ack <= (wb_stb)&&(mio_sel);
always @(posedge i_clk)
r_netp_ack <= (wb_stb)&&(netp_sel);
assign mio_ack = r_mio_ack;
assign netp_ack = r_netp_ack;
 
assign mio_data = 32'h00;
assign netp_data = 32'h00;
assign mio_stall = 1'b0;
assign netp_stall= 1'b0;
assign enet_rx_int = 1'b0;
assign enet_tx_int = 1'b0;
 
//
// 2kW memory, 1kW for each of transmit and receive. (Max pkt length
// is 512W, so this allows for two 512W in memory.) Since we don't
// really have ethernet without ETHERNET_ACCESS defined, this just
// consumes resources for us so we have an idea of what might be
// available when we do have ETHERNET_ACCESS defined.
//
memdev #(11) enet_buffers(i_clk, wb_cyc, (wb_stb)&&(netb_sel), wb_we,
wb_addr[10:0], wb_data, netb_ack, netb_stall, netb_data);
assign o_mdclk = 1'b1;
assign o_mdio = 1'b1;
assign o_mdwe = 1'b1;
`endif
 
 
//
// MULTIBOOT/ICAPE2 CONFIGURATION ACCESS
//
`ifdef ICAPE_ACCESS
wbicapetwo fpga_cfg(i_clk, wb_cyc,(cfg_sel)&&(wb_stb), wb_we,
wb_addr[4:0], wb_data,
cfg_ack, cfg_stall, cfg_data);
`else
reg r_cfg_ack;
always @(posedge i_clk)
r_cfg_ack <= (cfg_sel)&&(wb_stb);
assign cfg_ack = r_cfg_ack;
assign cfg_stall = 1'b0;
assign cfg_data = 32'h00;
`endif
 
//
// RAM MEMORY ACCESS
//
// There is no option to turn this off--this RAM must always be
// present in the design.
memdev #(15) // 32kW, or 128kB, 15 address lines
blkram(i_clk, wb_cyc, (wb_stb)&&(mem_sel), wb_we, wb_addr[14:0],
wb_data, mem_ack, mem_stall, mem_data);
 
//
// FLASH MEMORY ACCESS
//
`ifdef FLASH_ACCESS
`ifdef FLASH_SCOPE
wire [31:0] flash_debug;
`endif
wire w_ignore_cmd_accepted;
eqspiflash flashmem(i_clk, i_rst,
wb_cyc,(wb_stb)&&(flash_sel),(wb_stb)&&(flctl_sel),wb_we,
wb_addr[21: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_int, w_ignore_cmd_accepted
`ifdef FLASH_SCOPE
, flash_debug
`endif
);
`else
assign o_qspi_sck = 1'b1;
assign o_qspi_cs_n= 1'b1;
assign o_qspi_mod = 2'b01;
assign o_qspi_dat = 4'h0;
assign flash_data = 32'h00;
assign flash_stall = 1'b0;
assign flash_int = 1'b0;
 
reg r_flash_ack;
always @(posedge i_clk)
r_flash_ack <= (wb_stb)&&(flash_sel);
assign flash_ack = r_flash_ack;
`endif
 
 
//
//
// DDR3-SDRAM
//
//
`ifdef SDRAM_ACCESS
wbddrsdram rami(i_clk,
wb_cyc, (wb_stb)&&(ram_sel), wb_we, wb_addr[25:0], wb_data,
ram_ack, ram_stall, ram_data,
o_ddr_reset_n, o_ddr_cke,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
o_ddr_dqs,
o_ddr_addr, o_ddr_ba, o_ddr_data, i_ddr_data);
`else
assign ram_data = 32'h00;
assign ram_stall = 1'b0;
reg r_ram_ack;
always @(posedge i_clk)
r_ram_ack <= (wb_stb)&&(ram_sel);
assign ram_ack = r_ram_ack;
 
// And idle the DDR3 SDRAM
assign o_ddr_reset_n = 1'b0; // Leave the SDRAM in reset
assign o_ddr_cke = 1'b0; // Disable the SDRAM clock
// DQS
assign o_ddr_dqs = 3'b100; // Leave DQS pins in high impedence
// DDR3 control wires (not enabled if CKE=0)
assign o_ddr_cs_n = 1'b0; // NOOP command
assign o_ddr_ras_n = 1'b1;
assign o_ddr_cas_n = 1'b1;
assign o_ddr_we_n = 1'b1;
// (Unused) data wires
assign o_ddr_addr = 14'h00;
assign o_ddr_ba = 3'h0;
assign o_ddr_data = 32'h00;
`endif
 
 
//
//
// WISHBONE SCOPES
//
//
//
//
wire [31:0] scop_a_data;
wire scop_a_ack, scop_a_stall, scop_a_interrupt;
`ifdef CPU_SCOPE
wire [31:0] scop_cpu_data;
wire scop_cpu_ack, scop_cpu_stall, scop_cpu_interrupt;
wire scop_cpu_trigger;
// assign scop_cpu_trigger = zip_scope_data[30];
assign scop_cpu_trigger = (wb_stb)&&(mem_sel)&&(~wb_we)
&&(wb_err)||(zip_scope_data[31]);
wbscope #(5'd13) cpuscope(i_clk, 1'b1,(scop_cpu_trigger), zip_scope_data,
// Wishbone interface
i_clk, wb_cyc, ((wb_stb)&&(scop_sel)&&(wb_addr[2:1]==2'b00)), wb_we, wb_addr[0],
wb_data,
scop_cpu_ack, scop_cpu_stall, scop_cpu_data,
scop_cpu_interrupt);
 
assign scop_a_data = scop_cpu_data;
assign scop_a_ack = scop_cpu_ack;
assign scop_a_stall = scop_cpu_stall;
assign scop_a_interrupt = scop_cpu_interrupt;
`else
`ifdef FLASH_SCOPE
wire [31:0] scop_flash_data;
wire scop_flash_ack, scop_flash_stall, scop_flash_interrupt;
wire scop_flash_trigger;
// assign scop_cpu_trigger = zip_scope_data[30];
assign scop_flash_trigger = (wb_stb)&&((flash_sel)||(flctl_sel));
wbscope #(5'd13) flashscope(i_clk, 1'b1,
(scop_flash_trigger), flash_debug,
// Wishbone interface
i_clk, wb_cyc, ((wb_stb)&&(scop_sel)&&(wb_addr[2:1]==2'b00)), wb_we, wb_addr[0],
wb_data,
scop_flash_ack, scop_flash_stall, scop_flash_data,
scop_flash_interrupt);
 
assign scop_a_data = scop_flash_data;
assign scop_a_ack = scop_flash_ack;
assign scop_a_stall = scop_flash_stall;
assign scop_a_interrupt = scop_flash_interrupt;
`else
reg r_scop_a_ack;
always @(posedge i_clk)
r_scop_a_ack <= (wb_stb)&&(scop_sel)&&(wb_addr[2:1] == 2'b00);
assign scop_a_data = 32'h00;
assign scop_a_ack = r_scop_a_ack;
assign scop_a_stall = 1'b0;
assign scop_a_interrupt = 1'b0;
`endif
`endif
 
wire [31:0] scop_b_data;
wire scop_b_ack, scop_b_stall, scop_b_interrupt;
`ifdef GPS_SCOPE
reg [18:0] r_gps_debug;
wire [31:0] scop_gps_data;
wire scop_gps_ack, scop_gps_stall, scop_gps_interrupt;
always @(posedge i_clk)
r_gps_debug <= {
gps_dbg_tick, gps_tracking, gps_locked,
gpu_data[7:0],
// (wb_cyc)&&(wb_stb)&&(io_sel),
(wb_stb)&&(io_sel)&&(wb_addr[4:3]==2'b11)&&(wb_we),
(wb_stb)&&(gps_sel)&&(wb_addr[3:2]==2'b01),
gpu_int,
i_gps_rx, rtc_pps, ck_pps, i_gps_pps };
wbscopc #(5'd13,19,32,1) gpsscope(i_clk, 1'b1, ck_pps, r_gps_debug,
// Wishbone interface
i_clk, wb_cyc, ((wb_stb)&&(scop_sel)&&(wb_addr[2:1]==2'b01)),
wb_we, wb_addr[0], wb_data,
scop_gps_ack, scop_gps_stall, scop_gps_data,
scop_gps_interrupt);
`else
assign scop_b_data = 32'h00;
assign scop_b_stall = 1'b0;
assign scop_b_interrupt = 1'b0;
 
reg r_scop_b_ack;
always @(posedge i_clk)
r_scop_b_ack <= (wb_stb)&&(scop_sel)&&(wb_addr[2:1] == 2'b01);
assign scop_b_ack = r_scop_b_ack;
`endif
 
//
// SCOPE C
//
wire [31:0] scop_c_data;
wire scop_c_ack, scop_c_stall, scop_c_interrupt;
//
//`else
assign scop_c_data = 32'h00;
assign scop_c_stall = 1'b0;
assign scop_c_interrupt = 1'b0;
 
reg r_scop_c_ack;
always @(posedge i_clk)
r_scop_c_ack <= (wb_stb)&&(scop_sel)&&(wb_addr[2:1] == 2'b10);
assign scop_c_ack = r_scop_c_ack;
//`endif
 
//
// SCOPE D
//
wire [31:0] scop_d_data;
wire scop_d_ack, scop_d_stall, scop_d_interrupt;
//
//`else
assign scop_d_data = 32'h00;
assign scop_d_stall = 1'b0;
assign scop_d_interrupt = 1'b0;
 
reg r_scop_d_ack;
always @(posedge i_clk)
r_scop_d_ack <= (wb_stb)&&(scop_sel)&&(wb_addr[2:1] == 2'b11);
assign scop_d_ack = r_scop_d_ack;
//`endif
 
assign scop_int = scop_a_interrupt
|| scop_b_interrupt
|| scop_c_interrupt
|| scop_d_interrupt;
assign scop_stall = ((wb_addr[2:1]==2'b0)?scop_a_stall
: ((wb_addr[2:1]==2'b01)?scop_b_stall
: ((wb_addr[2:1]==2'b11)?scop_c_stall
: scop_d_stall))); // Will always be 1'b0;
initial scop_ack = 1'b0;
always @(posedge i_clk)
scop_ack <= scop_a_ack | scop_b_ack | scop_c_ack | scop_d_ack;
always @(posedge i_clk)
if (scop_a_ack)
scop_data <= scop_a_data;
else if (scop_b_ack)
scop_data <= scop_b_data;
else if (scop_c_ack)
scop_data <= scop_c_data;
else // if (scop_d_ack)
scop_data <= scop_d_data;
 
endmodule
/rtl/bigadd.v
0,0 → 1,66
////////////////////////////////////////////////////////////////////////////////
//
// Filename: bigadd.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 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 bigadd(i_clk, i_sync, i_a, i_b, o_r, o_sync);
input i_clk, i_sync;
input [63:0] i_a, i_b;
output reg [63:0] o_r;
output reg o_sync;
 
reg r_sync, r_pps;
reg [31:0] r_hi_a, r_hi_b, r_low;
 
initial r_sync = 1'b0;
always @(posedge i_clk)
r_sync <= i_sync;
 
always @(posedge i_clk)
{ r_pps, r_low } <= i_a[31:0] + i_b[31:0];
always @(posedge i_clk)
r_hi_a <= i_a[63:32];
always @(posedge i_clk)
r_hi_b <= i_b[63:32];
 
initial o_sync = 1'b0;
always @(posedge i_clk)
o_sync <= r_sync;
always @(posedge i_clk)
o_r[31:0] <= r_low;
always @(posedge i_clk)
o_r[63:32] <= r_hi_a + r_hi_b + { 31'h00, r_pps };
 
endmodule
/rtl/bigsmpy.v
0,0 → 1,117
////////////////////////////////////////////////////////////////////////////////
//
// Filename: bigsmpy.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:
//
// 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 bigsmpy(i_clk, i_sync, i_sgn, i_a, i_b, o_r, o_sync);
input i_clk, i_sync, i_sgn;
input [31:0] i_a, i_b;
output reg [63:0] o_r;
output reg o_sync;
 
//
// A pipeline, shift register, to track our synchronization pulse
reg [3:0] r_s;
 
//
reg r_mpy_signed;
reg [31:0] r_mpy_a_input, r_mpy_b_input;
always @(posedge i_clk)
begin
if (i_sgn)
begin
r_mpy_a_input <= {(~i_a[31]), i_a[30:0] };
r_mpy_b_input <= {(~i_b[31]), i_b[30:0] };
end else begin
r_mpy_a_input <= i_a[31:0];
r_mpy_b_input <= i_b[31:0];
end
 
r_mpy_signed <= i_sgn;
r_s[0] <= i_sync;
end
 
reg [31:0] pp_f, pp_o, pp_i, pp_l;
reg [32:0] pp_s;
always @(posedge i_clk)
begin
pp_f <= r_mpy_a_input[31:16] * r_mpy_b_input[31:16];
pp_o <= r_mpy_a_input[31:16] * r_mpy_b_input[15: 0];
pp_i <= r_mpy_a_input[15: 0] * r_mpy_b_input[31:16];
pp_l <= r_mpy_a_input[15: 0] * r_mpy_b_input[15: 0];
 
if (r_mpy_signed)
pp_s <= 32'h8000_0000 - (r_mpy_a_input[31:0]
+ r_mpy_b_input[31:0]);
else
pp_s <= 33'h0;
r_s[1] <= r_s[0];
end
 
reg [32:0] partial_mpy_oi, partial_mpy_lo;
reg [31:0] partial_mpy_hi;
always @(posedge i_clk)
begin
partial_mpy_lo[30: 0] <= pp_l[30:0];
partial_mpy_lo[32:31] <= pp_s[0] + pp_l[31];
partial_mpy_oi[32: 0] <= pp_o + pp_i;
partial_mpy_hi[31: 0] <= pp_s[32:1] + pp_f;
r_s[2] <= r_s[1];
end
 
reg partial_mpy_2cl, partial_mpy_2ch;
reg [31:0] partial_mpy_2lo, partial_mpy_2hi;
always @(posedge i_clk)
begin
partial_mpy_2lo[15:0] <= partial_mpy_lo[15:0];
{ partial_mpy_2cl, partial_mpy_2lo[31:16] }
<= { 1'b0, partial_mpy_oi[15:0]}+ partial_mpy_lo[32:16];
{ partial_mpy_2ch, partial_mpy_2hi[16:0] }
<= partial_mpy_oi[32:16] + partial_mpy_hi[16:0];
partial_mpy_2hi[31:16] <= { partial_mpy_2hi[31:17], 1'b0 };
r_s[3] <= r_s[2];
end
 
always @(posedge i_clk)
begin
o_r[31: 0] <= partial_mpy_2lo[31:0];
o_r[63:32] <= partial_mpy_2hi
+ { 13'h0, partial_mpy_2ch, 1'b0,
15'h0, partial_mpy_2cl };
o_sync <= r_s[3];
end
 
 
endmodule
/rtl/bigsub.v
0,0 → 1,66
////////////////////////////////////////////////////////////////////////////////
//
// Filename: bigsub.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 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 bigsub(i_clk, i_sync, i_a, i_b, o_r, o_sync);
input i_clk, i_sync;
input [63:0] i_a, i_b;
output reg [63:0] o_r;
output reg o_sync;
 
reg r_sync, r_pps;
reg [31:0] r_hi_a, r_hi_b, r_low;
 
initial r_sync = 1'b0;
always @(posedge i_clk)
r_sync <= i_sync;
 
always @(posedge i_clk)
{ r_pps, r_low } <= i_a[31:0] + ({1'b1,~i_b[31:0]}) + 1'b1;
always @(posedge i_clk)
r_hi_a <= i_a[63:32];
always @(posedge i_clk)
r_hi_b <= ~i_b[63:32];
 
initial o_sync = 1'b0;
always @(posedge i_clk)
o_sync <= r_sync;
always @(posedge i_clk)
o_r[31:0] <= r_low;
always @(posedge i_clk)
o_r[63:32] <= r_hi_a + r_hi_b + { 31'h00, r_pps };
 
endmodule
/rtl/lloled.v
0,0 → 1,222
////////////////////////////////////////////////////////////////////////////////
//
// Filename: lloled.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:
//
// 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
//
//
////////////////////////////////////////////////////////////////////////////////
`define OLED_IDLE 3'h0
`define OLED_START 3'h1
`define OLED_BITS 3'h2
`define OLED_READY 3'h3
`define OLED_STOP 3'h4
`define OLED_STOP_B 3'h5
 
// Modes
`define OLED_MOD_SPI 2'b00
`define OLED_MOD_QOUT 2'b10
`define OLED_MOD_QIN 2'b11
 
module lloled(i_clk,
// Module interface
i_wr, i_dbit, i_word, i_len, o_busy,
// OLED interface
o_sck, o_cs_n, o_mosi, o_dbit);
parameter CTRBITS = 8;
input i_clk;
// Chip interface
// Can send info
// i_wr = 1,
// i_word = { 1'b0, 32'info to send },
// i_len = # of bytes in word-1
input i_wr, i_dbit;
input [31:0] i_word;
input [1:0] i_len; // 0=>8bits, 1=>16 bits, 2=>24 bits, 3=>32 bits
output reg o_busy;
// Interface with the OLED lines
output reg o_sck, o_cs_n, o_mosi, o_dbit;
 
// Timing:
//
// Tick Clk BSY/WR CS_n BIT/MO STATE
// 0 1 0/0 1 -
// 1 1 0/1 1 -
// 2 1 1/0 0 - OLED_START
// 3 0 1/0 0 - OLED_START
// 4 0 1/0 0 0 OLED_BITS
// 5 1 1/0 0 0 OLED_BITS
// 6 0 1/0 0 1 OLED_BITS
// 7 1 1/0 0 1 OLED_BITS
// 8 0 1/0 0 2 OLED_BITS
// 9 1 1/0 0 2 OLED_BITS
// 10 0 1/0 0 3 OLED_BITS
// 11 1 1/0 0 3 OLED_BITS
// 12 0 1/0 0 4 OLED_BITS
// 13 1 1/0 0 4 OLED_BITS
// 14 0 1/0 0 5 OLED_BITS
// 15 1 1/0 0 5 OLED_BITS
// 16 0 1/0 0 6 OLED_BITS
// 17 1 1/1 0 6 OLED_BITS
// 18 0 1/1 0 7 OLED_READY
// 19 1 0/1 0 7 OLED_READY
// 20 0 1/0/V 0 8 OLED_BITS
// 21 1 1/0 0 8 OLED_BITS
// 22 0 1/0 0 9 OLED_BITS
// 23 1 1/0 0 9 OLED_BITS
// 24 0 1/0 0 10 OLED_BITS
// 25 1 1/0 0 10 OLED_BITS
// 26 0 1/0 0 11 OLED_BITS
// 27 1 1/0 0 11 OLED_BITS
// 28 0 1/0 0 12 OLED_BITS
// 29 1 1/0 0 12 OLED_BITS
// 30 0 1/0 0 13 OLED_BITS
// 31 1 1/0 0 13 OLED_BITS
// 32 0 1/0 0 14 OLED_BITS
// 33 1 1/0 0 14 OLED_BITS
// 34 0 1/0 0 15 OLED_READY
// 35 1 1/0 0 15 OLED_READY
// 36 1 1/0/V 0 - OLED_STOP
// 37 1 1/0 0 - OLED_STOPB
// 38 1 1/0 1 - OLED_IDLE
// 39 1 0/0 1 -
 
reg [5:0] spi_len;
reg [31:0] r_word;
reg [2:0] state;
initial state = `OLED_IDLE;
initial o_sck = 1'b1;
initial o_cs_n = 1'b1;
initial o_mosi = 1'b0;
initial o_busy = 1'b0;
 
reg [(CTRBITS-1):0] counter;
reg last_counter, pre_last_counter;
always @(posedge i_clk) // Clock cycle time > 150 ns > 300 ticks
last_counter <= (counter == {{(CTRBITS-1){1'b0}},1'b1});
always @(posedge i_clk)
pre_last_counter <= (counter == {{(CTRBITS-2){1'b0}},2'b10});
always @(posedge i_clk)
if (state == `OLED_IDLE)
counter <= {(CTRBITS){1'b1}};
else
counter <= counter + {(CTRBITS){1'b1}};
always @(posedge i_clk)
if ((state == `OLED_IDLE)&&(o_sck))
begin
o_cs_n <= 1'b1;
o_busy <= 1'b0;
r_word <= i_word;
spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8;
o_sck <= 1'b1;
o_dbit <= i_dbit;
if (i_wr)
begin
state <= `OLED_START;
o_cs_n <= 1'b0;
o_busy <= 1'b1;
end
end else if (state == `OLED_START)
begin // We come in here with sck high, stay here 'til sck is low
o_sck <= 1'b0;
if (o_sck == 1'b0)
begin
state <= `OLED_BITS;
spi_len<= spi_len - 6'h1;
r_word <= { r_word[30:0], 1'b0 };
end
o_cs_n <= 1'b0;
o_busy <= 1'b1;
o_mosi <= r_word[31];
end else if (~last_counter)
begin
o_busy <= (pre_last_counter)&&(o_sck)
&&((state != `OLED_READY)||(~i_wr));
end else if (~o_sck)
begin
o_sck <= 1'b1;
o_busy <= 1'b1;
end else if (state == `OLED_BITS)
begin
// Should enter into here with at least a spi_len
// of one, perhaps more
o_sck <= 1'b0;
o_busy <= 1'b1;
o_mosi <= r_word[31];
r_word <= { r_word[30:0], 1'b0 };
spi_len <= spi_len - 6'h1;
if (spi_len == 6'h1)
state <= `OLED_READY;
end else if (state == `OLED_READY)
begin
o_cs_n <= 1'b0;
o_busy <= 1'b1;
// This is the state on the last clock (both low and
// high clocks) of the data. Data is valid during
// this state. Here we chose to either STOP or
// continue and transmit more.
o_sck <= 1'b0;
if((~o_busy)&&(i_wr))// Acknowledge a new request
begin
state <= `OLED_BITS;
o_busy <= 1'b1;
o_sck <= 1'b0;
 
// Set up the first bits on the bus
o_mosi <= i_word[31];
r_word <= { i_word[30:0], 1'b0 };
spi_len<= { 1'b0, i_len, 3'b111 };
 
// Read a bit upon any transition
end else begin
o_sck <= 1'b1;
state <= `OLED_STOP;
o_busy <= 1'b1;
end
end else if (state == `OLED_STOP)
begin
o_sck <= 1'b1; // Stop the clock
o_busy <= 1'b1; // Still busy till port is clear
state <= `OLED_STOP_B;
end else // if (state == `OLED_STOP_B)
begin
o_cs_n <= 1'b1; // Deselect CS
o_sck <= 1'b1;
// Do I need this????
// spi_len <= 3; // Minimum CS high time before next cmd
state <= `OLED_IDLE;
o_mosi <= 1'b1;
o_busy <= 1'b1;
end
/*
*/
 
endmodule
 
/rtl/wbuoutput.v
0,0 → 1,109
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wbuoutput.v
//
// Project: FPGA library
//
// Purpose: Converts 36-bit codewords into bytes to be placed on the serial
// output port. The codewords themselves are the results of bus
// transactions, which are then (hopefully) compressed within here and
// carefully arranged into "lines" for visual viewing (if necessary).
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
module wbuoutput(i_clk, i_rst, i_stb, i_codword,
i_wb_cyc, i_int, i_bus_busy,
o_stb, o_char, i_tx_busy, o_fifo_err);
input i_clk, i_rst;
input i_stb;
input [35:0] i_codword;
// Not Idle indicators
input i_wb_cyc, i_int, i_bus_busy;
// Outputs to our UART transmitter
output wire o_stb;
output wire [7:0] o_char;
// Miscellaneous I/O: UART transmitter busy, and fifo error
input i_tx_busy;
output wire o_fifo_err;
 
wire fifo_rd, dw_busy, fifo_empty_n, fifo_err;
wire [35:0] fifo_codword;
 
wire cw_stb, cw_busy, cp_stb, dw_stb, ln_stb, ln_busy,
cp_busy, byte_busy;
wire [35:0] cw_codword, cp_word;
wire [6:0] dw_bits, ln_bits;
 
// `define SKIP_FIFO
`ifdef SKIP_FIFO
assign fifo_rd = i_stb;
assign fifo_codword = i_codword;
assign fifo_err = 1'b0;
`else
assign fifo_rd = (fifo_empty_n)&&(~cw_busy);
wbufifo #(36,10) busoutfifo(i_clk, i_rst, i_stb, i_codword,
fifo_rd, fifo_codword, fifo_empty_n,
fifo_err);
`endif
 
assign o_fifo_err = fifo_err;
 
wbuidleint buildcw(i_clk, fifo_rd, fifo_codword,
i_wb_cyc, i_bus_busy, i_int,
cw_stb, cw_codword, cw_busy, cp_busy);
// assign o_dbg = dw_busy; // Always asserted ... ???
// assign o_dbg = { dw_busy, ln_busy, fifo_rd };
// Stuck: dw_busy and ln_busy get stuck high after read attempt,
// fifo_rd is low
// assign o_dbg = { fifo_rd, cp_stb, cw_stb };
// cw_stb and cp_stb get stuck high after one read
 
//
// cw_busy & cw_stb, not cp_stb, but dw_busy
//
 
// `define SKIP_COMPRESS
`ifdef SKIP_COMPRESS
assign cp_stb = cw_stb;
assign cp_word = cw_codword;
assign cp_busy = dw_busy;
`else
assign cp_busy = cp_stb;
wbucompress packit(i_clk, cw_stb, cw_codword,
cp_stb, cp_word, dw_busy);
`endif
 
wbudeword deword(i_clk, cp_stb, cp_word, ln_busy,
dw_stb, dw_bits, dw_busy);
 
wbucompactlines linepacker(i_clk, dw_stb, dw_bits,
ln_stb, ln_bits,
(i_wb_cyc||i_bus_busy||fifo_empty_n||cw_busy),
byte_busy, ln_busy);
 
wbusixchar mkbytes(i_clk, ln_stb, ln_bits, o_stb, o_char, byte_busy, i_tx_busy);
 
endmodule
/rtl/fasttop.v
0,0 → 1,469
////////////////////////////////////////////////////////////////////////////////
//
// Filename: fasttop.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: This is the top level Verilog file. It is so named as fasttop,
// because my purpose will be to run the Arty at 200MHz, just to
// prove that I can get it up to that frequency.
//
// 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 fasttop(i_clk_100mhz, i_reset_btn,
i_sw, // Switches
i_btn, // Buttons
o_led, // Single color LEDs
o_clr_led0, o_clr_led1, o_clr_led2, o_clr_led3, // Color LEDs
// RS232 UART
i_uart_rx, o_uart_tx,
// Quad-SPI Flash control
o_qspi_sck, o_qspi_cs_n, io_qspi_dat,
// Missing: Ethernet
o_eth_mdclk, io_eth_mdio,
// Memory
o_ddr_reset_n, o_ddr_cke, o_ddr_ck_p, o_ddr_ck_n,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
io_ddr_dqs_p, io_ddr_dqs_n,
o_ddr_addr, o_ddr_ba,
io_ddr_data, o_ddr_dm, o_ddr_odt,
// SD Card
o_sd_sck, io_sd_cmd, io_sd, i_sd_cs, i_sd_wp,
// GPS Pmod
i_gps_pps, i_gps_3df, i_gps_rx, o_gps_tx,
// OLED Pmod
o_oled_sck, o_oled_cs_n, o_oled_mosi, o_oled_dcn, o_oled_reset_n,
o_oled_vccen, o_oled_pmoden,
// PMod I/O
i_aux_rx, i_aux_rts, o_aux_tx, o_aux_cts
);
input i_clk_100mhz, i_reset_btn;
input [3:0] i_sw; // Switches
input [3:0] i_btn; // Buttons
output wire [3:0] o_led; // LED
output wire [2:0] o_clr_led0, o_clr_led1, o_clr_led2, o_clr_led3;
// UARTs
input i_uart_rx;
output wire o_uart_tx;
// Quad SPI flash
output wire o_qspi_sck, o_qspi_cs_n;
inout [3:0] io_qspi_dat;
// Ethernet // Not yet implemented
// Ethernet control (MDIO)
output wire o_eth_mdclk;
inout wire io_eth_mdio;
// DDR3 SDRAM
output wire o_ddr_reset_n;
output wire o_ddr_cke;
output wire o_ddr_ck_p, o_ddr_ck_n;
output wire o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n;
inout [1:0] io_ddr_dqs_p, io_ddr_dqs_n;
output wire [13:0] o_ddr_addr;
output wire [2:0] o_ddr_ba;
inout [15:0] io_ddr_data;
//
output wire [1:0] o_ddr_dm;
output wire o_ddr_odt;
// SD Card
output wire o_sd_sck;
inout io_sd_cmd;
inout [3:0] io_sd;
input i_sd_cs;
input i_sd_wp;
// GPS PMod
input i_gps_pps, i_gps_3df, i_gps_rx;
output wire o_gps_tx;
// OLEDRGB PMod
output wire o_oled_sck, o_oled_cs_n, o_oled_mosi,
o_oled_dcn, o_oled_reset_n, o_oled_vccen,
o_oled_pmoden;
// Aux UART
input i_aux_rx, i_aux_rts;
output wire o_aux_tx, o_aux_cts;
 
// `define FULLCLOCK
// Build our master clock
wire i_clk, clk_for_ddr, clk2_unused, enet_clk, clk5_unused,
clk_feedback, clk_locked;
PLLE2_BASE #(
.BANDWIDTH("OPTIMIZED"), // OPTIMIZED, HIGH, LOW
.CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB, (-360-360)
.CLKIN1_PERIOD(10.0), // Input clock period in ns to ps resolution
`ifdef FULLCLOCK
// CLKOUT0_DIVIDE - CLKOUT5_DIVIDE: divide amount for each CLKOUT(1-128)
.CLKFBOUT_MULT(8), // Multiply value for all CLKOUT (2-64)
.CLKOUT0_DIVIDE(4), // 200 MHz
.CLKOUT1_DIVIDE(4), // 200 MHz
.CLKOUT2_DIVIDE(8), // 100 MHz
.CLKOUT3_DIVIDE(32), // 25 MHz
.CLKOUT4_DIVIDE(16), // 50 MHz
.CLKOUT5_DIVIDE(24),
`else
// 100*64/40 = 160 -- the fastest speed where the UART will
// still work at 4MBaud. Others will still support 115200
// Baud
// 100*64/36 = 177.78
// 100*64/34 = 188.24
// 100*64/33 = 193.94
.CLKFBOUT_MULT(8), // Multiply value for all CLKOUT (2-64)
.CLKOUT0_DIVIDE(5), // 160 MHz
.CLKOUT1_DIVIDE(5), // 160 MHz
.CLKOUT2_DIVIDE(10), // 80 MHz
.CLKOUT3_DIVIDE(40), // 20 MHz
.CLKOUT4_DIVIDE(20), // 40 MHz
.CLKOUT5_DIVIDE(30),
`endif
// CLKOUT0_DUTY_CYCLE -- Duty cycle for each CLKOUT
.CLKOUT0_DUTY_CYCLE(0.5),
.CLKOUT1_DUTY_CYCLE(0.5),
.CLKOUT2_DUTY_CYCLE(0.5),
.CLKOUT3_DUTY_CYCLE(0.5),
.CLKOUT4_DUTY_CYCLE(0.5),
.CLKOUT5_DUTY_CYCLE(0.5),
// CLKOUT0_PHASE -- phase offset for each CLKOUT
.CLKOUT0_PHASE(0.0),
.CLKOUT1_PHASE(90.0),
.CLKOUT2_PHASE(0.0),
.CLKOUT3_PHASE(0.0),
.CLKOUT4_PHASE(0.0),
.CLKOUT5_PHASE(0.0),
.DIVCLK_DIVIDE(1), // Master division value , (1-56)
.REF_JITTER1(0.0), // Reference input jitter in UI (0.000-0.999)
.STARTUP_WAIT("FALSE") // Delayu DONE until PLL Locks, ("TRUE"/"FALSE")
) genclock(
// Clock outputs: 1-bit (each) output
.CLKOUT0(i_clk),
.CLKOUT1(clk_for_ddr),
.CLKOUT2(clk2_unused), // Reserved for flash, should we need it
.CLKOUT3(enet_clk),
.CLKOUT4(clk4_unused),
.CLKOUT5(clk5_unused),
.CLKFBOUT(clk_feedback), // 1-bit output, feedback clock
.LOCKED(clk_locked),
.CLKIN1(i_clk_100mhz),
.PWRDWN(1'b0),
.RST(1'b0),
.CLKFBIN(clk_feedback) // 1-bit input, feedback clock
);
// UART interface
wire [29:0] bus_uart_setup;
`ifdef FULLCLOCK
assign bus_uart_setup = 30'h10000032; // 4MBaud, 7 bits
`else
assign bus_uart_setup = 30'h10000028;//4MBaud,7 bits,@160MHzClk
//assign bus_uart_setup = 30'h10000019;//4MBaud,7 bits,@100MHzClk
`endif
 
wire [7:0] rx_data, tx_data;
wire rx_break, rx_parity_err, rx_frame_err, rx_stb;
wire tx_stb, tx_busy;
 
reg pwr_reset, pre_reset;
initial pwr_reset = 1'b1;
initial pre_reset = 1'b0;
always @(posedge i_clk)
pre_reset <= ~i_reset_btn;
always @(posedge i_clk)
pwr_reset <= pre_reset;
 
wire w_ck_uart, w_uart_tx;
rxuart rcv(i_clk, pwr_reset, bus_uart_setup, i_uart_rx,
rx_stb, rx_data, rx_break,
rx_parity_err, rx_frame_err, w_ck_uart);
txuart txv(i_clk, pwr_reset, bus_uart_setup, 1'b0,
tx_stb, tx_data, o_uart_tx, tx_busy);
 
 
 
 
 
 
//////
//
//
// The WB bus interconnect, herein called fastmaster, which handles
// just about ... everything.
//
//
//////
wire w_qspi_sck;
wire [1:0] qspi_bmod;
wire [3:0] qspi_dat;
wire [3:0] i_qspi_dat;
 
//
wire [2:0] w_ddr_dqs;
wire [31:0] wo_ddr_data, wi_ddr_data;
//
wire w_mdio, w_mdwe;
//
wire w_sd_cmd;
wire [3:0] w_sd_data;
fastmaster wbbus(i_clk, pwr_reset,
// External USB-UART bus control
rx_stb, rx_data, tx_stb, tx_data, tx_busy,
// Board lights and switches
i_sw, i_btn, o_led,
o_clr_led0, o_clr_led1, o_clr_led2, o_clr_led3,
// Board level PMod I/O
i_aux_rx, o_aux_tx, o_aux_cts, i_gps_rx, o_gps_tx,
// Quad SPI flash
o_qspi_cs_n, w_qspi_sck, qspi_dat, io_qspi_dat, qspi_bmod,
// DDR3 SDRAM
o_ddr_reset_n, o_ddr_cke,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
w_ddr_dqs, o_ddr_addr, o_ddr_ba, wo_ddr_data, wi_ddr_data,
// SD Card
o_sd_sck, w_sd_cmd, w_sd_data, io_sd_cmd, io_sd, i_sd_cs,
// Ethernet control (MDIO) lines
o_eth_mdclk, w_mdio, w_mdwe, io_eth_mdio,
// OLEDRGB PMod wires
o_oled_sck, o_oled_cs_n, o_oled_mosi, o_oled_dcn,
o_oled_reset_n, o_oled_vccen, o_oled_pmoden,
// GPS PMod
i_gps_pps, i_gps_3df
);
 
//////
//
//
// Some wires need special treatment, and so are not quite completely
// handled by the bus master. These are handled below.
//
//
//////
 
//
//
// QSPI)BMOD, Quad SPI bus mode, Bus modes are:
// 0? Normal serial mode, one bit in one bit out
// 10 Quad SPI mode, going out
// 11 Quad SPI mode coming from the device (read mode)
//
// ?? Dual mode in (not yet)
// ?? Dual mode out (not yet)
//
//
assign io_qspi_dat = (~qspi_bmod[1])?({2'b11,1'bz,qspi_dat[0]})
:((qspi_bmod[0])?(4'bzzzz):(qspi_dat[3:0]));
assign i_qspi_dat = io_qspi_dat;
assign o_qspi_sck = w_qspi_sck;
/*
wire [3:0] i_qspi_dat_ign;
ODDR #(.DDR_CLK_EDGE("OPPOSITE_EDGE"), .INIT(1'b1), .SRTYPE("SYNC"))
qsck(
.Q(o_qspi_sck),
.C(i_clk),
.CE(1'b1),
.D1(w_qspi_sck),
.D2(w_qspi_sck),
.R(1'b0), .S(1'b0));
xioddr qd0(i_clk, (~qspi_bmod[1])|(~qspi_bmod[0]),
{ qspi_dat[0], qspi_dat[0] },
{ i_qspi_dat[0], i_qspi_dat_ign[0] }, io_qspi_dat[0]);
xioddr qd1(i_clk, (qspi_bmod == 2'b10),
{ qspi_dat[1], qspi_dat[1] },
{ i_qspi_dat[1], i_qspi_dat_ign[1] }, io_qspi_dat[1]);
xioddr qd2(i_clk, (~qspi_bmod[1])||(~qspi_bmod[0]),
{ qspi_dat[2], qspi_dat[2] },
{ i_qspi_dat[2], i_qspi_dat_ign[2] }, io_qspi_dat[2]);
xioddr qd3(i_clk, (~qspi_bmod[1])||(~qspi_bmod[0]),
{ qspi_dat[3], qspi_dat[3] },
{ i_qspi_dat[3], i_qspi_dat_ign[3] }, io_qspi_dat[3]);
*/
 
//
// Proposed QSPI mode select, to allow dual I/O mode
// 000 Normal SPI mode
// 001 Dual mode input
// 010 Dual mode, output
// 101 Quad I/O mode input
// 110 Quad I/O mode output
//
//
// assign io_qspi_dat[3:2] = (~qspi_bmod[2]) ? 2'b11
// : (qspi_bmod[0])?2'bzz : qspi_dat[3:2];
// assign io_qspi_dat[1] = (~qspi_bmod[1])?qspi_dat[1]:1'bz;
// assign io_qspi_dat[0] = (qspi_bmod[0])?1'bz : qspi_dat[0];
 
//
//
// The following primitive is necessary in order to gain access
// to the o_qspi_sck pin.
//
//
/*
wire [3:0] su_nc; // Startup primitive, no connect
STARTUPE2 #(
// Leave PROG_USR false to avoid activating the program
// event security feature. Notes state that such a feature
// requires encrypted bitstreams.
.PROG_USR("FALSE"),
// Sets the configuration clock frequency (in ns) for
// simulation.
.SIM_CCLK_FREQ(0.0)
) STARTUPE2_inst (
// CFGCLK, 1'b output: Configuration main clock output -- no connect
.CFGCLK(su_nc[0]),
// CFGMCLK, 1'b output: Configuration internal oscillator clock output
.CFGMCLK(su_nc[1]),
// EOS, 1'b output: Active high output indicating the End Of Startup.
.EOS(su_nc[2]),
// PREQ, 1'b output: PROGRAM request to fabric output
// Only enabled if PROG_USR is set. This lets the fabric know
// that a request has been made (either JTAG or pin pulled low)
// to program the device
.PREQ(su_nc[3]),
// CLK, 1'b input: User start-up clock input
.CLK(1'b0),
// GSR, 1'b input: Global Set/Reset input
.GSR(1'b0),
// GTS, 1'b input: Global 3-state input
.GTS(1'b0),
// KEYCLEARB, 1'b input: Clear AES Decrypter Key input from BBRAM
.KEYCLEARB(1'b0),
// PACK, 1-bit input: PROGRAM acknowledge input
// This pin is only enabled if PROG_USR is set. This allows the
// FPGA to acknowledge a request for reprogram to allow the FPGA
// to get itself into a reprogrammable state first.
.PACK(1'b0),
// USRCLKO, 1-bit input: User CCLK input -- This is why I am using this
// module at all.
.USRCCLKO(qspi_sck),
// USRCCLKTS, 1'b input: User CCLK 3-state enable input
// An active high here places the clock into a high impedence
// state. Since we wish to use the clock as an active output
// always, we drive this pin low.
.USRCCLKTS(1'b0),
// USRDONEO, 1'b input: User DONE pin output control
// Set this to "high" to make sure that the DONE LED pin is
// high.
.USRDONEO(1'b1),
// USRDONETS, 1'b input: User DONE 3-state enable output
// This enables the FPGA DONE pin to be active. Setting this
// active high sets the DONE pin to high impedence, setting it
// low allows the output of this pin to be as stated above.
.USRDONETS(1'b1)
);
*/
 
 
 
//
//
// Wires for setting up the SD Card Controller
//
//
assign io_sd_cmd = w_sd_cmd ? 1'bz:1'b0;
assign io_sd[0] = w_sd_data[0]? 1'bz:1'b0;
assign io_sd[1] = w_sd_data[1]? 1'bz:1'b0;
assign io_sd[2] = w_sd_data[2]? 1'bz:1'b0;
assign io_sd[3] = w_sd_data[3]? 1'bz:1'b0;
assign o_sd_wp = 1'b0;
 
 
//
//
// Wire(s) for setting up the MDIO ethernet control structure
//
//
assign io_eth_mdio = (w_mdwe)?w_mdio : 1'bz;
 
//
//
// Wires for setting up the DDR3 memory
//
//
wire [31:0] r_ddr_data;
 
xioddr p0(i_clk, ~o_ddr_we_n, { wo_ddr_data[16], wo_ddr_data[0] },
{ wi_ddr_data[16], wi_ddr_data[0] }, io_ddr_data[0]);
 
xioddr p1(i_clk, ~o_ddr_we_n, { wo_ddr_data[17], wo_ddr_data[1] },
{ wi_ddr_data[17], wi_ddr_data[1] }, io_ddr_data[1]);
 
xioddr p2(i_clk, ~o_ddr_we_n, { wo_ddr_data[18], wo_ddr_data[2] },
{ wi_ddr_data[18], wi_ddr_data[2] }, io_ddr_data[2]);
 
xioddr p3(i_clk, ~o_ddr_we_n, { wo_ddr_data[19], wo_ddr_data[3] },
{ wi_ddr_data[19], wi_ddr_data[3] }, io_ddr_data[3]);
 
xioddr p4(i_clk, ~o_ddr_we_n, { wo_ddr_data[20], wo_ddr_data[4] },
{ wi_ddr_data[20], wi_ddr_data[4] }, io_ddr_data[4]);
 
xioddr p5(i_clk, ~o_ddr_we_n, { wo_ddr_data[21], wo_ddr_data[5] },
{ wi_ddr_data[21], wi_ddr_data[5] }, io_ddr_data[5]);
 
xioddr p6(i_clk, ~o_ddr_we_n, { wo_ddr_data[22], wo_ddr_data[6] },
{ wi_ddr_data[22], wi_ddr_data[6] }, io_ddr_data[6]);
 
xioddr p7(i_clk, ~o_ddr_we_n, { wo_ddr_data[23], wo_ddr_data[7] },
{ wi_ddr_data[23], wi_ddr_data[7] }, io_ddr_data[7]);
 
xioddr p8(i_clk, ~o_ddr_we_n, { wo_ddr_data[24], wo_ddr_data[8] },
{ wi_ddr_data[24], wi_ddr_data[8] }, io_ddr_data[8]);
 
xioddr p9(i_clk, ~o_ddr_we_n, { wo_ddr_data[25], wo_ddr_data[9] },
{ wi_ddr_data[25], wi_ddr_data[9] }, io_ddr_data[9]);
 
xioddr pa(i_clk, ~o_ddr_we_n, { wo_ddr_data[26], wo_ddr_data[10] },
{ wi_ddr_data[26], wi_ddr_data[10] }, io_ddr_data[10]);
 
xioddr pb(i_clk, ~o_ddr_we_n, { wo_ddr_data[27], wo_ddr_data[11] },
{ wi_ddr_data[27], wi_ddr_data[11] }, io_ddr_data[11]);
 
xioddr pc(i_clk, ~o_ddr_we_n, { wo_ddr_data[28], wo_ddr_data[12] },
{ wi_ddr_data[28], wi_ddr_data[12] }, io_ddr_data[12]);
 
xioddr pd(i_clk, ~o_ddr_we_n, { wo_ddr_data[29], wo_ddr_data[13] },
{ wi_ddr_data[29], wi_ddr_data[13] }, io_ddr_data[13]);
 
xioddr pe(i_clk, ~o_ddr_we_n, { wo_ddr_data[30], wo_ddr_data[14] },
{ wi_ddr_data[30], wi_ddr_data[14] }, io_ddr_data[14]);
 
xioddr pf(i_clk, ~o_ddr_we_n, { wo_ddr_data[31], wo_ddr_data[15] },
{ wi_ddr_data[31], wi_ddr_data[15] }, io_ddr_data[15]);
 
OBUFTDS #(.IOSTANDARD("DIFF_SSTL135"), .SLEW("FAST"))
dqsbuf0(.O(io_ddr_dqs_p[0]), .OB(io_ddr_dqs_n[0]),
.I(w_ddr_dqs[1]), .T(w_ddr_dqs[2]));
OBUFTDS #(.IOSTANDARD("DIFF_SSTL135"), .SLEW("FAST"))
dqsbuf1(.O(io_ddr_dqs_p[1]), .OB(io_ddr_dqs_n[1]),
.I(w_ddr_dqs[0]), .T(w_ddr_dqs[2]));
 
OBUFDS #(.IOSTANDARD("DIFF_SSTL135"), .SLEW("FAST"))
clkbuf(.O(o_ddr_ck_p), .OB(o_ddr_ck_n), .I(clk_for_ddr));
 
assign o_ddr_dm = 2'b00;
assign o_ddr_odt = 1'b0;
 
endmodule
 
/rtl/enetctrl.v
0,0 → 1,209
////////////////////////////////////////////////////////////////////////////////
//
// Filename: enetctrl
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: This module translates wishbone commands, whether they be read
// or write commands, to MIO commands operating on an Ethernet
// controller, such as the TI DP83848 controller on the Artix-7 Arty
// development boarod (used by this project). As designed, the bus
// *will* stall until the command has been completed.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 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 ECTRL_RESET 3'h0
`define ECTRL_IDLE 3'h1
`define ECTRL_ADDRESS 3'h2
`define ECTRL_READ 3'h3
`define ECTRL_WRITE 3'h4
module enetctrl(i_clk, i_rst,
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_mdclk, o_mdio, i_mdio, o_mdwe);
parameter CLKBITS=3; // = 3 for 200MHz source clock, 2 for 100 MHz
input i_clk, i_rst;
input i_wb_cyc, i_wb_stb, i_wb_we;
input [4:0] i_wb_addr;
input [15:0] i_wb_data;
output reg o_wb_ack, o_wb_stall;
output wire [31:0] o_wb_data;
//
input i_mdio;
output wire o_mdclk;
output reg o_mdio, o_mdwe;
//
parameter PHYADDR = 5'h01;
 
 
reg read_pending, write_pending;
reg [4:0] r_addr;
reg [15:0] read_reg, write_reg, r_data;
reg [2:0] ctrl_state;
reg [5:0] reg_pos;
reg zreg_pos;
reg [15:0] r_wb_data;
 
 
// Step 1: Generate our clock
reg [(CLKBITS-1):0] clk_counter;
initial clk_counter = 0;
always @(posedge i_clk)
clk_counter <= clk_counter + 1;
assign o_mdclk = clk_counter[(CLKBITS-1)];
 
// Step 2: Generate strobes for when to move, given the clock
reg rclk, zclk;
initial zclk = 0;
always @(posedge i_clk)
zclk <= &clk_counter;
initial rclk = 0;
always @(posedge i_clk)
rclk <= (~clk_counter[(CLKBITS-1)])&&(&clk_counter[(CLKBITS-2):0]);
 
// Step 3: Read from our input port
// Note: I read on the falling edge, he changes on the rising edge
always @(posedge i_clk)
if (zclk)
read_reg <= { read_reg[14:0], i_mdio };
always @(posedge i_clk)
zreg_pos <= (reg_pos == 0);
 
always @(posedge i_clk)
if (rclk)
r_wb_data <= read_reg;
assign o_wb_data = { 16'h00, r_wb_data };
 
// Step 4: Write to our output port
// Note: I change on the falling edge,
always @(posedge i_clk)
if (zclk)
o_mdio <= write_reg[15];
 
reg in_idle;
initial in_idle = 1'b0;
always @(posedge i_clk)
in_idle <= (ctrl_state == `ECTRL_IDLE);
initial o_wb_stall = 1'b0;
always @(posedge i_clk)
if (ctrl_state != `ECTRL_IDLE)
o_wb_stall <= 1'b1;
else if (o_wb_ack)
o_wb_stall <= 1'b0;
else if (((i_wb_stb)&&(in_idle))||(read_pending)||(write_pending))
o_wb_stall <= 1'b1;
else o_wb_stall <= 1'b0;
 
initial read_pending = 1'b0;
initial write_pending = 1'b0;
always @(posedge i_clk)
begin
r_addr <= i_wb_addr;
if ((i_wb_stb)&&(~o_wb_stall))
r_data <= i_wb_data;
if ((i_rst)||(ctrl_state == `ECTRL_READ)||(ctrl_state == `ECTRL_WRITE))
begin
read_pending <= 1'b0;
write_pending <= 1'b0;
end else if ((i_wb_stb)&&(~o_wb_stall))
begin
read_pending <= (~i_wb_we);
write_pending <= (i_wb_we);
end
end
 
initial reg_pos = 6'h3f;
initial ctrl_state = `ECTRL_RESET;
initial write_reg = 16'hffff;
always @(posedge i_clk)
begin
o_wb_ack <= 1'b0;
if ((zclk)&&(~zreg_pos))
reg_pos <= reg_pos - 1;
if (zclk)
write_reg <= { write_reg[14:0], 1'b1 };
if (i_rst)
begin // Must go for 167 ms before our 32 clocks
ctrl_state <= `ECTRL_RESET;
reg_pos <= 6'h3f;
write_reg[15:0] <= 16'hffff;
end else case(ctrl_state)
`ECTRL_RESET: begin
o_mdwe <= 1'b1; // Write
write_reg[15:0] <= 16'hffff;
if ((zclk)&&(zreg_pos))
ctrl_state <= `ECTRL_IDLE;
end
`ECTRL_IDLE: begin
o_mdwe <= 1'b1; // Write
write_reg <= { 4'he, PHYADDR, r_addr, 2'b11 };
if (write_pending)
write_reg[15:12] <= { 4'h5 };
else if (read_pending)
write_reg[15:12] <= { 4'h6 };
if (read_pending || write_pending)
begin
reg_pos <= 6'h0f;
ctrl_state <= `ECTRL_ADDRESS;
end end
`ECTRL_ADDRESS: begin
o_mdwe <= 1'b1; // Write
if ((zreg_pos)&&(zclk))
begin
reg_pos <= 6'h10;
if (read_pending)
ctrl_state <= `ECTRL_READ;
else
ctrl_state <= `ECTRL_WRITE;
write_reg <= r_data;
end end
`ECTRL_READ: begin
o_mdwe <= 1'b0; // Read
if ((zreg_pos)&&(zclk))
begin
ctrl_state <= `ECTRL_IDLE;
o_wb_ack <= 1'b1;
end end
`ECTRL_WRITE: begin
o_mdwe <= 1'b1; // Write
if ((zreg_pos)&&(zclk))
begin
ctrl_state <= `ECTRL_IDLE;
o_wb_ack <= 1'b1;
end end
default: begin
o_mdwe <= 1'b0; // Read
reg_pos <= 6'h3f;
ctrl_state <= `ECTRL_RESET;
end
endcase
end
 
endmodule
/rtl/flash_config.v
0,0 → 1,48
///////////////////////////////////////////////////////////////////////////
//
// Filename: flashconfig.v
//
// Project: Wishbone Controlled Quad SPI Flash Controller
//
// Purpose: A configuration file, separated from the controller file, so
// that multiple files can use the same wishbone Quad Spi Flash
// controller, while each having a separate configuration. Currently,
// the configuration only includes whether the flash is read only or not.
// Other configuration options may be added later.
//
//
// Creator: Dan Gisselquist
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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
//
//
///////////////////////////////////////////////////////////////////////////
//
`ifndef FLASH_CONFIG_V
`define FLASH_CONFIG_V
//
// `define READ_ONLY
//
`endif
//
/rtl/wbureadcw.v
0,0 → 1,126
///////////////////////////////////////////////////////////////////////////
//
// Filename: wbureadcw.v
//
// Project: FPGA library
//
// Purpose: Read bytes from a serial port (i.e. the jtagser) and translate
// those bytes into a 6-byte codeword. This codeword may specify
// a number of values to be read, the value to be written, or an address
// to read/write from, or perhaps the end of a write sequence.
//
// See the encoding documentation file for more information.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
//
// Goal: single clock pipeline, 50 slices or less
//
module wbureadcw(i_clk, i_stb, i_valid, i_hexbits,
o_stb, o_codword);
input i_clk, i_stb, i_valid;
input [5:0] i_hexbits;
output reg o_stb;
output reg [35:0] o_codword;
 
 
// Timing:
// Clock 0: i_stb is high, i_valid is low
// Clock 1: shiftreg[5:0] is valid, cw_len is valid
// r_len = 1
// Clock 2: o_stb = 1, for cw_len = 1;
// o_codword is 1-byte valid
// i_stb may go high again on this clock as well.
// Clock 3: o_stb = 0 (cw_len=1),
// cw_len = 0,
// r_len = 0 (unless i_stb)
// Ready for next word
 
reg [2:0] r_len, cw_len;
reg [1:0] lastcw;
 
wire w_stb;
assign w_stb = ((r_len == cw_len)&&(cw_len != 0))
||((i_stb)&&(~i_valid)&&(lastcw == 2'b01));
 
// r_len is the length of the codeword as it exists
// in our register
initial r_len = 3'h0;
always @(posedge i_clk)
if ((i_stb)&&(~i_valid)) // Newline reset
r_len <= 0;
else if (w_stb) // reset/restart w/o newline
r_len <= (i_stb)? 3'h1:3'h0;
else if (i_stb) //in middle of word
r_len <= r_len + 3'h1;
 
reg [35:0] shiftreg;
always @(posedge i_clk)
if (w_stb)
shiftreg[35:30] <= i_hexbits;
else if (i_stb) case(r_len)
3'b000: shiftreg[35:30] <= i_hexbits;
3'b001: shiftreg[29:24] <= i_hexbits;
3'b010: shiftreg[23:18] <= i_hexbits;
3'b011: shiftreg[17:12] <= i_hexbits;
3'b100: shiftreg[11: 6] <= i_hexbits;
3'b101: shiftreg[ 5: 0] <= i_hexbits;
default: begin end
endcase
 
always @(posedge i_clk)
if (o_stb)
lastcw <= o_codword[35:34];
always @(posedge i_clk)
if ((i_stb)&&(~i_valid)&&(lastcw == 2'b01))
o_codword[35:30] <= 6'h2e;
else
o_codword <= shiftreg;
 
// How long do we expect this codeword to be?
initial cw_len = 3'b000;
always @(posedge i_clk)
if ((i_stb)&&(~i_valid))
cw_len <= 0;
else if ((i_stb)&&((cw_len == 0)||(w_stb)))
begin
if (i_hexbits[5:4] == 2'b11) // 2b vector read
cw_len <= 3'h2;
else if (i_hexbits[5:4] == 2'b10) // 1b vector read
cw_len <= 3'h1;
else if (i_hexbits[5:3] == 3'b010) // 2b compressed wr
cw_len <= 3'h2;
else if (i_hexbits[5:3] == 3'b001) // 2b compressed addr
cw_len <= 3'b010 + { 1'b0, i_hexbits[2:1] };
else // long write or set address
cw_len <= 3'h6;
end else if (w_stb)
cw_len <= 0;
 
always @(posedge i_clk)
o_stb <= w_stb;
 
endmodule
 
/rtl/wbqspiflash.v
0,0 → 1,1202
///////////////////////////////////////////////////////////////////////////
//
// Filename: wbspiflash.v
//
// Project: Wishbone Controlled Quad SPI Flash Controller
//
// Purpose: Access a Quad SPI flash via a WISHBONE interface. This
// includes both read and write (and erase) commands to the SPI
// flash. All read/write commands are accomplished using the
// high speed (4-bit) interface. Further, the device will be
// left/kept in the 4-bit read interface mode between accesses,
// for a minimum read latency.
//
// Wishbone Registers (See spec sheet for more detail):
// 0: local config(r) / erase commands(w) / deep power down cmds / etc.
// R: (Write in Progress), (dirty-block), (spi_port_busy), 1'b0, 9'h00,
// { last_erased_sector, 14'h00 } if (WIP)
// else { current_sector_being_erased, 14'h00 }
// current if write in progress, last if written
// W: (1'b1 to erase), (12'h ignored), next_erased_block, 14'h ignored)
// 1: Configuration register
// 2: Status register (R/w)
// 3: Read ID (read only)
// (19 bits): Data (R/w, but expect writes to take a while)
//
//
// 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
//
//
///////////////////////////////////////////////////////////////////////////
//
`include "flash_config.v"
//
`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 wbqspiflash(i_clk,
// 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;
// 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,
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 qspi_full_stop;
always @(posedge i_clk)
qspi_full_stop <= ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr));
 
reg [7:0] last_status;
reg quad_mode_enabled;
reg spif_cmd, spif_override, wr_same_row, pipeline_read;
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)
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)
//
if ((i_wb_data_stb)&&(~i_wb_we)&&(~write_in_progress))
begin // Read access, normal mode(s)
o_wb_ack <= 1'b0;
o_wb_stall <= 1'b1;
spi_wr <= 1'b1; // Write cmd to device
spi_len <= 2'b11;
if (quad_mode_enabled)
begin
// spi_in <= { 8'heb, bus_address };
state <= `WBQSPI_QRD_ADDRESS;
end else begin
//spi_in <= { 8'h0b, bus_address };
state <= `WBQSPI_RD_DUMMY;
end
end else if((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_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'b0;
spi_len <= 2'b11;
// spi_in <= 32'h00;
state <= `WBQSPI_WBDECODE;
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_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 <= { bus_address, 8'ha0 };
state <= `WBQSPI_QRD_DUMMY;
end else if((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_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 (qspi_full_stop) // 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 <=pipeline_read;
// 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 (qspi_full_stop) // 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 (qspi_full_stop)
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 (qspi_full_stop)
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 (qspi_full_stop) // 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 (wr_same_row)
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, 6'h0, spif_data[1: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
 
 
wire [23:0] bus_address, reg_address;
generate
if (ADDRESS_WIDTH<24)
begin
assign bus_address = { {(24-ADDRESS_WIDTH){1'b0}},
i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
assign reg_address = { {(24-ADDRESS_WIDTH){1'b0}},
spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
end else begin
assign bus_address = { i_wb_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
assign reg_address = { spif_addr[(ADDRESS_WIDTH-3):0], 2'b00 };
end endgenerate
 
// Set the spi_in register, and that register only
always @(posedge i_clk)
begin
if (state == `WBQSPI_IDLE)
begin
if (quad_mode_enabled)
spi_in <= { 8'heb, bus_address };
else
spi_in <= { 8'h0b, bus_address };
end else if (state == `WBQSPI_RDIDLE)
begin
spi_in <= 32'h00;
if ((i_wb_data_stb)&&(~i_wb_we))
begin // Send the new address / mode
spi_in <= { bus_address, 8'ha0 };
end
end else if (state == `WBQSPI_WBDECODE)
begin
if ((~spi_busy)&&(o_qspi_cs_n)&&(~spi_wr)) // only in full idle ...
begin
// Data register access
if (~spif_ctrl)
begin
spi_in <= { 8'h06, 24'h00 };
end else if ((spif_ctrl)&&(spif_cmd))
begin
`ifdef READ_ONLY
`else
spi_in <= { 8'h06, 24'h00 };
`endif
end else begin // on (~spif_we)
case(spif_addr[1:0])
2'b00: ;// Read local register
2'b01: // Read configuration register
spi_in <= { 8'h35, 24'h00};
2'b10: // Read status register
spi_in <= { 8'h05, 24'h00};
2'b11: // Read ID register
spi_in <= { 8'h9f, 24'h00};
endcase
end
end
end else if (state == `WBQSPI_RD_DUMMY)
begin
spi_in <= { 8'h00, 24'h00 };
end else if (state == `WBQSPI_QRD_ADDRESS)
begin
spi_in <= { reg_address, 8'ha0 };
end else if (state == `WBQSPI_QRD_DUMMY)
begin
spi_in <= { 8'ha0, 24'h00 }; // Mode byte, then 2 bytes dummy
end else if (state == `WBQSPI_READ_CMD)
begin // Issue our first command to read 32 bits.
spi_in <= { 8'hff, 24'h00 }; // Empty
end else if (state == `WBQSPI_READ_DATA)
begin
spi_in <= 32'h00;
end else if (state == `WBQSPI_WAIT_TIL_RDIDLE)
begin // Wait 'til idle, but then go to fast read idle instead of full
end else if (state == `WBQSPI_READ_ID_CMD)
begin // We came into here immediately after issuing a 0x9f command
spi_in <= 32'h00; // Irrelevant
end else if (state == `WBQSPI_READ_ID)
begin
end else if (state == `WBQSPI_READ_STATUS)
begin // We enter after the command has been given, for now just
end else if (state == `WBQSPI_READ_CONFIG)
begin // We enter after the command has been given, for now just
`ifndef READ_ONLY
end else if (state == `WBQSPI_WAIT_WIP_CLEAR)
begin
if (~spi_busy)
spi_in <= { 8'h05, 24'h0000 };
end else if (state == `WBQSPI_CHECK_WIP_CLEAR)
begin
spi_in <= 32'h0000; // Values here are actually irrelevant
end else if (state == `WBQSPI_CHECK_WIP_DONE)
begin
if ((o_qspi_cs_n)&&(~spi_busy)) // Chip select line is high, we can continue
begin
// The bottom 24 bits are either don't cares, or the
// address we want. Set them to be the address always,
// to spare a touch on their logic.
spi_in <= { 8'heb, reg_address };
casez({ spif_cmd, spif_ctrl, spif_addr[1:0] })
4'b00??: begin // Read data from ... somewhere
if (quad_mode_enabled)
begin
spi_in[31:24] <= 8'heb;
end else begin
spi_in[31:24] <= 8'h0b;
end end
4'b10??: // Write data to ... anywhere
spi_in[31:24] <= 8'h06 ;
4'b0110: // Read status register
spi_in[31:24] <= 8'h05 ;
4'b0111:
spi_in[31:24] <= 8'h9f ;
default: begin //
end
endcase
end
end else if (state == `WBQSPI_WEN)
begin // We came here after issuing a write enable command
end else if (state == `WBQSPI_PP)
begin // We come here under a full stop / full port idle mode
spi_in <= { 8'h02, reg_address };
end else if (state == `WBQSPI_QPP)
begin // We come here under a full stop / full port idle mode
spi_in <= { 8'h32, reg_address };
end else if (state == `WBQSPI_WR_DATA)
begin
spi_in <= {
spif_data[ 7: 0],
spif_data[15: 8],
spif_data[23:16],
spif_data[31:24] };
end else if (state == `WBQSPI_WR_BUS_CYCLE)
begin
end else if (state == `WBQSPI_WRITE_CONFIG)
begin // We enter immediately after commanding a WEN
// spi_in <= { 8'h01, last_status, spif_data[7:0], 8'h00 };
spi_in <= { 8'h01, last_status, 6'h0, spif_data[1:0], 8'h00 };
end else if (state == `WBQSPI_WRITE_STATUS)
begin // We enter immediately after commanding a WEN
spi_in <= { 8'h01, spif_data[7:0], 16'h00 };
end else if (state == `WBQSPI_ERASE_CMD)
begin // Know that WIP is clear on entry, WEN has just been commanded
// Here's the erase command
spi_in <= { 8'hd8, 2'h0, spif_data[19:14], 14'h000, 2'b00 };
end else if (state == `WBQSPI_ERASE_BLOCK)
begin
end else if (state == `WBQSPI_CLEAR_STATUS)
begin // Issue a clear status command
spi_in <= { 8'h30, 24'h00 };
end else if (state == `WBQSPI_IDLE_CHECK_WIP)
begin // We are now in read status register mode
`endif // !READ_ONLY
end
end
 
 
initial wr_same_row = 1'b0;
always @(posedge i_clk)
wr_same_row <= ((i_wb_data_stb)&&(i_wb_we)
&&(i_wb_addr[5:0] == (spif_addr[5:0]+6'h1))
&&(i_wb_addr[(ADDRESS_WIDTH-3):6]
==spif_addr[(ADDRESS_WIDTH-3):6]));
initial pipeline_read = 1'b0;
always @(posedge i_clk)
pipeline_read <=((i_wb_data_stb)&&(~i_wb_we)&&(i_wb_addr== (spif_addr+1)));
 
// 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
/rtl/fastio.v
0,0 → 1,458
////////////////////////////////////////////////////////////////////////////////
//
// Filename: fastio.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose:
//
// 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
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`include "builddate.v"
//
module fastio(i_clk,
// Board level I/O
i_sw, i_btn, o_led,
o_clr_led0, o_clr_led1, o_clr_led2, o_clr_led3,
// Board level PMod I/O
i_aux_rx, o_aux_tx, o_aux_cts, i_gps_rx, o_gps_tx,
// i_gpio, o_gpio,
// Wishbone control
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr,
i_wb_data, o_wb_ack, o_wb_stall, o_wb_data,
// Cross-board I/O
i_rtc_ppd, i_buserr, i_other_ints, o_bus_int, o_board_ints);
parameter AUXUART_SETUP = 30'hd50, // 4M baud from 200MHz clock
GPSUART_SETUP = 30'hd20833; // 9600 baud from 200MHz clk
input i_clk;
// Board level I/O
input [3:0] i_sw;
input [3:0] i_btn;
output wire [3:0] o_led;
output reg [2:0] o_clr_led0;
output reg [2:0] o_clr_led1;
output reg [2:0] o_clr_led2;
output reg [2:0] o_clr_led3;
// Board level PMod I/O
//
// Auxilliary UART I/O
input i_aux_rx;
output wire o_aux_tx, o_aux_cts;
//
// GPS UART I/O
input i_gps_rx;
output wire o_gps_tx;
//
// GPIO
// input [(NGPI-1):0] i_gpio;
// output reg [(NGPO-1):0] o_gpio;
//
// Wishbone inputs
input i_wb_cyc, i_wb_stb, i_wb_we;
input [4:0] i_wb_addr;
input [31:0] i_wb_data;
// Wishbone outputs
output reg o_wb_ack;
output wire o_wb_stall;
output reg [31:0] o_wb_data;
// A strobe at midnight, to keep the calendar on "time"
input i_rtc_ppd;
// Address of the last bus error
input [31:0] i_buserr;
//
// Interrupts -- both the output bus interrupt, as well as those
// internally generated interrupts which may be used elsewhere
// in the design
input wire [8:0] i_other_ints;
output wire o_bus_int;
output wire [5:0] o_board_ints; // Button and switch interrupts
 
reg last_wb_stb;
reg [4:0] last_wb_addr;
reg [31:0] last_wb_data;
initial last_wb_stb = 1'b0;
always @(posedge i_clk)
begin
last_wb_addr <= i_wb_addr;
last_wb_data <= i_wb_data;
last_wb_stb <= (i_wb_stb)&&(i_wb_we);
end
 
wire [31:0] pic_data;
reg sw_int, btn_int;
wire pps_int, rtc_int, netrx_int, nettx_int,
auxrx_int, auxtx_int, gpio_int, flash_int, scop_int,
gpsrx_int, sd_int, oled_int, zip_int;
assign { zip_int, oled_int, rtc_int, sd_int,
nettx_int, netrx_int, scop_int, flash_int,
pps_int } = i_other_ints;
 
icontrol #(15) buspic(i_clk, 1'b0,
(last_wb_stb)&&(last_wb_addr==5'h1),
i_wb_data, pic_data,
{ zip_int, oled_int, sd_int,
gpsrx_int, scop_int, flash_int, gpio_int,
auxtx_int, auxrx_int, nettx_int, netrx_int,
rtc_int, pps_int, sw_int, btn_int },
o_bus_int);
 
//
// PWR Count
//
// A 32-bit counter that starts at power up and never resets. It's a
// read only counter if you will.
reg [31:0] pwr_counter;
initial pwr_counter = 32'h00;
always @(posedge i_clk)
pwr_counter <= pwr_counter+32'h001;
 
//
// BTNSW
//
// The button and switch control register
wire [31:0] w_btnsw;
reg [3:0] r_sw, swcfg, swnow, swlast;
reg [3:0] r_btn, btncfg, btnnow, btnlast, btnstate;
initial btn_int = 1'b0;
initial sw_int = 1'b0;
always @(posedge i_clk)
begin
r_sw <= i_sw;
swnow <= r_sw;
swlast<= swnow;
sw_int <= |((swnow^swlast)|swcfg);
 
if ((last_wb_stb)&&(last_wb_addr == 5'h4))
swcfg <= ((last_wb_data[3:0])&(last_wb_data[11:8]))
|((~last_wb_data[3:0])&(swcfg));
 
r_btn <= i_btn;
btnnow <= r_btn;
btn_int <= |(btnnow&btncfg);
if ((last_wb_stb)&&(last_wb_addr == 5'h4))
begin
btncfg <= ((last_wb_data[7:4])&(last_wb_data[15:12]))
|((~last_wb_data[7:4])&(btncfg));
btnstate<= (btnnow)|((btnstate)&(~last_wb_data[7:4]));
end else
btnstate <= (btnstate)|(btnnow);
end
assign w_btnsw = { 8'h00, btnnow, 4'h0, btncfg, swcfg, btnstate, swnow };
 
//
// LEDCTRL
//
reg [3:0] r_leds;
wire [31:0] w_ledreg;
reg last_cyc;
always @(posedge i_clk)
last_cyc <= i_wb_cyc;
initial r_leds = 4'h0;
always @(posedge i_clk)
if ((last_wb_stb)&&(last_wb_addr == 5'h5))
r_leds <= last_wb_data[3:0];
assign o_led = r_leds;
assign w_ledreg = { 28'h0, r_leds };
 
//
// GPIO
//
// Not used (yet), but this interface should allow us to control up to
// 16 GPIO inputs, and another 16 GPIO outputs. The interrupt trips
// when any of the inputs changes. (Sorry, which input isn't (yet)
// selectable.)
//
assign gpio_int = 1'b0;
 
//
// AUX (UART) SETUP
//
// Set us up for 4Mbaud, 8 data bits, no stop bits.
reg [29:0] aux_setup;
initial aux_setup = AUXUART_SETUP;
always @(posedge i_clk)
if ((last_wb_stb)&&(last_wb_addr == 5'h6))
aux_setup[29:0] <= last_wb_data[29:0];
 
//
// GPSSETUP
//
// Set us up for 9600 kbaud, 8 data bits, no stop bits.
reg [29:0] gps_setup;
initial gps_setup = GPSUART_SETUP;
always @(posedge i_clk)
if ((last_wb_stb)&&(last_wb_addr == 5'h7))
gps_setup[29:0] <= last_wb_data[29:0];
 
//
// CLR LEDs
//
 
// CLR LED 0
wire [31:0] w_clr_led0;
reg [8:0] r_clr_led0_r, r_clr_led0_g, r_clr_led0_b;
initial r_clr_led0_r = 9'h003; // Color LED on the far right
initial r_clr_led0_g = 9'h000;
initial r_clr_led0_b = 9'h000;
always @(posedge i_clk)
if ((last_wb_stb)&&(last_wb_addr == 5'h8))
begin
r_clr_led0_r <= { last_wb_data[26], last_wb_data[23:16] };
r_clr_led0_g <= { last_wb_data[25], last_wb_data[15: 8] };
r_clr_led0_b <= { last_wb_data[24], last_wb_data[ 7: 0] };
end
assign w_clr_led0 = { 5'h0,
r_clr_led0_r[8], r_clr_led0_g[8], r_clr_led0_b[8],
r_clr_led0_r[7:0], r_clr_led0_g[7:0], r_clr_led0_b[7:0]
};
always @(posedge i_clk)
o_clr_led0 <= { (pwr_counter[8:0] < r_clr_led0_r),
(pwr_counter[8:0] < r_clr_led0_g),
(pwr_counter[8:0] < r_clr_led0_b) };
 
// CLR LED 1
wire [31:0] w_clr_led1;
reg [8:0] r_clr_led1_r, r_clr_led1_g, r_clr_led1_b;
initial r_clr_led1_r = 9'h007;
initial r_clr_led1_g = 9'h000;
initial r_clr_led1_b = 9'h000;
always @(posedge i_clk)
if ((last_wb_stb)&&(last_wb_addr == 5'h9))
begin
r_clr_led1_r <= { last_wb_data[26], last_wb_data[23:16] };
r_clr_led1_g <= { last_wb_data[25], last_wb_data[15: 8] };
r_clr_led1_b <= { last_wb_data[24], last_wb_data[ 7: 0] };
end
assign w_clr_led1 = { 5'h0,
r_clr_led1_r[8], r_clr_led1_g[8], r_clr_led1_b[8],
r_clr_led1_r[7:0], r_clr_led1_g[7:0], r_clr_led1_b[7:0]
};
always @(posedge i_clk)
o_clr_led1 <= { (pwr_counter[8:0] < r_clr_led1_r),
(pwr_counter[8:0] < r_clr_led1_g),
(pwr_counter[8:0] < r_clr_led1_b) };
// CLR LED 0
wire [31:0] w_clr_led2;
reg [8:0] r_clr_led2_r, r_clr_led2_g, r_clr_led2_b;
initial r_clr_led2_r = 9'h00f;
initial r_clr_led2_g = 9'h000;
initial r_clr_led2_b = 9'h000;
always @(posedge i_clk)
if ((last_wb_stb)&&(last_wb_addr == 5'ha))
begin
r_clr_led2_r <= { last_wb_data[26], last_wb_data[23:16] };
r_clr_led2_g <= { last_wb_data[25], last_wb_data[15: 8] };
r_clr_led2_b <= { last_wb_data[24], last_wb_data[ 7: 0] };
end
assign w_clr_led2 = { 5'h0,
r_clr_led2_r[8], r_clr_led2_g[8], r_clr_led2_b[8],
r_clr_led2_r[7:0], r_clr_led2_g[7:0], r_clr_led2_b[7:0]
};
always @(posedge i_clk)
o_clr_led2 <= { (pwr_counter[8:0] < r_clr_led2_r),
(pwr_counter[8:0] < r_clr_led2_g),
(pwr_counter[8:0] < r_clr_led2_b) };
// CLR LED 3
wire [31:0] w_clr_led3;
reg [8:0] r_clr_led3_r, r_clr_led3_g, r_clr_led3_b;
initial r_clr_led3_r = 9'h01f; // LED is on far left
initial r_clr_led3_g = 9'h000;
initial r_clr_led3_b = 9'h000;
always @(posedge i_clk)
if ((last_wb_stb)&&(last_wb_addr == 5'hb))
begin
r_clr_led3_r <= { last_wb_data[26], last_wb_data[23:16] };
r_clr_led3_g <= { last_wb_data[25], last_wb_data[15: 8] };
r_clr_led3_b <= { last_wb_data[24], last_wb_data[ 7: 0] };
end
assign w_clr_led3 = { 5'h0,
r_clr_led3_r[8], r_clr_led3_g[8], r_clr_led3_b[8],
r_clr_led3_r[7:0], r_clr_led3_g[7:0], r_clr_led3_b[7:0]
};
always @(posedge i_clk)
o_clr_led3 <= { (pwr_counter[8:0] < r_clr_led3_r),
(pwr_counter[8:0] < r_clr_led3_g),
(pwr_counter[8:0] < r_clr_led3_b) };
 
//
// The Calendar DATE
//
wire [31:0] date_data;
`define GET_DATE
`ifdef GET_DATE
wire date_ack, date_stall;
rtcdate thedate(i_clk, i_rtc_ppd,
i_wb_cyc, last_wb_stb, (last_wb_addr==5'hc), last_wb_data,
date_ack, date_stall, date_data);
`else
assign date_data = 32'h20160000;
`endif
 
//////
//
// The auxilliary UART
//
//////
 
// First the receiver
wire auxrx_stb, auxrx_break, auxrx_perr, auxrx_ferr, auxck_uart;
wire [7:0] rx_data_aux_port;
rxuart auxrx(i_clk, 1'b0, aux_setup, i_aux_rx,
auxrx_stb, rx_data_aux_port, auxrx_break,
auxrx_perr, auxrx_ferr, auxck_uart);
 
wire [31:0] auxrx_data;
reg [11:0] r_auxrx_data;
always @(posedge i_clk)
if (auxrx_stb)
begin
r_auxrx_data[11] <= auxrx_break;
r_auxrx_data[10] <= auxrx_ferr;
r_auxrx_data[ 9] <= auxrx_perr;
r_auxrx_data[7:0]<= rx_data_aux_port;
end
always @(posedge i_clk)
if(((i_wb_stb)&&(~i_wb_we)&&(i_wb_addr == 5'h0d))||(auxrx_stb))
r_auxrx_data[8] <= auxrx_stb;
assign o_aux_cts = auxrx_stb;
assign auxrx_data = { 20'h00, r_auxrx_data };
assign auxrx_int = r_auxrx_data[8];
 
 
// Then the transmitter
wire auxtx_busy;
reg [7:0] r_auxtx_data;
reg r_auxtx_stb, r_auxtx_break;
wire [31:0] auxtx_data;
txuart auxtx(i_clk, 1'b0, aux_setup,
r_auxtx_break, r_auxtx_stb, r_auxtx_data,
o_aux_tx, auxtx_busy);
always @(posedge i_clk)
if ((last_wb_stb)&&(last_wb_addr == 5'h0e))
begin
r_auxtx_stb <= 1'b1;
r_auxtx_data <= last_wb_data[7:0];
r_auxtx_break<= last_wb_data[9];
end else if (~auxtx_busy)
begin
r_auxtx_stb <= 1'b0;
r_auxtx_data <= 8'h0;
end
assign auxtx_data = { 20'h00,
auxck_uart, o_aux_tx, r_auxtx_break, auxtx_busy,
r_auxtx_data };
assign auxtx_int = ~auxtx_busy;
 
//////
//
// The GPS UART
//
//////
 
// First the receiver
wire gpsrx_stb, gpsrx_break, gpsrx_perr, gpsrx_ferr, gpsck_uart;
wire [7:0] rx_data_gps_port;
rxuart gpsrx(i_clk, 1'b0, gps_setup, i_gps_rx,
gpsrx_stb, rx_data_gps_port, gpsrx_break,
gpsrx_perr, gpsrx_ferr, gpsck_uart);
 
wire [31:0] gpsrx_data;
reg [11:0] r_gpsrx_data;
always @(posedge i_clk)
if (gpsrx_stb)
begin
r_gpsrx_data[11] <= gpsrx_break;
r_gpsrx_data[10] <= gpsrx_ferr;
r_gpsrx_data[ 9] <= gpsrx_perr;
r_gpsrx_data[7:0]<= rx_data_gps_port;
end
always @(posedge i_clk)
if(((i_wb_stb)&&(~i_wb_we)&&(i_wb_addr == 5'h0d))||(gpsrx_stb))
r_gpsrx_data[8] <= gpsrx_stb;
assign gpsrx_data = { 20'h00, r_gpsrx_data };
assign gpsrx_int = r_gpsrx_data[8];
 
 
// Then the transmitter
reg r_gpstx_break, r_gpstx_stb;
reg [7:0] r_gpstx_data;
wire gpstx_busy;
wire [31:0] gpstx_data;
txuart gpstx(i_clk, 1'b0, gps_setup,
r_gpstx_break, r_gpstx_stb, r_gpstx_data,
o_gps_tx, gpstx_busy);
always @(posedge i_clk)
if ((last_wb_stb)&&(last_wb_addr == 5'h0e))
begin
r_gpstx_stb <= 1'b1;
r_gpstx_data <= last_wb_data[7:0];
r_gpstx_break<= last_wb_data[9];
end else if (~gpstx_busy)
begin
r_gpstx_stb <= 1'b0;
r_gpstx_data <= 8'h0;
end
assign gpstx_data = { 20'h00,
gpsck_uart, o_gps_tx, r_gpstx_break, gpstx_busy,
r_gpstx_data };
 
always @(posedge i_clk)
case(i_wb_addr)
5'h00: o_wb_data <= `DATESTAMP;
5'h01: o_wb_data <= pic_data;
5'h02: o_wb_data <= i_buserr;
5'h03: o_wb_data <= pwr_counter;
5'h04: o_wb_data <= w_btnsw;
5'h05: o_wb_data <= w_ledreg;
5'h06: o_wb_data <= { 2'b00, aux_setup };
5'h07: o_wb_data <= { 2'b00, gps_setup };
5'h08: o_wb_data <= w_clr_led0;
5'h09: o_wb_data <= w_clr_led1;
5'h0a: o_wb_data <= w_clr_led2;
5'h0b: o_wb_data <= w_clr_led3;
5'h0c: o_wb_data <= date_data;
5'h0d: o_wb_data <= auxrx_data;
5'h0e: o_wb_data <= auxtx_data;
5'h10: o_wb_data <= gpsrx_data;
5'h11: o_wb_data <= gpstx_data;
// 5'hf: UART_SETUP
// 4'h6: GPIO
// ?? : GPS-UARTRX
// ?? : GPS-UARTTX
default: o_wb_data <= 32'h00;
endcase
 
assign o_wb_stall = 1'b0;
always @(posedge i_clk)
o_wb_ack <= (i_wb_stb);
assign o_board_ints = { gpio_int, auxrx_int, auxtx_int, gpsrx_int, sw_int, btn_int };
 
 
endmodule
/rtl/rxuart.v
0,0 → 1,330
////////////////////////////////////////////////////////////////////////////////
//
// Filename: rxuart.v
//
// Project: FPGA library
//
// Purpose: Receive and decode inputs from a single UART line.
//
//
// To interface with this module, connect it to your system clock,
// pass it the 32 bit setup register (defined below) and the UART
// input. When data becomes available, the o_wr line will be asserted
// for one clock cycle. On parity or frame errors, the o_parity_err
// or o_frame_err lines will be asserted. Likewise, on a break
// condition, o_break will be asserted. These lines are self clearing.
//
// There is a synchronous reset line, logic high.
//
// Now for the setup register. The register is 32 bits, so that this
// UART may be set up over a 32-bit bus.
//
// i_setup[29:28] Indicates the number of data bits per word. This will
// either be 2'b00 for an 8-bit word, 2'b01 for a 7-bit word, 2'b10
// for a six bit word, or 2'b11 for a five bit word.
//
// i_setup[27] Indicates whether or not to use one or two stop bits.
// Set this to one to expect two stop bits, zero for one.
//
// i_setup[26] Indicates whether or not a parity bit exists. Set this
// to 1'b1 to include parity.
//
// i_setup[25] Indicates whether or not the parity bit is fixed. Set
// to 1'b1 to include a fixed bit of parity, 1'b0 to allow the
// parity to be set based upon data. (Both assume the parity
// enable value is set.)
//
// i_setup[24] This bit is ignored if parity is not used. Otherwise,
// in the case of a fixed parity bit, this bit indicates whether
// mark (1'b1) or space (1'b0) parity is used. Likewise if the
// parity is not fixed, a 1'b1 selects even parity, and 1'b0
// selects odd.
//
// i_setup[23:0] Indicates the speed of the UART in terms of clocks.
// So, for example, if you have a 200 MHz clock and wish to
// run your UART at 9600 baud, you would take 200 MHz and divide
// by 9600 to set this value to 24'd20834. Likewise if you wished
// to run this serial port at 115200 baud from a 200 MHz clock,
// you would set the value to 24'd1736
//
// Thus, to set the UART for the common setting of an 8-bit word,
// one stop bit, no parity, and 115200 baud over a 200 MHz clock, you
// would want to set the setup value to:
//
// 32'h0006c8 // For 115,200 baud, 8 bit, no parity
// 32'h005161 // For 9600 baud, 8 bit, no parity
//
//
//
// 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
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
// States: (@ baud counter == 0)
// 0 First bit arrives
// ..7 Bits arrive
// 8 Stop bit (x1)
// 9 Stop bit (x2)
/// c break condition
// d Waiting for the channel to go high
// e Waiting for the reset to complete
// f Idle state
`define RXU_BIT_ZERO 4'h0
`define RXU_BIT_ONE 4'h1
`define RXU_BIT_TWO 4'h2
`define RXU_BIT_THREE 4'h3
`define RXU_BIT_FOUR 4'h4
`define RXU_BIT_FIVE 4'h5
`define RXU_BIT_SIX 4'h6
`define RXU_BIT_SEVEN 4'h7
`define RXU_PARITY 4'h8
`define RXU_STOP 4'h9
`define RXU_SECOND_STOP 4'ha
// Unused 4'hb
// Unused 4'hc
`define RXU_BREAK 4'hd
`define RXU_RESET_IDLE 4'he
`define RXU_IDLE 4'hf
 
module rxuart(i_clk, i_reset, i_setup, i_uart, o_wr, o_data, o_break,
o_parity_err, o_frame_err, o_ck_uart);
// parameter // CLOCKS_PER_BAUD = 25'd004340,
// BREAK_CONDITION = CLOCKS_PER_BAUD * 12,
// CLOCKS_PER_HALF_BAUD = CLOCKS_PER_BAUD/2;
// 8 data bits, no parity, (at least 1) stop bit
input i_clk, i_reset;
input [29:0] i_setup;
input i_uart;
output reg o_wr;
output reg [7:0] o_data;
output reg o_break;
output reg o_parity_err, o_frame_err;
output wire o_ck_uart;
 
 
wire [27:0] clocks_per_baud, break_condition, half_baud;
wire [1:0] data_bits;
wire use_parity, parity_even, dblstop, fixd_parity;
reg [29:0] r_setup;
assign clocks_per_baud = { 4'h0, r_setup[23:0] };
assign data_bits = r_setup[29:28];
assign dblstop = r_setup[27];
assign use_parity = r_setup[26];
assign fixd_parity = r_setup[25];
assign parity_even = r_setup[24];
assign break_condition = { r_setup[23:0], 4'h0 };
assign half_baud = { 5'h00, r_setup[23:1] };
 
reg q_uart, qq_uart, ck_uart;
initial q_uart = 1'b0;
initial qq_uart = 1'b0;
initial ck_uart = 1'b0;
always @(posedge i_clk)
begin
q_uart <= i_uart;
qq_uart <= q_uart;
ck_uart <= qq_uart;
end
assign o_ck_uart = ck_uart;
 
reg [27:0] chg_counter;
initial chg_counter = 28'h00;
always @(posedge i_clk)
if (i_reset)
chg_counter <= 28'h00;
else if (qq_uart != ck_uart)
chg_counter <= 28'h00;
else if (chg_counter < break_condition)
chg_counter <= chg_counter + 1;
 
reg line_synch;
initial line_synch = 1'b0;
initial o_break = 1'b0;
always @(posedge i_clk)
o_break <= ((chg_counter >= break_condition)&&(~ck_uart))? 1'b1:1'b0;
always @(posedge i_clk)
line_synch <= ((chg_counter >= break_condition)&&(ck_uart));
 
reg [3:0] state;
reg [27:0] baud_counter;
reg [7:0] data_reg;
reg calc_parity, zero_baud_counter, half_baud_time;
initial o_wr = 1'b0;
initial state = `RXU_RESET_IDLE;
initial o_parity_err = 1'b0;
initial o_frame_err = 1'b0;
// initial baud_counter = clocks_per_baud;
always @(posedge i_clk)
begin
if (i_reset)
begin
o_wr <= 1'b0;
o_data <= 8'h00;
state <= `RXU_RESET_IDLE;
baud_counter <= clocks_per_baud-28'h01;// Set, not reset
data_reg <= 8'h00;
calc_parity <= 1'b0;
o_parity_err <= 1'b0;
o_frame_err <= 1'b0;
end else if (state == `RXU_RESET_IDLE)
begin
r_setup <= i_setup;
data_reg <= 8'h00; o_data <= 8'h00; o_wr <= 1'b0;
baud_counter <= clocks_per_baud-28'h01;// Set, not reset
if (line_synch)
// Goto idle state from a reset
state <= `RXU_IDLE;
else // Otherwise, stay in this condition 'til reset
state <= `RXU_RESET_IDLE;
calc_parity <= 1'b0;
o_parity_err <= 1'b0;
o_frame_err <= 1'b0;
end else if (o_break)
begin // We are in a break condition
state <= `RXU_BREAK;
o_wr <= 1'b0;
o_data <= 8'h00;
baud_counter <= clocks_per_baud-28'h01;// Set, not reset
data_reg <= 8'h00;
calc_parity <= 1'b0;
o_parity_err <= 1'b0;
o_frame_err <= 1'b0;
r_setup <= i_setup;
end else if (state == `RXU_BREAK)
begin // Goto idle state following return ck_uart going high
data_reg <= 8'h00; o_data <= 8'h00; o_wr <= 1'b0;
baud_counter <= clocks_per_baud - 28'h01;
if (ck_uart)
state <= `RXU_IDLE;
else
state <= `RXU_BREAK;
calc_parity <= 1'b0;
o_parity_err <= 1'b0;
o_frame_err <= 1'b0;
r_setup <= i_setup;
end else if (state == `RXU_IDLE)
begin // Idle state, independent of baud counter
r_setup <= i_setup;
data_reg <= 8'h00; o_data <= 8'h00; o_wr <= 1'b0;
baud_counter <= clocks_per_baud - 28'h01;
if ((~ck_uart)&&(half_baud_time))
begin
// We are in the center of a valid start bit
case (data_bits)
2'b00: state <= `RXU_BIT_ZERO;
2'b01: state <= `RXU_BIT_ONE;
2'b10: state <= `RXU_BIT_TWO;
2'b11: state <= `RXU_BIT_THREE;
endcase
end else // Otherwise, just stay here in idle
state <= `RXU_IDLE;
calc_parity <= 1'b0;
o_parity_err <= 1'b0;
o_frame_err <= 1'b0;
end else if (zero_baud_counter)
begin
baud_counter <= clocks_per_baud-28'h1;
if (state < `RXU_BIT_SEVEN)
begin
// Data arrives least significant bit first.
// By the time this is clocked in, it's what
// you'll have.
data_reg <= { ck_uart, data_reg[7:1] };
calc_parity <= calc_parity ^ ck_uart;
o_data <= 8'h00;
o_wr <= 1'b0;
state <= state + 1;
o_parity_err <= 1'b0;
o_frame_err <= 1'b0;
end else if (state == `RXU_BIT_SEVEN)
begin
data_reg <= { ck_uart, data_reg[7:1] };
calc_parity <= calc_parity ^ ck_uart;
o_data <= 8'h00;
o_wr <= 1'b0;
state <= (use_parity) ? `RXU_PARITY:`RXU_STOP;
o_parity_err <= 1'b0;
o_frame_err <= 1'b0;
end else if (state == `RXU_PARITY)
begin
if (fixd_parity)
o_parity_err <= (ck_uart ^ parity_even);
else
o_parity_err <= ((parity_even && (calc_parity != ck_uart))
||((~parity_even)&&(calc_parity==ck_uart)));
state <= `RXU_STOP;
o_frame_err <= 1'b0;
end else if (state == `RXU_STOP)
begin // Stop (or parity) bit(s)
case (data_bits)
2'b00: o_data <= data_reg;
2'b01: o_data <= { 1'b0, data_reg[7:1] };
2'b10: o_data <= { 2'b0, data_reg[7:2] };
2'b11: o_data <= { 3'b0, data_reg[7:3] };
endcase
o_wr <= 1'b1; // Pulse the write
o_frame_err <= (~ck_uart);
if (~ck_uart)
state <= `RXU_RESET_IDLE;
else if (dblstop)
state <= `RXU_SECOND_STOP;
else
state <= `RXU_IDLE;
// o_parity_err <= 1'b0;
end else // state must equal RX_SECOND_STOP
begin
if (~ck_uart)
begin
o_frame_err <= 1'b1;
state <= `RXU_RESET_IDLE;
end else begin
state <= `RXU_IDLE;
o_frame_err <= 1'b0;
end
o_parity_err <= 1'b0;
end
end else begin
o_wr <= 1'b0; // data_reg = data_reg
baud_counter <= baud_counter - 28'd1;
o_parity_err <= 1'b0;
o_frame_err <= 1'b0;
end
end
 
initial zero_baud_counter = 1'b0;
always @(posedge i_clk)
zero_baud_counter <= (baud_counter == 28'h01);
 
initial half_baud_time = 0;
always @(posedge i_clk)
half_baud_time <= (~ck_uart)&&(chg_counter >= half_baud);
 
 
endmodule
 
 
/rtl/txuart.v
0,0 → 1,252
////////////////////////////////////////////////////////////////////////////////
//
// Filename: txuart.v
//
// Project: FPGA library
//
// Purpose: Transmit outputs over a single UART line.
//
// To interface with this module, connect it to your system clock,
// pass it the 32 bit setup register (defined below) and the byte
// of data you wish to transmit. Strobe the i_wr line high for one
// clock cycle, and your data will be off. Wait until the 'o_busy'
// line is low before strobing the i_wr line again--this implementation
// has NO BUFFER, so strobing i_wr while the core is busy will just
// cause your data to be lost. The output will be placed on the o_txuart
// output line. If you wish to set/send a break condition, assert the
// i_break line otherwise leave it low.
//
// There is a synchronous reset line, logic high.
//
// Now for the setup register. The register is 32 bits, so that this
// UART may be set up over a 32-bit bus.
//
// i_setup[29:28] Indicates the number of data bits per word. This will
// either be 2'b00 for an 8-bit word, 2'b01 for a 7-bit word, 2'b10
// for a six bit word, or 2'b11 for a five bit word.
//
// i_setup[27] Indicates whether or not to use one or two stop bits.
// Set this to one to expect two stop bits, zero for one.
//
// i_setup[26] Indicates whether or not a parity bit exists. Set this
// to 1'b1 to include parity.
//
// i_setup[25] Indicates whether or not the parity bit is fixed. Set
// to 1'b1 to include a fixed bit of parity, 1'b0 to allow the
// parity to be set based upon data. (Both assume the parity
// enable value is set.)
//
// i_setup[24] This bit is ignored if parity is not used. Otherwise,
// in the case of a fixed parity bit, this bit indicates whether
// mark (1'b1) or space (1'b0) parity is used. Likewise if the
// parity is not fixed, a 1'b1 selects even parity, and 1'b0
// selects odd.
//
// i_setup[23:0] Indicates the speed of the UART in terms of clocks.
// So, for example, if you have a 200 MHz clock and wish to
// run your UART at 9600 baud, you would take 200 MHz and divide
// by 9600 to set this value to 24'd20834. Likewise if you wished
// to run this serial port at 115200 baud from a 200 MHz clock,
// you would set the value to 24'd1736
//
// Thus, to set the UART for the common setting of an 8-bit word,
// one stop bit, no parity, and 115200 baud over a 200 MHz clock, you
// would want to set the setup value to:
//
// 32'h0006c8 // For 115,200 baud, 8 bit, no parity
// 32'h005161 // For 9600 baud, 8 bit, no parity
//
//
//
// 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
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
`define TXU_BIT_ZERO 4'h0
`define TXU_BIT_ONE 4'h1
`define TXU_BIT_TWO 4'h2
`define TXU_BIT_THREE 4'h3
`define TXU_BIT_FOUR 4'h4
`define TXU_BIT_FIVE 4'h5
`define TXU_BIT_SIX 4'h6
`define TXU_BIT_SEVEN 4'h7
`define TXU_PARITY 4'h8 // Constant 1
`define TXU_STOP 4'h9 // Constant 1
`define TXU_SECOND_STOP 4'ha
// 4'hb // Unused
// 4'hc // Unused
// `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);
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;
output wire o_busy;
 
wire [27:0] clocks_per_baud, break_condition;
wire [1:0] data_bits;
wire use_parity, parity_even, dblstop, fixd_parity;
reg [29:0] r_setup;
assign clocks_per_baud = { 4'h0, r_setup[23:0] };
assign break_condition = { r_setup[23:0], 4'h0 };
assign data_bits = r_setup[29:28];
assign dblstop = r_setup[27];
assign use_parity = r_setup[26];
assign fixd_parity = r_setup[25];
assign parity_even = r_setup[24];
 
reg [27:0] baud_counter;
reg [3:0] state;
reg [7:0] lcl_data;
reg calc_parity, r_busy, zero_baud_counter;
 
initial o_uart = 1'b1;
initial r_busy = 1'b1;
initial state = `TXU_IDLE;
initial lcl_data= 8'h0;
initial calc_parity = 1'b0;
// initial baud_counter = clocks_per_baud;//ILLEGAL--not constant
always @(posedge i_clk)
begin
if (i_reset)
begin
o_uart <= 1'b1;
r_busy <= 1'b1;
state <= `TXU_IDLE;
lcl_data <= 8'h0;
calc_parity <= 1'b0;
end else if (i_break)
begin
o_uart <= 1'b0;
state <= `TXU_BREAK;
calc_parity <= 1'b0;
r_busy <= 1'b1;
end else if (~zero_baud_counter)
begin // r_busy needs to be set coming into here
r_busy <= 1'b1;
end else if (state == `TXU_BREAK)
begin
state <= `TXU_IDLE;
r_busy <= 1'b1;
o_uart <= 1'b1;
calc_parity <= 1'b0;
end else if (state == `TXU_IDLE) // STATE_IDLE
begin
// baud_counter <= 0;
r_setup <= i_setup;
calc_parity <= 1'b0;
if ((i_wr)&&(~r_busy))
begin // Immediately start us off with a start bit
o_uart <= 1'b0;
r_busy <= 1'b1;
case(data_bits)
2'b00: state <= `TXU_BIT_ZERO;
2'b01: state <= `TXU_BIT_ONE;
2'b10: state <= `TXU_BIT_TWO;
2'b11: state <= `TXU_BIT_THREE;
endcase
lcl_data <= i_data;
// baud_counter <= clocks_per_baud-28'h01;
end else begin // Stay in idle
o_uart <= 1'b1;
r_busy <= 0;
// lcl_data is irrelevant
// state <= state;
end
end else begin
// One clock tick in each of these states ...
// baud_counter <= clocks_per_baud - 28'h01;
r_busy <= 1'b1;
if (state[3] == 0) // First 8 bits
begin
o_uart <= lcl_data[0];
calc_parity <= calc_parity ^ lcl_data[0];
if (state == `TXU_BIT_SEVEN)
state <= (use_parity)?`TXU_PARITY:`TXU_STOP;
else
state <= state + 1;
lcl_data <= { 1'b0, lcl_data[7:1] };
end else if (state == `TXU_PARITY)
begin
state <= `TXU_STOP;
if (fixd_parity)
o_uart <= parity_even;
else
o_uart <= calc_parity^((parity_even)? 1'b1:1'b0);
end else if (state == `TXU_STOP)
begin // two stop bit(s)
o_uart <= 1'b1;
if (dblstop)
state <= `TXU_SECOND_STOP;
else
state <= `TXU_IDLE;
calc_parity <= 1'b0;
end else // `TXU_SECOND_STOP and default:
begin
state <= `TXU_IDLE; // Go back to idle
o_uart <= 1'b1;
// Still r_busy, since we need to wait
// for the baud clock to finish counting
// out this last bit.
end
end
end
 
assign o_busy = (r_busy);
 
 
initial zero_baud_counter = 1'b0;
always @(posedge i_clk)
begin
zero_baud_counter <= (baud_counter == 28'h01);
if ((i_reset)||(i_break))
// Give ourselves 16 bauds before being ready
baud_counter <= break_condition;
else if (~zero_baud_counter)
baud_counter <= baud_counter - 28'h01;
else if (state == `TXU_BREAK)
// Give us two stop bits before becoming available
baud_counter <= clocks_per_baud<<2;
else if (state == `TXU_IDLE)
begin
if((i_wr)&&(~r_busy))
baud_counter <= clocks_per_baud - 28'h01;
else
zero_baud_counter <= 1'b1;
end else
baud_counter <= clocks_per_baud - 28'h01;
end
endmodule
 
/rtl/icontrol.v
0,0 → 1,153
////////////////////////////////////////////////////////////////////////////////
//
// Filename: icontrol.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: An interrupt controller, for managing many interrupt sources.
//
// This interrupt controller started from the question of how best to
// design a simple interrupt controller. As such, it has a few nice
// qualities to it:
// 1. This is wishbone compliant
// 2. It sits on a 32-bit wishbone data bus
// 3. It only consumes one address on that wishbone bus.
// 4. There is no extra delays associated with reading this
// device.
// 5. Common operations can all be done in one clock.
//
// So, how shall this be used? First, the 32-bit word is broken down as
// follows:
//
// Bit 31 - This is the global interrupt enable bit. If set, interrupts
// will be generated and passed on as they come in.
// Bits 16-30 - These are specific interrupt enable lines. If set,
// interrupts from source (bit#-16) will be enabled.
// To set this line and enable interrupts from this source, write
// to the register with this bit set and the global enable set.
// To disable this line, write to this register with global enable
// bit not set, but this bit set. (Writing a zero to any of these
// bits has no effect, either setting or unsetting them.)
// Bit 15 - This is the any interrupt pin. If any interrupt is pending,
// this bit will be set.
// Bits 0-14 - These are interrupt bits. When set, an interrupt is
// pending from the corresponding source--regardless of whether
// it was enabled. (If not enabled, it won't generate an
// interrupt, but it will still register here.) To clear any
// of these bits, write a '1' to the corresponding bit. Writing
// a zero to any of these bits has no effect.
//
// The peripheral also sports a parameter, IUSED, which can be set
// to any value between 1 and (buswidth/2-1, or) 15 inclusive. This will
// be the number of interrupts handled by this routine. (Without the
// parameter, Vivado was complaining about unused bits. With it, we can
// keep the complaints down and still use the routine).
//
// To get access to more than 15 interrupts, chain these together, so
// that one interrupt controller device feeds another.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
module icontrol(i_clk, i_reset, i_wr, i_proc_bus, o_proc_bus,
i_brd_ints, o_interrupt);
parameter IUSED = 15;
input i_clk, i_reset;
input i_wr;
input [31:0] i_proc_bus;
output wire [31:0] o_proc_bus;
input [(IUSED-1):0] i_brd_ints;
output wire o_interrupt;
 
reg [(IUSED-1):0] r_int_state;
reg [(IUSED-1):0] r_int_enable;
wire [(IUSED-1):0] nxt_int_state;
reg r_any, r_interrupt, r_gie;
 
assign nxt_int_state = (r_int_state|i_brd_ints);
initial r_int_state = 0;
always @(posedge i_clk)
if (i_reset)
r_int_state <= 0;
else if (i_wr)
r_int_state <= nxt_int_state & (~i_proc_bus[(IUSED-1):0]);
else
r_int_state <= nxt_int_state;
initial r_int_enable = 0;
always @(posedge i_clk)
if (i_reset)
r_int_enable <= 0;
else if ((i_wr)&&(i_proc_bus[31]))
r_int_enable <= r_int_enable | i_proc_bus[(16+IUSED-1):16];
else if ((i_wr)&&(~i_proc_bus[31]))
r_int_enable <= r_int_enable & (~ i_proc_bus[(16+IUSED-1):16]);
 
initial r_gie = 1'b0;
always @(posedge i_clk)
if (i_reset)
r_gie <= 1'b0;
else if (i_wr)
r_gie <= i_proc_bus[31];
 
initial r_any = 1'b0;
always @(posedge i_clk)
r_any <= ((r_int_state & r_int_enable) != 0);
initial r_interrupt = 1'b0;
always @(posedge i_clk)
r_interrupt <= r_gie & r_any;
 
generate
if (IUSED < 15)
begin
assign o_proc_bus = {
r_gie, { {(15-IUSED){1'b0}}, r_int_enable },
r_any, { {(15-IUSED){1'b0}}, r_int_state } };
end else begin
assign o_proc_bus = { r_gie, r_int_enable, r_any, r_int_state };
end endgenerate
 
/*
reg int_condition;
initial int_condition = 1'b0;
initial o_interrupt_strobe = 1'b0;
always @(posedge i_clk)
if (i_reset)
begin
int_condition <= 1'b0;
o_interrupt_strobe <= 1'b0;
end else if (~r_interrupt) // This might end up generating
begin // many, many, (wild many) interrupts
int_condition <= 1'b0;
o_interrupt_strobe <= 1'b0;
end else if ((~int_condition)&&(r_interrupt))
begin
int_condition <= 1'b1;
o_interrupt_strobe <= 1'b1;
end else
o_interrupt_strobe <= 1'b0;
*/
 
assign o_interrupt = r_interrupt;
 
endmodule
/rtl/builddate.v
0,0 → 1,41
////////////////////////////////////////////////////////////////////////////////
//
// Filename: builddate.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: This file records the date of the last build. Running "make"
// in the main directory will create this file. The `define found
// within it then creates a version stamp that can be used to tell which
// configuration is within an FPGA and so forth.
//
// 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
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`define DATESTAMP 32'h20160725
/rtl/wbscopc.v
0,0 → 1,220
///////////////////////////////////////////////////////////////////////////
//
// Filename: wbscopc.v
//
// Project: FPGA Library of Routines
//
// Purpose: This scope is identical in function to the wishbone scope
// found in wbscope, save that the output is compressed and that (as a
// result) it can only handle recording 31 bits at a time. This allows
// the top bit to indicate an 'address difference'. Okay, there's
// another difference as well: this version only works in a synchronous
// fashion with the clock from the WB bus. You cannot have a separate
// bus and data clock.
//
// Reading/decompressing the output of this scope works in this fashion:
// Once the scope has stopped, read from the port. Any time the high
// order bit is set, the other 31 bits tell you how many times to repeat
// the last value. If the high order bit is not set, then the value
// is a new data value.
//
// I've provided this version of a compressed scope to OpenCores for
// discussion purposes. While wbscope.v works and works well by itself,
// this compressed scope has a couple of fundamental flaw that I have
// yet to fix. One of them is that it is impossible to know when the
// trigger took place. The second problem is that it may be impossible
// to know the state of the scope at the beginning of the buffer--should
// the buffer begin with an address difference value instead of a data
// value.
//
// Ideally, the first item read out of the scope should be a data value,
// even if the scope was skipping values to a new address at the time.
// If it was in the middle of a skip, the next item out of the scope
// should be the skip length. This, though, violates the rule that there
// are (1<<LGMEMLEN) items in the memory, and that the trigger took place
// on the last item of memory ... so that portion of this compressed
// scope is still to be defined.
//
// Like I said, this version is placed here for discussion purposes,
// not because it runs well nor because I have recognized that it has any
// particular value (yet).
//
// Well, I take that back. When dealing with an interface such as the
// PS/2 interface, or even the 16x2 LCD interface, it is often true
// that things change _very_ slowly. They could change so slowly that
// the other approach to the scope doesn't work. This then gives you
// a working scope, by only capturing the changes. You'll still need
// to figure out (after the fact) when the trigge took place. Perhaps
// you'll wish to add the trigger as another data line, so you can find
// when it took place in your own data?
//
// Okay, I take that back twice: I'm finding this compressed scope very
// valuable for evaluating the timing associated with a GPS PPS and
// associated NMEA stream. I need to collect over a seconds worth of
// data, and I don't have enough memory to handle one memory value per
// clock, yet I still want to know exactly when the GPS PPS goes high,
// when it goes low, when I'm adjusting my clock, and when the clock's
// PPS output goes high. Did I synchronize them well? Oh, and when does
// the NMEA time string show up when compared with the PPS? All of those
// are valuable, but could never be done if the scope wasn't compressed.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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 wbscopc(i_clk, i_ce, i_trigger, i_data,
i_wb_clk, 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_interrupt);
parameter LGMEM = 5'd10, NELM=31, BUSW = 32, SYNCHRONOUS=1;
// The input signals that we wish to record
input i_clk, i_ce, i_trigger;
input [(NELM-1):0] i_data;
// The WISHBONE bus for reading and configuring this scope
input i_wb_clk, i_wb_cyc, i_wb_stb, i_wb_we;
input i_wb_addr; // One address line only
input [(BUSW-1):0] i_wb_data;
output wire o_wb_ack, o_wb_stall;
output wire [(BUSW-1):0] o_wb_data;
// And, finally, for a final flair --- offer to interrupt the CPU after
// our trigger has gone off. This line is equivalent to the scope
// being stopped. It is not maskable here.
output wire o_interrupt;
 
 
// Let's first see how far we can get by cheating. We'll use the
// wbscope program, and suffer a lack of several features
 
// When is the full scope reset? Capture that reset bit from any
// write.
wire lcl_reset;
assign lcl_reset = (i_wb_cyc)&&(i_wb_stb)&&(~i_wb_addr)&&(i_wb_we)
&&(~i_wb_data[31]);
 
// A big part of this scope is the 'address' of any particular
// data value. As of this current version, the 'address' changed
// in definition from an absolute time (which had all kinds of
// problems) to a difference in time. Hence, when the address line
// is high on decompression, the 'address' field will record an
// address difference.
//
// To implement this, we set our 'address' to zero any time the
// data changes, but increment it on all other clocks. Should the
// address difference get to our maximum value, we let it saturate
// rather than overflow.
reg [(BUSW-2):0] ck_addr;
reg [(NELM-1):0] lst_dat;
initial ck_addr = 0;
always @(posedge i_clk)
if ((lcl_reset)||((i_ce)&&(i_data != lst_dat)))
ck_addr <= 0;
else if (&ck_addr)
; // Saturated (non-overflowing) address diff
else
ck_addr <= ck_addr + 1;
 
wire [(BUSW-2):0] w_data;
generate
if (NELM == BUSW-1)
assign w_data = i_data;
else
assign w_data = { {(BUSW-NELM-1){1'b0}}, i_data };
endgenerate
//
// To do our compression, we keep track of two registers: the most
// recent data to the device (imm_ prefix) and the data from one
// clock ago. This allows us to suppress writes to the scope which
// would otherwise be two address writes in a row.
reg imm_adr, lst_adr; // Is this an address (1'b1) or data value?
reg [(BUSW-2):0] lst_val, // Data for the scope, delayed by one
imm_val; // Data to write to the scope
initial lst_dat = 0;
initial lst_adr = 1'b1;
initial imm_adr = 1'b1;
always @(posedge i_clk)
if (lcl_reset)
begin
imm_val <= 31'h0;
imm_adr <= 1'b1;
lst_val <= 31'h0;
lst_adr <= 1'b1;
lst_dat <= 0;
end else if ((i_ce)&&(i_data != lst_dat))
begin
imm_val <= w_data;
imm_adr <= 1'b0;
lst_val <= imm_val;
lst_adr <= imm_adr;
lst_dat <= i_data;
end else begin
imm_val <= ck_addr; // Minimum value here is '1'
imm_adr <= 1'b1;
lst_val <= imm_val;
lst_adr <= imm_adr;
end
 
//
// Here's where we suppress writing pairs of address words to the
// scope at once.
//
reg r_ce;
reg [(BUSW-1):0] r_data;
initial r_ce = 1'b0;
always @(posedge i_clk)
r_ce <= (~lst_adr)||(~imm_adr);
always @(posedge i_clk)
r_data <= ((~lst_adr)||(~imm_adr))
? { lst_adr, lst_val }
: { {(32 - NELM){1'b0}}, i_data };
 
 
//
// The trigger needs some extra attention, in order to keep triggers
// that happen between events from being ignored.
//
wire w_trigger;
assign w_trigger = (r_trigger)||(i_trigger);
 
reg r_trigger;
initial r_trigger = 1'b0;
always @(posedge i_clk)
if (lcl_reset)
r_trigger <= 1'b0;
else
r_trigger <= w_trigger;
 
//
// Call the regular wishbone scope to do all of our real work, now
// that we've compressed the input.
//
wbscope #(.SYNCHRONOUS(1), .LGMEM(LGMEM),
.BUSW(BUSW)) cheatersscope(i_clk, r_ce, w_trigger, r_data,
i_wb_clk, 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_interrupt);
endmodule
/rtl/wbscope.v
0,0 → 1,341
///////////////////////////////////////////////////////////////////////////
//
// Filename: wbscope.v
//
// Project: FPGA Library of Routines
//
// Purpose: This is a generic/library routine for providing a bus accessed
// 'scope' or (perhaps more appropriately) a bus accessed logic
// analyzer. The general operation is such that this 'scope' can
// record and report on any 32 bit value transiting through the
// FPGA. Once started and reset, the scope records a copy of the
// input data every time the clock ticks with the circuit enabled.
// That is, it records these values up until the trigger. Once
// the trigger goes high, the scope will record for bw_holdoff
// more counts before stopping. Values may then be read from the
// buffer, oldest to most recent. After reading, the scope may
// then be reset for another run.
//
// In general, therefore, operation happens in this fashion:
// 1. A reset is issued.
// 2. Recording starts, in a circular buffer, and continues until
// 3. The trigger line is asserted.
// The scope registers the asserted trigger by setting
// the 'o_triggered' output flag.
// 4. A counter then ticks until the last value is written
// The scope registers that it has stopped recording by
// setting the 'o_stopped' output flag.
// 5. The scope recording is then paused until the next reset.
// 6. While stopped, the CPU can read the data from the scope
// 7. -- oldest to most recent
// 8. -- one value per i_rd&i_clk
// 9. Writes to the data register reset the address to the
// beginning of the buffer
//
// Although the data width DW is parameterized, it is not very changable,
// since the width is tied to the width of the data bus, as is the
// control word. Therefore changing the data width would require changing
// the interface. It's doable, but it would be a change to the interface.
//
// The SYNCHRONOUS parameter turns on and off meta-stability
// synchronization. Ideally a wishbone scope able to handle one or two
// clocks would have a changing number of ports as this SYNCHRONOUS
// parameter changed. Other than running another script to modify
// this, I don't know how to do that so ... we'll just leave it running
// off of two clocks or not.
//
//
// Internal to this routine, registers and wires are named with one of the
// following prefixes:
//
// i_ An input port to the routine
// o_ An output port of the routine
// br_ A register, controlled by the bus clock
// dr_ A register, controlled by the data clock
// bw_ A wire/net, controlled by the bus clock
// dw_ A wire/net, controlled by the data clock
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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 wbscope(i_clk, i_ce, i_trigger, i_data,
i_wb_clk, 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_interrupt);
parameter LGMEM = 5'd10, BUSW = 32, SYNCHRONOUS=1;
// The input signals that we wish to record
input i_clk, i_ce, i_trigger;
input [(BUSW-1):0] i_data;
// The WISHBONE bus for reading and configuring this scope
input i_wb_clk, i_wb_cyc, i_wb_stb, i_wb_we;
input i_wb_addr; // One address line only
input [(BUSW-1):0] i_wb_data;
output wire o_wb_ack, o_wb_stall;
output reg [(BUSW-1):0] o_wb_data;
// And, finally, for a final flair --- offer to interrupt the CPU after
// our trigger has gone off. This line is equivalent to the scope
// being stopped. It is not maskable here.
output wire o_interrupt;
 
reg [(LGMEM-1):0] raddr;
reg [(BUSW-1):0] mem[0:((1<<LGMEM)-1)];
 
// Our status/config register
wire bw_reset_request, bw_manual_trigger,
bw_disable_trigger, bw_reset_complete;
reg [22:0] br_config;
wire [19:0] bw_holdoff;
initial br_config = ((1<<(LGMEM-1))-4);
always @(posedge i_wb_clk)
if ((i_wb_stb)&&(~i_wb_addr))
begin
if (i_wb_we)
br_config <= { i_wb_data[31],
(i_wb_data[27]),
i_wb_data[26],
i_wb_data[19:0] };
end else if (bw_reset_complete)
br_config[22] <= 1'b1;
assign bw_reset_request = (~br_config[22]);
assign bw_manual_trigger = (br_config[21]);
assign bw_disable_trigger = (br_config[20]);
assign bw_holdoff = br_config[19:0];
 
wire dw_reset, dw_manual_trigger, dw_disable_trigger;
generate
if (SYNCHRONOUS > 0)
begin
assign dw_reset = bw_reset_request;
assign dw_manual_trigger = bw_manual_trigger;
assign dw_disable_trigger = bw_disable_trigger;
assign bw_reset_complete = bw_reset_request;
end else begin
reg r_reset_complete;
reg [2:0] r_iflags, q_iflags;
 
// Resets are synchronous to the bus clock, not the data clock
// so do a clock transfer here
initial q_iflags = 3'b000;
initial r_reset_complete = 1'b0;
always @(posedge i_clk)
begin
q_iflags <= { bw_reset_request, bw_manual_trigger, bw_disable_trigger };
r_iflags <= q_iflags;
r_reset_complete <= (dw_reset);
end
 
assign dw_reset = r_iflags[2];
assign dw_manual_trigger = r_iflags[1];
assign dw_disable_trigger = r_iflags[0];
 
reg q_reset_complete, qq_reset_complete;
// Pass an acknowledgement back from the data clock to the bus
// clock that the reset has been accomplished
initial q_reset_complete = 1'b0;
initial qq_reset_complete = 1'b0;
always @(posedge i_wb_clk)
begin
q_reset_complete <= r_reset_complete;
qq_reset_complete <= q_reset_complete;
end
 
assign bw_reset_complete = qq_reset_complete;
end endgenerate
 
//
// Set up the trigger
//
//
// Write with the i-clk, or input clock. All outputs read with the
// WISHBONE-clk, or i_wb_clk clock.
reg dr_triggered, dr_primed;
wire dw_trigger;
assign dw_trigger = (dr_primed)&&(
((i_trigger)&&(~dw_disable_trigger))
||(dr_triggered)
||(dw_manual_trigger));
initial dr_triggered = 1'b0;
always @(posedge i_clk)
if (dw_reset)
dr_triggered <= 1'b0;
else if ((i_ce)&&(dw_trigger))
dr_triggered <= 1'b1;
 
//
// Determine when memory is full and capture is complete
//
// Writes take place on the data clock
reg dr_stopped, dr_past_holdoff;
reg [19:0] counter; // This is unsigned
initial dr_stopped = 1'b0;
initial counter = 20'h0000;
initial dr_past_holdoff = 1'b0;
always @(posedge i_clk)
dr_past_holdoff <= (counter >= bw_holdoff);
always @(posedge i_clk)
if (dw_reset)
begin
counter <= 0;
dr_stopped <= 1'b0;
end else if ((i_ce)&&(dr_triggered))
begin // MUST BE a < and not <=, so that we can keep this w/in
// 20 bits. Else we'd need to add a bit to comparison
// here.
if (~dr_stopped)
counter <= counter + 20'h01;
dr_stopped <= (dr_stopped)||(dr_past_holdoff);
end
 
//
// Actually do our writes to memory. Record, via 'primed' when
// the memory is full.
//
// The 'waddr' address that we are using really crosses two clock
// domains. While writing and changing, it's in the data clock
// domain. Once stopped, it becomes part of the bus clock domain.
// The clock transfer on the stopped line handles the clock
// transfer for these signals.
//
reg [(LGMEM-1):0] waddr;
initial waddr = {(LGMEM){1'b0}};
initial dr_primed = 1'b0;
always @(posedge i_clk)
if (dw_reset) // For simulation purposes, supply a valid value
begin
waddr <= 0; // upon reset.
dr_primed <= 1'b0;
end else if ((i_ce)&&(~dr_stopped))
begin
// mem[waddr] <= i_data;
waddr <= waddr + {{(LGMEM-1){1'b0}},1'b1};
dr_primed <= (dr_primed)||(&waddr);
end
always @(posedge i_clk)
if ((i_ce)&&(~dr_stopped))
mem[waddr] <= i_data;
 
//
// Clock transfer of the status signals
//
wire bw_stopped, bw_triggered, bw_primed;
generate
if (SYNCHRONOUS > 0)
begin
assign bw_stopped = dr_stopped;
assign bw_triggered = dr_triggered;
assign bw_primed = dr_primed;
end else begin
// These aren't a problem, since none of these are strobe
// signals. They goes from low to high, and then stays high
// for many clocks. Swapping is thus easy--two flip flops to
// protect against meta-stability and we're done.
//
reg [2:0] q_oflags, r_oflags;
initial q_oflags = 3'h0;
initial r_oflags = 3'h0;
always @(posedge i_wb_clk)
if (bw_reset_request)
begin
q_oflags <= 3'h0;
r_oflags <= 3'h0;
end else begin
q_oflags <= { dr_stopped, dr_triggered, dr_primed };
r_oflags <= q_oflags;
end
 
assign bw_stopped = r_oflags[2];
assign bw_triggered = r_oflags[1];
assign bw_primed = r_oflags[0];
end endgenerate
 
// Reads use the bus clock
reg br_wb_ack, r_wb_ack; // takes one clock to read
wire bw_cyc_stb, bus_read_fifo;
assign bw_cyc_stb = (i_wb_stb);
assign bus_read_fifo = (i_wb_stb)&&(i_wb_addr)&&(~i_wb_we);
initial br_wb_ack = 1'b0;
always @(posedge i_wb_clk)
begin // CE depends upon 5 inputs, output on 7 (ignoring add&carries)
if ((bw_reset_request)
||((bw_cyc_stb)&&(i_wb_addr)&&(i_wb_we)))
raddr <= 0;
else if ((bus_read_fifo)&&(bw_stopped))
raddr <= raddr + {{(LGMEM-1){1'b0}},1'b1}; // Data read, when stopped
 
r_wb_ack <= i_wb_stb;
br_wb_ack <= r_wb_ack;
end
 
reg [(LGMEM-1):0] nxt_addr;
always @(posedge i_wb_clk) // 2 adds, then 5 inputs
if (bus_read_fifo)
nxt_addr <= nxt_addr + {{(LGMEM-1){1'b0}},1'b1};
else
nxt_addr <= raddr + waddr;
// nxt_addr <= raddr + waddr + (bus_read_fifo)
// ? {{(LGMEM-1){1'b0}},1'b1}: 0;
 
reg [31:0] nxt_mem;
always @(posedge i_wb_clk)
nxt_mem <= mem[nxt_addr];
 
reg r_wb_addr;
always @(posedge i_clk)
r_wb_addr <= i_wb_addr;
 
wire [4:0] bw_lgmem;
assign bw_lgmem = LGMEM;
always @(posedge i_wb_clk)
if (~r_wb_addr) // Control register read
o_wb_data <= { bw_reset_request,
bw_stopped,
bw_triggered,
bw_primed,
bw_manual_trigger,
bw_disable_trigger,
(raddr == {(LGMEM){1'b0}}),
bw_lgmem,
bw_holdoff };
else if (~bw_stopped) // read, prior to stopping
o_wb_data <= i_data;
else // if (i_wb_addr) // Read from FIFO memory
o_wb_data <= nxt_mem; // mem[raddr+waddr];
 
assign o_wb_stall = 1'b0;
assign o_wb_ack = (br_wb_ack);
 
reg br_level_interrupt;
initial br_level_interrupt = 1'b0;
assign o_interrupt = (bw_stopped)&&(~bw_disable_trigger)
&&(~br_level_interrupt);
always @(posedge i_wb_clk)
if ((bw_reset_complete)||(bw_reset_request))
br_level_interrupt<= 1'b0;
else
br_level_interrupt<= (bw_stopped)&&(~bw_disable_trigger);
 
endmodule
/rtl/wbicapetwo.v
0,0 → 1,262
///////////////////////////////////////////////////////////////////////////
//
// Filename: wbicapetwo.v
//
// Project: Wishbone to ICAPE2 interface conversion
//
// Purpose: This routine maps the configuration registers of a 7-series
// Xilinx part onto register addresses on a wishbone bus interface
// via the ICAPE2 access port to those parts. The big thing this
// captures is the timing and handshaking required to read and
// write registers from the configuration interface.
//
// As an example of what can be done, writing a 32'h00f to
// local address 5'h4 sends the IPROG command to the FPGA, causing
// it to immediately reconfigure itself.
//
// As another example, the warm boot start address is located
// in register 5'h10. Writing to this address, followed by
// issuing the IPROG command just mentioned will cause the
// FPGA to configure from that warm boot start address.
//
// For more details on the configuration interface, the registers
// in question, their meanings and what they do, please see
// User's Guide 470, the "7 Series FPGAs Configuration" User
// Guide.
//
// Notes: This module supports both reads and writes from the ICAPE2
// interface. These follow the following pattern.
//
// For writes:
// (Idle) 0xffffffff (Dummy)
// (CS/W) 0x20000000 NOOP
// (CS/W) 0xaa995566 SYNC WORD
// (CS/W) 0x20000000 NOOP
// (CS/W) 0x20000000 NOOP
// (CS/W) ... Write command
// (CS/W) ... Write value, from Wishbone bus
// (CS/W) 0x20000000 NOOP
// (CS/W) 0x20000000 NOOP
// (CS/W) 0x30008001 Write to CMD register (address 4)
// (CS/W) 0x0000000d DESYNC command
// (CS/W) 0x20000000 NOOP
// (CS/W) 0x20000000 NOOP
// (Idle)
//
// and for reads:
// (Idle) 0xffffffff (Dummy)
// (CS/W) 0x20000000 NOOP
// (CS/W) 0xaa995566 SYNC WORD
// (CS/W) 0x20000000 NOOP
// (CS/W) 0x20000000 NOOP
// (CS/W) ... Read command
// (CS/W) 0x20000000 NOOP
// (CS/W) 0x20000000 NOOP
// (Idle) 0x20000000 (Idle the interface again, so we can rd)
// (CS/R) 0x20000000 (Wait)
// (CS/R) 0x20000000 (Wait)
// (CS/R) 0x20000000 (Wait)
// (CS/R) 0x20000000 (Wait)
// (Idle) 0x20000000 (Idle the interface before writing)
// (CS/W) 0x20000000 NOOP
// (CS/W) 0x20000000 NOOP
// (CS/W) 0x30008001 Write to CMD register (address 4)
// (CS/W) 0x0000000d DESYNC command
// (CS/W) 0x20000000 NOOP
// (CS/W) 0x20000000 NOOP
// (Idle)
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
//
`define MBOOT_IDLE 5'h00
`define MBOOT_START 5'h01
`define MBOOT_READ 5'h06
`define MBOOT_WRITE 5'h0f
`define MBOOT_DESYNC 5'h11
module wbicapetwo(i_clk,
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
o_wb_ack, o_wb_stall, o_wb_data);
input i_clk;
// Wishbone inputs
input i_wb_cyc, i_wb_stb, i_wb_we;
input [4:0] i_wb_addr;
input [31:0] i_wb_data;
// Wishbone outputs
output reg o_wb_ack, o_wb_stall;
output reg [31:0] o_wb_data;
// ICAPE2 interface signals
// These are kept internal to this block ...
 
reg wb_req, r_we;
reg [31:0] r_data;
reg [4:0] r_addr;
 
reg slow_clk;
reg [31:0] cfg_in;
reg cfg_cs_n, cfg_rdwrn;
wire [31:0] cfg_out;
reg [4:0] state;
initial state = `MBOOT_IDLE;
initial cfg_cs_n = 1'b1;
always @(posedge i_clk)
begin
o_wb_ack <= 1'b0;
// Turn any request "off", so that it will not be ack'd, if
// the wb_cyc line is ever lowered.
wb_req <= wb_req & i_wb_cyc;
slow_clk <= slow_clk ^ 1'b1;
o_wb_stall <= (state != `MBOOT_IDLE)&&(slow_clk);
if (~slow_clk)
begin
state <= state + 5'h01;
case(state)
`MBOOT_IDLE: begin
cfg_cs_n <= 1'b1;
cfg_rdwrn <= 1'b1;
cfg_in <= 32'hffffffff; // Dummy word
 
state <= `MBOOT_IDLE;
 
o_wb_ack <= 1'b0;
 
r_addr <= i_wb_addr;
r_data <= i_wb_data;
r_we <= i_wb_we;
if(i_wb_stb)
begin
state <= `MBOOT_START;
wb_req <= 1'b1;
//
o_wb_ack <= 1'b0;
end end
`MBOOT_START: cfg_in <= 32'hffffffff; // NOOP
5'h02: begin
cfg_cs_n <= 1'b0; // Activate interface
cfg_rdwrn <= 1'b0;
cfg_in <= 32'h20000000; // NOOP
end
5'h03: cfg_in <= 32'haa995566; // Sync word
5'h04: cfg_in <= 32'h20000000; // NOOP
5'h05: begin
cfg_in <= 32'h20000000; // NOOP
state <= (r_we) ? `MBOOT_WRITE : `MBOOT_READ;
end
`MBOOT_READ: cfg_in <= { 8'h28, 6'h0, r_addr, 13'h001 };
5'h07: cfg_in <= 32'h20000000; // NOOP
5'h08: cfg_in <= 32'h20000000; // NOOP
5'h09: begin // Idle the interface before the read cycle
cfg_cs_n <= 1'b1;
cfg_rdwrn <= 1'b1;
cfg_in <= 32'h20000000; // NOOP
end
5'h0a: begin // Re-activate the interface and wait 3 cycles
cfg_cs_n <= 1'b0;
cfg_rdwrn <= 1'b1;
cfg_in <= 32'h20000000; // NOOP
end
5'h0b: // ... still waiting, cycle two
cfg_in <= 32'h20000000; // NOOP
5'h0c: // ... still waiting, cycle three
cfg_in <= 32'h20000000; // NOOP
5'h0d: // ... still waiting, cycle four
cfg_in <= 32'h20000000; // NOOP
5'h0e: begin // and now our answer is there
cfg_cs_n <= 1'b1;
cfg_rdwrn <= 1'b1;
cfg_in <= 32'h20000000; // NOOP
//
// Wishbone return
o_wb_ack <= wb_req;
o_wb_data <= cfg_out;
wb_req <= 1'b0;
//
state <= `MBOOT_DESYNC;
end
`MBOOT_WRITE: // Issue a write command to the given address
cfg_in <= { 8'h30, 6'h0, r_addr, 13'h001 };
5'h10: cfg_in <= r_data; // Write the value
`MBOOT_DESYNC: begin
cfg_cs_n <= 1'b0;
cfg_rdwrn <= 1'b0;
cfg_in <= 32'h20000000; // 1st NOOP
end
5'h12: cfg_in <= 32'h20000000; // 2nd NOOP
5'h13: cfg_in <= 32'h30008001; // Write to CMD register
5'h14: cfg_in <= 32'h0000000d; // DESYNC command
5'h15: cfg_in <= 32'h20000000; // NOOP
5'h16: cfg_in <= 32'h20000000; // NOOP
5'h17: begin
// Acknowledge the bus transaction, it is now complete
o_wb_ack <= wb_req;
wb_req <= 1'b0;
//
cfg_cs_n <= 1'b1;
cfg_rdwrn <= 1'b0;
cfg_in <= 32'hffffffff; // DUMMY
//
state <= `MBOOT_IDLE;
end
default: begin
o_wb_ack <= 1'b0;
cfg_cs_n <= 1'b1;
cfg_rdwrn <= 1'b0;
state <= `MBOOT_IDLE;
cfg_in <= 32'hffffffff; // DUMMY WORD
end
endcase
end else begin
o_wb_ack <= 1'b0;
end
end
 
genvar k;
//
// The data registers to the ICAPE2 interface are bit swapped within
// each byte. Thus, in order to read from or write to the interface,
// we need to bit swap the bits in each byte. These next lines
// accomplish that for both the input and output ports.
//
wire [31:0] bit_swapped_cfg_in;
generate
for(k=0; k<8; k=k+1)
begin
assign bit_swapped_cfg_in[ k] = cfg_in[ 7-k];
assign bit_swapped_cfg_in[ 8+k] = cfg_in[ 8+7-k];
assign bit_swapped_cfg_in[16+k] = cfg_in[16+7-k];
assign bit_swapped_cfg_in[24+k] = cfg_in[24+7-k];
end endgenerate
 
wire [31:0] bit_swapped_cfg_out;
generate
for(k=0; k<8; k=k+1)
begin
assign cfg_out[ k] = bit_swapped_cfg_out[ 7-k];
assign cfg_out[ 8+k] = bit_swapped_cfg_out[ 8+7-k];
assign cfg_out[16+k] = bit_swapped_cfg_out[16+7-k];
assign cfg_out[24+k] = bit_swapped_cfg_out[24+7-k];
end endgenerate
 
ICAPE2 #(.ICAP_WIDTH("X32")) reconfig(.CLK(slow_clk),
.CSIB(cfg_cs_n), .RDWRB(cfg_rdwrn),
.I(bit_swapped_cfg_in), .O(bit_swapped_cfg_out));
endmodule
/rtl/busmaster.v
0,0 → 1,1076
////////////////////////////////////////////////////////////////////////////////
//
// Filename: busmaster.v
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: This is the "bus interconnect", herein called the "busmaster".
// This module connects all the devices on the Wishbone bus
// within this project together. It is created by hand, not
// automatically.
//
// 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
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`define NO_ZIP_WBU_DELAY
`define ZIPCPU
`ifdef ZIPCPU
`define ZIP_SYSTEM
`ifndef ZIP_SYSTEM
`define ZIP_BONES
`endif // ZIP_SYSTEM
`endif // ZipCPU
//
//
`define SDCARD_ACCESS
`define ETHERNET_ACCESS
`ifndef VERILATOR
`define ICAPE_ACCESS
`endif
`define FLASH_ACCESS
//`define SDRAM_ACCESS
`define GPS_CLOCK
// UART_ACCESS and GPS_UART have both been placed within fastio
// `define UART_ACCESS
// `define GPS_UART
`define RTC_ACCESS
`define OLEDRGB_ACCESS
//
// `define CPU_SCOPE
// `define GPS_SCOPE
`define FLASH_SCOPE
// `define SDRAM_SCOPE
// `define ENET_SCOPE
//
//
module busmaster(i_clk, i_rst,
// CNC
i_rx_stb, i_rx_data, o_tx_stb, o_tx_data, i_tx_busy,
// Boad I/O
i_sw, i_btn, o_led,
o_clr_led0, o_clr_led1, o_clr_led2, o_clr_led3,
// PMod I/O
i_aux_rx, o_aux_tx, o_aux_cts, i_gps_rx, o_gps_tx,
// The Quad SPI Flash
o_qspi_cs_n, o_qspi_sck, o_qspi_dat, i_qspi_dat, o_qspi_mod,
// The DDR3 SDRAM
o_ddr_reset_n, o_ddr_cke,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
o_ddr_dqs, o_ddr_addr, o_ddr_ba, o_ddr_data, i_ddr_data,
// The SD Card
o_sd_sck, o_sd_cmd, o_sd_data, i_sd_cmd, i_sd_data, i_sd_detect,
// Ethernet control (MDIO) lines
o_mdclk, o_mdio, o_mdwe, i_mdio,
// OLED Control interface (roughly SPI)
o_oled_sck, o_oled_cs_n, o_oled_mosi, o_oled_dcn,
o_oled_reset_n, o_oled_vccen, o_oled_pmoden,
// The GPS PMod
i_gps_pps, i_gps_3df
);
parameter ZA=24, ZIPINTS=13;
input i_clk, i_rst;
// The bus commander, via an external uart port
input i_rx_stb;
input [7:0] i_rx_data;
output wire o_tx_stb;
output wire [7:0] o_tx_data;
input i_tx_busy;
// I/O to/from board level devices
input [3:0] i_sw; // 16 switch bus
input [3:0] i_btn; // 5 Buttons
output wire [3:0] o_led; // 16 wide LED's
output wire [2:0] o_clr_led0, o_clr_led1, o_clr_led2, o_clr_led3;
// PMod UARTs
input i_aux_rx;
output wire o_aux_tx, o_aux_cts;
input i_gps_rx;
output wire o_gps_tx;
// Quad-SPI flash control
output wire o_qspi_cs_n, o_qspi_sck;
output wire [3:0] o_qspi_dat;
input [3:0] i_qspi_dat;
output wire [1:0] o_qspi_mod;
// DDR3 RAM controller
output wire o_ddr_reset_n, o_ddr_cke,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n,o_ddr_we_n;
output wire [2:0] o_ddr_dqs;
output wire [13:0] o_ddr_addr;
output wire [2:0] o_ddr_ba;
output wire [31:0] o_ddr_data;
input [31:0] i_ddr_data;
// The SD Card
output wire o_sd_sck;
output wire o_sd_cmd;
output wire [3:0] o_sd_data;
input i_sd_cmd;
input [3:0] i_sd_data;
input i_sd_detect;
// Ethernet control (MDIO)
output wire o_mdclk, o_mdio, o_mdwe;
input i_mdio;
// OLEDRGB interface
output wire o_oled_sck, o_oled_cs_n, o_oled_mosi,
o_oled_dcn, o_oled_reset_n, o_oled_vccen,
o_oled_pmoden;
// GPS PMod (GPS UART above)
input i_gps_pps;
input i_gps_3df;
 
//
//
// Master wishbone wires
//
//
wire wb_cyc, wb_stb, wb_we, wb_stall, wb_err;
wire [31:0] wb_data, wb_addr;
reg wb_ack;
reg [31:0] wb_idata;
 
// Interrupts
wire gpio_int, oled_int, flash_int, scop_int;
wire enet_tx_int, enet_rx_int, sdcard_int, rtc_int, rtc_pps,
auxrx_int, auxtx_int, gpsrx_int, sw_int, btn_int;
 
//
//
// First BUS master source: The UART
//
//
wire [31:0] dwb_idata;
 
// Wires going to devices
wire wbu_cyc, wbu_stb, wbu_we;
wire [31:0] wbu_addr, wbu_data;
// and then coming from devices
wire wbu_ack, wbu_stall, wbu_err;
wire [31:0] wbu_idata;
// And then headed back home
wire w_interrupt;
// Oh, and the debug control for the ZIP CPU
wire wbu_zip_sel, zip_dbg_ack, zip_dbg_stall;
wire [31:0] zip_dbg_data;
wbubus genbus(i_clk, i_rx_stb, i_rx_data,
wbu_cyc, wbu_stb, wbu_we, wbu_addr, wbu_data,
(wbu_zip_sel)?zip_dbg_ack:wbu_ack,
(wbu_zip_sel)?zip_dbg_stall:wbu_stall,
wbu_err,
(wbu_zip_sel)?zip_dbg_data:wbu_idata,
w_interrupt,
o_tx_stb, o_tx_data, i_tx_busy);
 
// assign o_dbg = (wbu_ack)&&(wbu_cyc);
 
wire zip_cpu_int; // True if the CPU suddenly halts
`ifdef ZIPCPU
// Are we trying to access the ZipCPU? Such accesses must be special,
// because they must succeed regardless of whether or not the ZipCPU
// is on the bus. Hence, we trap them here.
assign wbu_zip_sel = (wbu_addr[27]);
 
//
//
// Second BUS master source: The ZipCPU
//
//
wire zip_cyc, zip_stb, zip_we;
wire [(ZA-1):0] w_zip_addr;
wire [31:0] zip_data, zip_scope_data;
// and then coming from devices
wire zip_ack, zip_stall, zip_err;
 
`ifdef ZIP_SYSTEM
wire [(ZIPINTS-1):0] zip_interrupt_vec = {
// Lazy(ier) interrupts
oled_int, gpio_int, rtc_int, scop_int, flash_int, sw_int, btn_int,
// Fast interrupts
sdcard_int, auxtx_int, auxrx_int, enet_tx_int, enet_rx_int,
gpsrx_int, rtc_pps
};
 
zipsystem #( .RESET_ADDRESS(24'h08000),
.ADDRESS_WIDTH(ZA),
.LGICACHE(10),
.START_HALTED(1),
.EXTERNAL_INTERRUPTS(ZIPINTS),
.HIGHSPEED_CPU(0))
zippy(i_clk, i_rst,
// Zippys wishbone interface
zip_cyc, zip_stb, zip_we, w_zip_addr, zip_data,
zip_ack, zip_stall, dwb_idata, zip_err,
zip_interrupt_vec, zip_cpu_int,
// Debug wishbone interface
((wbu_cyc)&&(wbu_zip_sel)),
((wbu_stb)&&(wbu_zip_sel)),wbu_we, wbu_addr[0],
wbu_data,
zip_dbg_ack, zip_dbg_stall, zip_dbg_data
`ifdef CPU_DEBUG
, zip_scope_data
`endif
);
`else // ZIP_SYSTEM
wire w_zip_cpu_int_ignored;
zipbones #( .RESET_ADDRESS(24'h08000),
.ADDRESS_WIDTH(ZA),
.LGICACHE(10),
.START_HALTED(1),
.HIGHSPEED_CPU(0))
zippy(i_clk, i_rst,
// Zippys wishbone interface
zip_cyc, zip_stb, zip_we, w_zip_addr, zip_data,
zip_ack, zip_stall, dwb_idata, zip_err,
w_interrupt, w_zip_cpu_int_ignored,
// Debug wishbone interface
((wbu_cyc)&&(wbu_zip_sel)),
((wbu_stb)&&(wbu_zip_sel)),wbu_we, wbu_addr[0],
wbu_data,
zip_dbg_ack, zip_dbg_stall, zip_dbg_data
`ifdef CPU_DEBUG
, zip_scope_data
`endif
);
assign zip_cpu_int = 1'b0;
`endif // ZIP_SYSTEM v ZIP_BONES
 
wire [31:0] zip_addr;
generate
if (ZA < 32)
assign zip_addr = { {(32-ZA){1'b0}}, w_zip_addr};
else
assign zip_addr = w_zip_addr;
endgenerate
 
//
//
// And an arbiter to decide who gets to access the bus
//
//
wire dwb_we, dwb_stb, dwb_cyc, dwb_ack, dwb_stall, dwb_err;
wire [31:0] dwb_addr, dwb_odata;
wbpriarbiter #(32,32) wbu_zip_arbiter(i_clk,
// The ZIP CPU Master -- Gets the priority slot
zip_cyc, zip_stb, zip_we, zip_addr, zip_data,
zip_ack, zip_stall, zip_err,
// The UART interface Master
(wbu_cyc)&&(~wbu_zip_sel), (wbu_stb)&&(~wbu_zip_sel), wbu_we,
wbu_addr, wbu_data,
wbu_ack, wbu_stall, wbu_err,
// Common bus returns
dwb_cyc, dwb_stb, dwb_we, dwb_addr, dwb_odata,
dwb_ack, dwb_stall, dwb_err);
 
//
//
// And because the ZIP CPU and the Arbiter create an unacceptable
// delay, we fail timing. So we add in a delay cycle ...
//
//
assign wbu_idata = dwb_idata;
busdelay wbu_zip_delay(i_clk,
dwb_cyc, dwb_stb, dwb_we, dwb_addr, dwb_odata,
dwb_ack, dwb_stall, dwb_idata, dwb_err,
wb_cyc, wb_stb, wb_we, wb_addr, wb_data,
wb_ack, wb_stall, wb_idata, wb_err);
 
`else // ZIPCPU
assign zip_cpu_int = 1'b0; // No CPU here to halt
assign wbu_zip_sel = 1'b0;
 
// If there's no ZipCPU, there's no need for a Zip/WB-Uart bus delay.
// We can go directly from the WB-Uart master bus to the master bus
// itself.
assign wb_cyc = wbu_cyc;
assign wb_stb = wbu_stb;
assign wb_we = wbu_we;
assign wb_addr = wbu_addr;
assign wb_data = wbu_data;
assign wbu_idata = wb_idata;
assign wbu_ack = wb_ack;
assign wbu_stall = wb_stall;
assign wbu_err = wb_err;
 
// The CPU never halts if it doesn't exist, so set this interrupt to
// zero.
assign zip_cpu_int= 1'b0;
`endif // ZIPCPU
 
 
//
// Peripheral select lines.
//
// These lines will be true during any wishbone cycle whose address
// line selects the given I/O peripheral. The none_sel and many_sel
// lines are used to detect problems, such as when no device is
// selected or many devices are selected. Such problems will lead to
// bus errors (below).
//
wire io_sel, scop_sel, netb_sel,
flctl_sel, rtc_sel, sdcard_sel, netp_sel,
oled_sel, gps_sel, mio_sel, cfg_sel,
mem_sel, flash_sel, ram_sel,
none_sel, many_sel;
 
wire [4:0] skipaddr;
assign skipaddr = { wb_addr[26], wb_addr[22], wb_addr[15], wb_addr[11],
~wb_addr[8] };
assign ram_sel = (skipaddr[4]);
assign flash_sel = (skipaddr[4:3]==2'b01);
assign mem_sel = (skipaddr[4:2]==3'b001);
assign netb_sel = (skipaddr[4:1]==4'b0001);
assign io_sel = (~|skipaddr)&&(wb_addr[7:5]==3'b000);
assign scop_sel = (~|skipaddr)&&(wb_addr[7:3]==5'b00100);
assign rtc_sel = (~|skipaddr)&&(wb_addr[7:2]==6'b001010);
assign sdcard_sel= (~|skipaddr)&&(wb_addr[7:2]==6'b001011);
assign netp_sel = (~|skipaddr)&&(wb_addr[7:2]==6'b001101);
assign oled_sel = (~|skipaddr)&&(wb_addr[7:2]==6'b001110);
assign gps_sel = (~|skipaddr)&&( (wb_addr[7:2]==6'b001100)
|| (wb_addr[7:3]==5'b01000));
assign mio_sel = (~|skipaddr)&&(wb_addr[7:5]==3'b101);
assign flctl_sel = (~|skipaddr)&&(wb_addr[7:5]==3'b110);
assign cfg_sel = (~|skipaddr)&&(wb_addr[7:5]==3'b111);
 
wire skiperr;
assign skiperr = (|wb_addr[31:27])
||(~skipaddr[4])&&(|wb_addr[25:23])
||(skipaddr[4:3]==2'b00)&&(|wb_addr[21:16])
||(skipaddr[4:2]==3'b000)&&(|wb_addr[14:12])
||(skipaddr[4:1]==4'b0000)&&(|wb_addr[10:9]);
 
 
//
// Peripheral acknowledgement lines
//
// These are only a touch more confusing, since the flash device will
// ACK for both flctl_sel (the control line select), as well as the
// flash_sel (the memory line select). Hence we have one fewer ack
// line.
wire io_ack, oled_ack,
rtc_ack, sdcard_ack,
netp_ack, gps_ack, mio_ack, cfg_ack, netb_ack,
mem_ack, flash_ack, ram_ack;
reg many_ack, slow_many_ack;
reg slow_ack, scop_ack;
wire [4:0] ack_list;
assign ack_list = { ram_ack, flash_ack, mem_ack, netb_ack, cfg_ack };
initial many_ack = 1'b0;
always @(posedge i_clk)
many_ack <= ((ack_list != 5'h10)
&&(ack_list != 5'h8)
&&(ack_list != 5'h4)
&&(ack_list != 5'h2)
&&(ack_list != 5'h1)
&&(ack_list != 5'h0));
/*
assign many_ack = ( { 2'h0, ram_ack}
+{2'h0, flash_ack }
+{2'h0, mem_ack }
+{2'h0, netb_ack }
+{2'h0, slow_ack } > 3'h1 );
*/
 
wire [7:0] slow_ack_list;
assign slow_ack_list = { mio_ack, gps_ack, netp_ack,
sdcard_ack, rtc_ack, scop_ack, oled_ack, io_ack };
initial slow_many_ack = 1'b0;
always @(posedge i_clk)
slow_many_ack <= ((slow_ack_list != 8'h80)
&&(slow_ack_list != 8'h40)
&&(slow_ack_list != 8'h20)
&&(slow_ack_list != 8'h10)
&&(slow_ack_list != 8'h08)
&&(slow_ack_list != 8'h04)
&&(slow_ack_list != 8'h02)
&&(slow_ack_list != 8'h01)
&&(slow_ack_list != 8'h00));
 
always @(posedge i_clk)
wb_ack <= (wb_cyc)&&(|{ ram_ack, flash_ack, mem_ack,
netb_ack, cfg_ack, slow_ack });
always @(posedge i_clk)
slow_ack <= (wb_cyc)&&(|{oled_ack, mio_ack, gps_ack,
netp_ack, sdcard_ack, rtc_ack, scop_ack,
oled_ack, io_ack});
 
//
// Peripheral data lines
//
wire [31:0] io_data, oled_data,
rtc_data, sdcard_data,
netp_data, gps_data, mio_data, cfg_data, netb_data,
mem_data, flash_data, ram_data;
reg [31:0] slow_data, scop_data;
 
// 4 control lines, 5x32 data lines ...
always @(posedge i_clk)
if ((ram_ack)||(flash_ack))
wb_idata <= (ram_ack)?ram_data:flash_data;
else if ((mem_ack)||(netb_ack))
wb_idata <= (mem_ack)?mem_data:netb_data;
else
wb_idata <= slow_data;
 
// 7 control lines, 8x32 data lines
always @(posedge i_clk)
if ((cfg_ack)||(mio_ack))
slow_data <= (cfg_ack) ? cfg_data : mio_data;
else if ((gps_ack)||(netp_ack))
slow_data <= (gps_ack) ? gps_data : netp_data;
else if ((sdcard_ack)||(rtc_ack))
slow_data <= (sdcard_ack)?sdcard_data : rtc_data;
else if ((scop_ack)|(oled_ack))
slow_data <= (scop_ack)?scop_data:oled_data;
else
slow_data <= io_data;
 
//
// Peripheral stall lines
//
// As per the wishbone spec, these cannot be clocked or delayed. They
// *must* be done via combinatorial logic.
//
wire io_stall, scop_stall, oled_stall,
rtc_stall, sdcard_stall,
netp_stall, gps_stall, mio_stall, cfg_stall, netb_stall,
mem_stall, flash_stall, ram_stall,
many_stall;
assign wb_stall = (wb_cyc)&&(
((io_sel)&&(io_stall)) // Never stalls
||((scop_sel)&&(scop_stall)) // Never stalls
||((rtc_sel)&&(rtc_stall)) // Never stalls
||((sdcard_sel)&&(sdcard_stall))// Never stalls
||((netp_sel)&&(netp_stall))
||((gps_sel)&&(gps_stall)) //(maybe? never stalls?)
||((oled_sel)&&(oled_stall))
||((mio_sel)&&(mio_stall))
||((cfg_sel)&&(cfg_stall))
||((netb_sel)&&(netb_stall)) // Never stalls
||((mem_sel)&&(mem_stall)) // Never stalls
||((flash_sel|flctl_sel)&&(flash_stall))
||((ram_sel)&&(ram_stall)));
 
 
//
// Bus Error calculation(s)
//
 
// Selecting nothing is only an error if the strobe line is high as well
// as the cycle line. However, this is captured within the wb_err
// logic itself, so we can ignore it for a line or two.
assign none_sel = ( //(skiperr)||
(~|{ io_sel, scop_sel, flctl_sel, rtc_sel,
sdcard_sel, netp_sel, gps_sel,
oled_sel,
mio_sel, cfg_sel, netb_sel, mem_sel,
flash_sel,ram_sel }));
//
// Selecting multiple devices at once is a design flaw that should
// never happen. Hence, if this logic won't build, we won't include
// it. Still, having this logic in place has saved my tush more than
// once.
//
reg [31:0] sel_addr;
always @(posedge i_clk)
sel_addr <= wb_addr;
 
reg many_sel_a, many_sel_b, single_sel_a, single_sel_b, last_stb;
always @(posedge i_clk)
begin
last_stb <= wb_stb;
 
single_sel_a <= (wb_stb)&&((ram_sel)|(flash_sel)
|(mem_sel)|(netb_sel)|(cfg_sel));
many_sel_a <= 1'b0;
if ((ram_sel)&&((flash_sel)||(mem_sel)||(netb_sel)||cfg_sel))
many_sel_a <= 1'b1;
else if ((flash_sel)&&((mem_sel)||(netb_sel)||cfg_sel))
many_sel_a <= 1'b1;
else if ((mem_sel)&&((netb_sel)||cfg_sel))
many_sel_a <= 1'b1;
else if ((netb_sel)&&(cfg_sel))
many_sel_a <= 1'b1;
 
single_sel_b <= (wb_stb)&&((mio_sel)||(gps_sel)||(netp_sel)
||(sdcard_sel)||(rtc_sel)||(flctl_sel)
||(oled_sel)||(scop_sel)||(io_sel));
many_sel_b <= 1'b0;
if ((mio_sel)&&((gps_sel)||(netp_sel)||(sdcard_sel)||(rtc_sel)
||(flctl_sel)||(scop_sel)||(oled_sel)||(io_sel)))
many_sel_b <= 1'b1;
else if ((gps_sel)&&((netp_sel)||(sdcard_sel)||(rtc_sel)
||(flctl_sel)||(scop_sel)||(oled_sel)||(io_sel)))
many_sel_b <= 1'b1;
else if ((netp_sel)&&((sdcard_sel)||(rtc_sel)
||(flctl_sel)||(scop_sel)||(oled_sel)||(io_sel)))
many_sel_b <= 1'b1;
else if ((sdcard_sel)&&((rtc_sel)
||(flctl_sel)||(scop_sel)||(oled_sel)||(io_sel)))
many_sel_b <= 1'b1;
else if ((rtc_sel)&&((flctl_sel)||(scop_sel)||(oled_sel)||(io_sel)))
many_sel_b <= 1'b1;
else if ((flctl_sel)&&((scop_sel)||(oled_sel)||(io_sel)))
many_sel_b <= 1'b1;
else if ((scop_sel)&&((oled_sel)||(io_sel)))
many_sel_b <= 1'b1;
else if ((oled_sel)&&(io_sel))
many_sel_b <= 1'b1;
end
 
wire sel_err; // 5 inputs
assign sel_err = ( (last_stb)&&(~single_sel_a)&&(~single_sel_b))
||((single_sel_a)&&(single_sel_b))
||((single_sel_a)&&(many_sel_a))
||((single_sel_b)&&(many_sel_b));
assign wb_err = (wb_cyc)&&(sel_err || many_ack || slow_many_ack);
 
 
// Finally, if we ever encounter a bus error, knowing the address of
// the error will be important to figuring out how to fix it. Hence,
// we grab it here. Be aware, however, that this might not truly be
// the address that caused an error: in the case of none_sel it will
// be, but if many_ack or slow_many_ack are true then we might just be
// looking at an address on the bus that was nearby the one requested.
reg [31:0] bus_err_addr;
initial bus_err_addr = 32'h00;
always @(posedge i_clk)
if (wb_err)
bus_err_addr <= sel_addr;
 
//
// I/O peripheral
//
// The I/O processor, herein called an fastio. This is a unique
// set of peripherals--these are all of the peripherals that can answer
// in a single clock--or, rather, they are the peripherals that can
// answer the bus before their clock. Hence, the fastio simply consists
// of a mux that selects between various peripheral responses. Further,
// these peripherals are not allowed to stall the bus.
//
// There is no option for turning these off--they will always be on.
wire [8:0] master_ints;
assign master_ints = { zip_cpu_int, oled_int, rtc_int, sdcard_int,
enet_tx_int, enet_rx_int,
scop_int, flash_int, rtc_pps };
wire [5:0] board_ints;
wire [3:0] w_led;
wire rtc_ppd;
fastio #(
.AUXUART_SETUP(30'hd50),
.GPSUART_SETUP(30'hd20833)
) runio(i_clk, i_sw, i_btn,
w_led, o_clr_led0, o_clr_led1, o_clr_led2, o_clr_led3,
i_aux_rx, o_aux_tx, o_aux_cts, i_gps_rx, o_gps_tx,
wb_cyc, (io_sel)&&(wb_stb), wb_we, wb_addr[4:0],
wb_data, io_ack, io_stall, io_data,
rtc_ppd,
bus_err_addr, master_ints, w_interrupt,
board_ints);
assign { gpio_int, auxrx_int, auxtx_int, gpsrx_int, sw_int, btn_int } = board_ints;
 
/*
reg [25:0] dbg_counter_err, dbg_counter_cyc, dbg_counter_sel,
dbg_counter_many;
// assign wb_err = (wb_cyc)&&(sel_err || many_ack || slow_many_ack);
always @(posedge i_clk)
if (wbu_cyc)
dbg_counter_cyc <= 0;
else if (!dbg_counter_cyc[25])
dbg_counter_cyc <= dbg_counter_cyc+26'h1;
always @(posedge i_clk)
if (wbu_err)
dbg_counter_err <= 0;
else if (!dbg_counter_err[25])
dbg_counter_err <= dbg_counter_err+26'h1;
always @(posedge i_clk)
if ((wb_cyc)&&(sel_err))
dbg_counter_sel <= 0;
else if (!dbg_counter_sel[25])
dbg_counter_sel <= dbg_counter_sel+26'h1;
always @(posedge i_clk)
if ((wb_cyc)&&(many_ack))
dbg_counter_many <= 0;
else if (!dbg_counter_many[25])
dbg_counter_many <= dbg_counter_many+26'h1;
assign o_led = {
(!dbg_counter_many[25])|w_led[3],
(!dbg_counter_sel[25])|w_led[2],
(!dbg_counter_cyc[25])|w_led[1],
(!dbg_counter_err[25])|w_led[0] };
*/
assign o_led = w_led;
 
 
//
//
// Real Time Clock (RTC) device level access
//
//
wire gps_tracking, ck_pps;
wire [63:0] gps_step;
`ifdef RTC_ACCESS
rtcgps #(32'h15798f) // 2^48 / 200MHz
thertc(i_clk,
wb_cyc, (wb_stb)&&(rtc_sel), wb_we,
wb_addr[1:0], wb_data,
rtc_data, rtc_int, rtc_ppd,
gps_tracking, ck_pps, gps_step[47:16], rtc_pps);
`else
assign rtc_data = 32'h00;
assign rtc_int = 1'b0;
assign rtc_pps = 1'b0;
assign rtc_ppd = 1'b0;
`endif
reg r_rtc_ack;
initial r_rtc_ack = 1'b0;
always @(posedge i_clk)
r_rtc_ack <= (wb_stb)&&(rtc_sel);
assign rtc_ack = r_rtc_ack;
assign rtc_stall = 1'b0;
 
//
//
// SDCard device level access
//
//
`ifdef SDCARD_ACCESS
wire [31:0] sd_dbg;
// SPI mapping
wire w_sd_cs_n, w_sd_mosi, w_sd_miso;
 
sdspi sdctrl(i_clk,
wb_cyc, (wb_stb)&&(sdcard_sel), wb_we,
wb_addr[1:0], wb_data,
sdcard_ack, sdcard_stall, sdcard_data,
w_sd_cs_n, o_sd_sck, w_sd_mosi, w_sd_miso,
sdcard_int, 1'b1, sd_dbg);
assign w_sd_miso = i_sd_data[0];
assign o_sd_data = { w_sd_cs_n, 3'b111 };
assign o_sd_cmd = w_sd_mosi;
`else
reg r_sdcard_ack;
always @(posedge i_clk)
r_sdcard_ack <= (wb_stb)&&(sdcard_sel);
assign sdcard_ack = r_sdcard_ack;
 
assign sdcard_data = 32'h00;
assign sdcard_stall= 1'b0;
assign sdcard_int = 1'b0;
`endif
 
//
//
// OLEDrgb device control
//
//
`ifdef OLEDRGB_ACCESS
wboled rgbctrl(i_clk,
wb_cyc, (wb_stb)&&(oled_sel), wb_we,
wb_addr[1:0], wb_data,
oled_ack, oled_stall, oled_data,
o_oled_sck, o_oled_cs_n, o_oled_mosi, o_oled_dcn,
{ o_oled_reset_n, o_oled_vccen, o_oled_pmoden },
oled_int);
`else
assign o_oled_cs_n = 1'b1;
assign o_oled_sck = 1'b1;
assign o_oled_mosi = 1'b1;
assign o_oled_dcn = 1'b1;
assign o_oled_reset_n = 1'b0;
assign o_oled_vccen = 1'b0;
assign o_oled_pmoden = 1'b0;
 
reg r_oled_ack;
always @(posedge i_clk)
r_oled_ack <= (wb_stb)&&(oled_sel);
assign oled_ack = r_oled_ack;
 
assign oled_data = 32'h00;
assign oled_stall= 1'b0;
assign oled_int = 1'b0;
`endif
 
//
//
// GPS CLOCK CONTROLS, BOTH THE TEST BENCH AND THE CLOCK ITSELF
//
//
wire [63:0] gps_now, gps_err;
wire [31:0] gck_data, gtb_data;
wire gck_ack, gck_stall, gtb_ack, gtb_stall;
`ifdef GPS_CLOCK
//
// GPS CLOCK SCHOOL TESTING
//
wire gps_pps, tb_pps, gps_locked;
wire [1:0] gps_dbg_tick;
 
gpsclock_tb ppscktb(i_clk, ck_pps, tb_pps,
(wb_stb)&&(gps_sel)&&(wb_addr[3]),
wb_we, wb_addr[2:0],
wb_data, gtb_ack, gtb_stall, gtb_data,
gps_err, gps_now, gps_step);
`ifdef GPSTB
assign gps_pps = tb_pps; // Let the truth come from our test bench
`else
assign gps_pps = i_gps_pps;
`endif
wire gps_led;
 
//
// GPS CLOCK CONTROL
//
gpsclock ppsck(i_clk, 1'b0, gps_pps, ck_pps, gps_led,
(wb_stb)&&(gps_sel)&&(~wb_addr[3]),
wb_we, wb_addr[1:0],
wb_data, gck_ack, gck_stall, gck_data,
gps_tracking, gps_now, gps_step, gps_err, gps_locked,
gps_dbg_tick);
`else
 
assign gps_err = 64'h0;
assign gps_now = 64'h0;
assign gck_data = 32'h0;
assign gtb_data = 32'h0;
assign gtb_stall = 1'b0;
assign gck_stall = 1'b0;
assign ck_pps = 1'b0;
 
assign gps_tracking = 1'b0;
// Appropriate step for a 200MHz clock
assign gps_step = { 16'h00, 32'h015798e, 16'h00 };
 
reg r_gck_ack;
always @(posedge i_clk)
r_gck_ack <= (wb_stb)&&(gps_sel);
assign gck_ack = r_gck_ack;
assign gtb_ack = r_gck_ack;
 
`endif
 
assign gps_ack = (gck_ack | gtb_ack);
assign gps_stall = (gck_stall | gtb_stall);
assign gps_data = (gck_ack) ? gck_data : gtb_data;
 
 
//
// ETHERNET DEVICE ACCESS
//
`ifdef ETHERNET_ACCESS
reg r_mio_ack, r_netb_ack, r_netp_ack;
always @(posedge i_clk)
r_mio_ack <= (wb_stb)&&(mio_sel);
always @(posedge i_clk)
r_netp_ack <= (wb_stb)&&(netp_sel);
assign mio_ack = r_mio_ack;
assign netp_ack = r_netp_ack;
 
assign mio_data = 32'h00;
assign netp_data = 32'h00;
assign mio_stall = 1'b0;
assign netp_stall= 1'b0;
assign enet_rx_int = 1'b0;
assign enet_tx_int = 1'b0;
 
enetctrl #(3)
mdio(i_clk, i_rst, wb_cyc, (wb_stb)&&(netb_sel), wb_we,
wb_addr[4:0], wb_data[15:0],
netb_ack, netb_stall, netb_data,
o_mdclk, o_mdio, i_mdio, o_mdwe);
`else
reg r_mio_ack, r_netb_ack, r_netp_ack;
always @(posedge i_clk)
r_mio_ack <= (wb_stb)&&(mio_sel);
always @(posedge i_clk)
r_netp_ack <= (wb_stb)&&(netp_sel);
assign mio_ack = r_mio_ack;
assign netp_ack = r_netp_ack;
 
assign mio_data = 32'h00;
assign netp_data = 32'h00;
assign mio_stall = 1'b0;
assign netp_stall= 1'b0;
assign enet_rx_int = 1'b0;
assign enet_tx_int = 1'b0;
 
//
// 2kW memory, 1kW for each of transmit and receive. (Max pkt length
// is 512W, so this allows for two 512W in memory.) Since we don't
// really have ethernet without ETHERNET_ACCESS defined, this just
// consumes resources for us so we have an idea of what might be
// available when we do have ETHERNET_ACCESS defined.
//
memdev #(11) enet_buffers(i_clk, wb_cyc, (wb_stb)&&(netb_sel), wb_we,
wb_addr[10:0], wb_data, netb_ack, netb_stall, netb_data);
assign o_mdclk = 1'b1;
assign o_mdio = 1'b1;
assign o_mdwe = 1'b1;
`endif
 
 
//
// MULTIBOOT/ICAPE2 CONFIGURATION ACCESS
//
`ifdef ICAPE_ACCESS
wbicapetwo fpga_cfg(i_clk, wb_cyc,(cfg_sel)&&(wb_stb), wb_we,
wb_addr[4:0], wb_data,
cfg_ack, cfg_stall, cfg_data);
`else
reg r_cfg_ack;
always @(posedge i_clk)
r_cfg_ack <= (cfg_sel)&&(wb_stb);
assign cfg_ack = r_cfg_ack;
assign cfg_stall = 1'b0;
assign cfg_data = 32'h00;
`endif
 
//
// RAM MEMORY ACCESS
//
// There is no option to turn this off--this RAM must always be
// present in the design.
memdev #(15) // 32kW, or 128kB, 15 address lines
blkram(i_clk, wb_cyc, (wb_stb)&&(mem_sel), wb_we, wb_addr[14:0],
wb_data, mem_ack, mem_stall, mem_data);
 
//
// FLASH MEMORY ACCESS
//
`ifdef FLASH_ACCESS
`ifdef FLASH_SCOPE
wire [31:0] flash_debug;
`endif
wire w_ignore_cmd_accepted;
eqspiflash flashmem(i_clk, i_rst,
wb_cyc,(wb_stb)&&(flash_sel),(wb_stb)&&(flctl_sel),wb_we,
wb_addr[21: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_int, w_ignore_cmd_accepted
`ifdef FLASH_SCOPE
, flash_debug
`endif
);
`else
assign o_qspi_sck = 1'b1;
assign o_qspi_cs_n= 1'b1;
assign o_qspi_mod = 2'b01;
assign o_qspi_dat = 4'h0;
assign flash_data = 32'h00;
assign flash_stall = 1'b0;
assign flash_int = 1'b0;
 
reg r_flash_ack;
always @(posedge i_clk)
r_flash_ack <= (wb_stb)&&(flash_sel);
assign flash_ack = r_flash_ack;
`endif
 
 
//
//
// DDR3-SDRAM
//
//
`ifdef SDRAM_ACCESS
wbddrsdram rami(i_clk,
wb_cyc, (wb_stb)&&(ram_sel), wb_we, wb_addr[25:0], wb_data,
ram_ack, ram_stall, ram_data,
o_ddr_reset_n, o_ddr_cke,
o_ddr_cs_n, o_ddr_ras_n, o_ddr_cas_n, o_ddr_we_n,
o_ddr_dqs,
o_ddr_addr, o_ddr_ba, o_ddr_data, i_ddr_data);
`else
assign ram_data = 32'h00;
assign ram_stall = 1'b0;
reg r_ram_ack;
always @(posedge i_clk)
r_ram_ack <= (wb_stb)&&(ram_sel);
assign ram_ack = r_ram_ack;
 
// And idle the DDR3 SDRAM
assign o_ddr_reset_n = 1'b0; // Leave the SDRAM in reset
assign o_ddr_cke = 1'b0; // Disable the SDRAM clock
// DQS
assign o_ddr_dqs = 3'b100; // Leave DQS pins in high impedence
// DDR3 control wires (not enabled if CKE=0)
assign o_ddr_cs_n = 1'b0; // NOOP command
assign o_ddr_ras_n = 1'b1;
assign o_ddr_cas_n = 1'b1;
assign o_ddr_we_n = 1'b1;
// (Unused) data wires
assign o_ddr_addr = 14'h00;
assign o_ddr_ba = 3'h0;
assign o_ddr_data = 32'h00;
`endif
 
 
//
//
// WISHBONE SCOPES
//
//
//
//
wire [31:0] scop_a_data;
wire scop_a_ack, scop_a_stall, scop_a_interrupt;
`ifdef CPU_SCOPE
wire [31:0] scop_cpu_data;
wire scop_cpu_ack, scop_cpu_stall, scop_cpu_interrupt;
wire scop_cpu_trigger;
// assign scop_cpu_trigger = zip_scope_data[30];
assign scop_cpu_trigger = (wb_stb)&&(mem_sel)&&(~wb_we)
&&(wb_err)||(zip_scope_data[31]);
wbscope #(5'd13) cpuscope(i_clk, 1'b1,(scop_cpu_trigger), zip_scope_data,
// Wishbone interface
i_clk, wb_cyc, ((wb_stb)&&(scop_sel)&&(wb_addr[2:1]==2'b00)), wb_we, wb_addr[0],
wb_data,
scop_cpu_ack, scop_cpu_stall, scop_cpu_data,
scop_cpu_interrupt);
 
assign scop_a_data = scop_cpu_data;
assign scop_a_ack = scop_cpu_ack;
assign scop_a_stall = scop_cpu_stall;
assign scop_a_interrupt = scop_cpu_interrupt;
`else
`ifdef FLASH_SCOPE
wire [31:0] scop_flash_data;
wire scop_flash_ack, scop_flash_stall, scop_flash_interrupt;
wire scop_flash_trigger;
// assign scop_cpu_trigger = zip_scope_data[30];
assign scop_flash_trigger = (wb_stb)&&((flash_sel)||(flctl_sel));
wbscope #(5'd13) flashscope(i_clk, 1'b1,
(scop_flash_trigger), flash_debug,
// Wishbone interface
i_clk, wb_cyc, ((wb_stb)&&(scop_sel)&&(wb_addr[2:1]==2'b00)), wb_we, wb_addr[0],
wb_data,
scop_flash_ack, scop_flash_stall, scop_flash_data,
scop_flash_interrupt);
 
assign scop_a_data = scop_flash_data;
assign scop_a_ack = scop_flash_ack;
assign scop_a_stall = scop_flash_stall;
assign scop_a_interrupt = scop_flash_interrupt;
`else
reg r_scop_a_ack;
always @(posedge i_clk)
r_scop_a_ack <= (wb_stb)&&(scop_sel)&&(wb_addr[2:1] == 2'b00);
assign scop_a_data = 32'h00;
assign scop_a_ack = r_scop_a_ack;
assign scop_a_stall = 1'b0;
assign scop_a_interrupt = 1'b0;
`endif
`endif
 
wire [31:0] scop_b_data;
wire scop_b_ack, scop_b_stall, scop_b_interrupt;
`ifdef GPS_SCOPE
reg [18:0] r_gps_debug;
wire [31:0] scop_gps_data;
wire scop_gps_ack, scop_gps_stall, scop_gps_interrupt;
always @(posedge i_clk)
r_gps_debug <= {
gps_dbg_tick, gps_tracking, gps_locked,
gpu_data[7:0],
// (wb_cyc)&&(wb_stb)&&(io_sel),
(wb_stb)&&(io_sel)&&(wb_addr[4:3]==2'b11)&&(wb_we),
(wb_stb)&&(gps_sel)&&(wb_addr[3:2]==2'b01),
gpu_int,
i_gps_rx, rtc_pps, ck_pps, i_gps_pps };
wbscopc #(5'd13,19,32,1) gpsscope(i_clk, 1'b1, ck_pps, r_gps_debug,
// Wishbone interface
i_clk, wb_cyc, ((wb_stb)&&(scop_sel)&&(wb_addr[2:1]==2'b01)),
wb_we, wb_addr[0], wb_data,
scop_gps_ack, scop_gps_stall, scop_gps_data,
scop_gps_interrupt);
`else
assign scop_b_data = 32'h00;
assign scop_b_stall = 1'b0;
assign scop_b_interrupt = 1'b0;
 
reg r_scop_b_ack;
always @(posedge i_clk)
r_scop_b_ack <= (wb_stb)&&(scop_sel)&&(wb_addr[2:1] == 2'b01);
assign scop_b_ack = r_scop_b_ack;
`endif
 
//
// SCOPE C
//
wire [31:0] scop_c_data;
wire scop_c_ack, scop_c_stall, scop_c_interrupt;
//
//`else
assign scop_c_data = 32'h00;
assign scop_c_stall = 1'b0;
assign scop_c_interrupt = 1'b0;
 
reg r_scop_c_ack;
always @(posedge i_clk)
r_scop_c_ack <= (wb_stb)&&(scop_sel)&&(wb_addr[2:1] == 2'b10);
assign scop_c_ack = r_scop_c_ack;
//`endif
 
//
// SCOPE D
//
wire [31:0] scop_d_data;
wire scop_d_ack, scop_d_stall, scop_d_interrupt;
//
//`else
assign scop_d_data = 32'h00;
assign scop_d_stall = 1'b0;
assign scop_d_interrupt = 1'b0;
 
reg r_scop_d_ack;
always @(posedge i_clk)
r_scop_d_ack <= (wb_stb)&&(scop_sel)&&(wb_addr[2:1] == 2'b11);
assign scop_d_ack = r_scop_d_ack;
//`endif
 
assign scop_int = scop_a_interrupt
|| scop_b_interrupt
|| scop_c_interrupt
|| scop_d_interrupt;
assign scop_stall = ((wb_addr[2:1]==2'b0)?scop_a_stall
: ((wb_addr[2:1]==2'b01)?scop_b_stall
: ((wb_addr[2:1]==2'b11)?scop_c_stall
: scop_d_stall))); // Will always be 1'b0;
initial scop_ack = 1'b0;
always @(posedge i_clk)
scop_ack <= scop_a_ack | scop_b_ack | scop_c_ack | scop_d_ack;
always @(posedge i_clk)
if (scop_a_ack)
scop_data <= scop_a_data;
else if (scop_b_ack)
scop_data <= scop_b_data;
else if (scop_c_ack)
scop_data <= scop_c_data;
else // if (scop_d_ack)
scop_data <= scop_d_data;
 
endmodule
/rtl/wbuidleint.v
0,0 → 1,125
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wbuidleint.v
//
// Project: FPGA library
//
// Purpose: Creates an output for the interface, inserting idle words and
// words indicating an interrupt has taken place into the output
// stream. Henceforth, the output means more than just bus transaction
// results. It may mean there is no bus transaction result to report,
// or that an interrupt has taken place.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
module wbuidleint(i_clk, i_stb, i_codword, i_cyc, i_busy, i_int,
o_stb, o_codword, o_busy,
i_tx_busy);
input i_clk;
// From the FIFO following the bus executor
input i_stb;
input [35:0] i_codword;
// From the rest of the board
input i_cyc, i_busy, i_int;
// To the next stage
output reg o_stb;
output reg [35:0] o_codword;
output reg o_busy;
// Is the next stage busy?
input i_tx_busy;
 
reg int_request, int_sent;
initial int_request = 1'b0;
always @(posedge i_clk)
if((o_stb)&&(~i_tx_busy)&&(o_codword[35:30]==6'h4))
int_request <= i_int;
else
int_request <= (int_request)||(i_int);
 
 
// Now, for the idle counter
wire idle_expired;
reg idle_state;
reg [35:0] idle_counter;
initial idle_counter = 36'h0000;
always @(posedge i_clk)
if ((i_stb)||(o_stb))
idle_counter <= 36'h000;
else if (~idle_counter[35])
idle_counter <= idle_counter + 36'd43;
 
initial idle_state = 1'b0;
always @(posedge i_clk)
if ((o_stb)&&(~i_tx_busy)&&(o_codword[35:31]==5'h0))
idle_state <= 1'b1;
else if (~idle_counter[35])
idle_state <= 1'b0;
 
assign idle_expired = (~idle_state)&&(idle_counter[35]);
 
initial o_stb = 1'b0;
initial o_busy = 1'b0;
always @(posedge i_clk)
if ((o_stb)&&(i_tx_busy))
begin
o_busy <= 1'b1;
end else if (o_stb) // and not i_tx_busy
begin
// Idle one clock before becoming not busy
o_stb <= 1'b0;
o_busy <= 1'b1;
end else if (o_busy)
o_busy <= 1'b0;
else if (i_stb) // and (~o_busy)&&(~o_stb)
begin // On a valid output, just send it out
// We'll open this strobe, even if the transmitter
// is busy, just 'cause we might otherwise lose it
o_codword <= i_codword;
o_stb <= 1'b1;
o_busy <= 1'b1;
end else if ((int_request)&&(~int_sent))
begin
o_stb <= 1'b1;
o_codword <= { 6'h4, 30'h0000 }; // interrupt codeword
o_busy <= 1'b1;
end else if (idle_expired)
begin // Strobe, if we're not writing or our
// last command wasn't an idle
o_stb <= 1'b1;
o_busy <= 1'b1;
if (i_cyc)
o_codword <= { 6'h1, 30'h0000 }; // idle codeword, bus busy
else
o_codword <= { 6'h0, 30'h0000 };
end
 
initial int_sent = 1'b0;
always @(posedge i_clk)
if ((int_request)&&((~o_stb)&&(~o_busy)&&(~i_stb)))
int_sent <= 1'b1;
else if (~i_int)
int_sent <= 1'b0;
endmodule
/rtl/wbucompress.v
0,0 → 1,283
////////////////////////////////////////////////////////////////////////////////
//
// Filename: wbucompress.v
//
// Project: FPGA library
//
// Purpose: When reading many words that are identical, it makes no sense
// to spend the time transmitting the same thing over and over
// again, especially on a slow channel. Hence this routine uses a table
// lookup to see if the word to be transmitted was one from the recent
// past. If so, the word is replaced with an address of the recently
// transmitted word. Mind you, the table lookup takes one clock per table
// entry, so even if a word is in the table it might not be found in time.
// If the word is not in the table, or if it isn't found due to a lack of
// time, the word is placed into the table while incrementing every other
// table address.
//
// Oh, and on a new address--the table is reset and starts over. This way,
// any time the host software changes, the host software will always start
// by issuing a new address--hence the table is reset for every new piece
// of software that may wish to communicate.
//
//
// 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.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
// All input words are valid codewords. If we can, we make them
// better here.
module wbucompress(i_clk, i_stb, i_codword, o_stb, o_cword, i_busy);
parameter DW=32, CW=36, TBITS=10;
input i_clk, i_stb;
input [(CW-1):0] i_codword;
output wire o_stb;
output wire [(CW-1):0] o_cword;
input i_busy;
 
//
//
// First stage is to compress the address.
// This stage requires one clock.
//
// ISTB,ICODWORD
// ISTB2,IWRD2 ASTB,AWORD
// ISTB3,IWRD3 ASTB2,AWRD2 I_BUSY(1)
// ISTB3,IWRD3 ASTB2,AWRD2 I_BUSY(1)
// ISTB3,IWRD3 ASTB2,AWRD2 I_BUSY(1)
// ISTB3,IWRD3 ASTB2,AWRD2
// ISTB4,IWRD4 ASTB3,AWRD3 I_BUSY(2)
// ISTB4,IWRD4 ASTB3,AWRD3 I_BUSY(2)
// ISTB4,IWRD4 ASTB3,AWRD3 I_BUSY(2)
reg a_stb;
reg [35:0] a_addrword;
wire [31:0] w_addr;
assign w_addr = i_codword[31:0];
always @(posedge i_clk)
if ((i_stb)&&(~a_stb))
begin
if (i_codword[35:32] != 4'h2)
begin
a_addrword <= i_codword;
end else if (w_addr[31:6] == 26'h00)
a_addrword <= { 6'hc, w_addr[ 5:0], 24'h00 };
else if (w_addr[31:12] == 20'h00)
a_addrword <= { 6'hd, w_addr[11:0], 18'h00 };
else if (w_addr[31:18] == 14'h00)
a_addrword <= { 6'he, w_addr[17:0], 12'h00 };
else if (w_addr[31:24] == 8'h00)
a_addrword <= { 6'hf, w_addr[23:0], 6'h00 };
else begin
a_addrword <= i_codword;
end
end
initial a_stb = 1'b0;
always @(posedge i_clk)
if ((i_stb)&&(~a_stb))
a_stb <= i_stb;
else if (~i_busy)
a_stb <= 1'b0;
 
 
//
//
// The next stage attempts to replace data codewords with previous
// codewords that may have been sent. The memory is only allowed
// to be as old as the last new address command. In this fashion,
// any program that wishes to talk to the device can start with a
// known compression table by simply setting the address and then
// reading from the device.
//
 
// We start over any time a new value shows up, and
// the follow-on isn't busy and can take it. Likewise,
// we reset the writer on the compression any time a
// i_clr value comes through (i.e., ~i_cyc or new
// address)
 
wire w_accepted;
assign w_accepted = (a_stb)&&(~i_busy);
 
reg r_stb;
always @(posedge i_clk)
r_stb <= a_stb;
 
wire [35:0] r_word;
assign r_word = a_addrword;
 
 
//
// First step of the compression is keeping track of a compression
// table. And the first part of that is keeping track of what address
// to write into the compression table, and whether or not the entire
// table is full or not. This logic follows:
//
reg [(TBITS-1):0] tbl_addr;
reg tbl_filled;
// First part, write the compression table
always @(posedge i_clk)
// If we send a new address, then reset the table to empty
if (w_accepted)
begin
// Reset on new address (0010xx) and on new compressed
// addresses (0011ll).
if (o_cword[35:33]==3'h1)
tbl_addr <= 0;
// Otherwise, on any valid return result that wasn't
// from our table, for whatever reason (such as didn't
// have the clocks to find it, etc.), increment the
// address to add another value into our table
else if (o_cword[35:33] == 3'b111)
tbl_addr <= tbl_addr + {{(TBITS-1){1'b0}},1'b1};
end
always @(posedge i_clk)
if ((w_accepted)&&(o_cword[35:33]==3'h1)) // on new address
tbl_filled <= 1'b0;
else if (tbl_addr == 10'h3ff)
tbl_filled <= 1'b1;
 
// Now that we know where we are writing into the table, and what
// values of the table are valid, we need to actually write into
// the table.
//
// We can keep this logic really simple by writing on every clock
// and writing junk on many of those clocks, but we'll need to remember
// that the value of the table at tbl_addr is unreliable until tbl_addr
// changes.
//
reg [31:0] compression_tbl [0:((1<<TBITS)-1)];
// Write new values into the table
always @(posedge i_clk)
compression_tbl[tbl_addr] <= { r_word[32:31], r_word[29:0] };
 
// Now that we have a working table, can we use it?
// On any new word, we'll start looking through our codewords.
// If we find any that matches, we're there. We might (or might not)
// make it through the table first. That's irrelevant. We just look
// while we can.
reg tbl_match, nxt_match; // <= (nxt_rd_addr == tbl_addr);
reg [(TBITS-1):0] rd_addr;
reg [(TBITS-1):0] nxt_rd_addr;
initial rd_addr = 0;
initial tbl_match = 0;
always @(posedge i_clk)
begin
nxt_match <= ((nxt_rd_addr-tbl_addr)=={{(TBITS-1){1'b0}},1'b1});
if ((w_accepted)||(~a_stb))
begin
// Keep in mind, if a write was just accepted, then
// rd_addr will need to be reset on the next clock
// when (~a_stb). Hence this must be a two clock
// update
rd_addr <= tbl_addr + {(TBITS){1'b1}};
nxt_rd_addr = tbl_addr + { {(TBITS-1){1'b1}}, 1'b0 };
tbl_match <= 1'b0;
end else if ((~tbl_match)&&(~match)
&&((~nxt_rd_addr[TBITS-1])||(tbl_filled)))
begin
rd_addr <= nxt_rd_addr;
nxt_rd_addr = nxt_rd_addr - { {(TBITS-1){1'b0}}, 1'b1 };
tbl_match <= nxt_match;
end
end
 
reg [1:0] pmatch;
reg dmatch, // Match, on clock 'd'
vaddr; // Was the address valid then?
reg [(DW-1):0] cword;
reg [(TBITS-1):0] caddr, daddr, maddr;
always @(posedge i_clk)
begin
cword <= compression_tbl[rd_addr];
caddr <= rd_addr;
 
dmatch <= (cword == { r_word[32:31], r_word[29:0] });
daddr <= caddr;
maddr <= tbl_addr - caddr;
 
vaddr <= ( {1'b0, caddr} < {tbl_filled, tbl_addr} )
&&(caddr != tbl_addr);
end
 
always @(posedge i_clk)
if ((w_accepted)||(~a_stb))
pmatch <= 0; // rd_addr is set on this clock
else
// cword is set on the next clock, pmatch = 3'b001
// dmatch is set on the next clock, pmatch = 3'b011
pmatch <= { pmatch[0], 1'b1 };
 
reg match;
reg [(TBITS-1):0] matchaddr;
always @(posedge i_clk)
if((w_accepted)||(~a_stb)||(~r_stb))// Reset upon any write
match <= 1'b0;
else if (~match)
begin
// To be a match, the table must not be empty,
match <= (vaddr)&&(dmatch)&&(r_word[35:33]==3'b111)
&&(pmatch == 2'b11);
end
 
reg zmatch, hmatch, fmatch;
always @(posedge i_clk)
if (~match)
begin
matchaddr <= maddr;
fmatch <= (maddr < 10'h521);
zmatch <= (maddr == 10'h1);
hmatch <= (maddr < 10'd10);
end
 
// Did we find something?
wire [(TBITS-1):0] adr_diff;
wire [9:0] adr_dbld;
wire [2:0] adr_hlfd;
assign adr_diff = matchaddr;
assign adr_hlfd = matchaddr[2:0]- 3'd2;
assign adr_dbld = matchaddr- 10'd10;
reg [(CW-1):0] r_cword; // Record our result
always @(posedge i_clk)
begin
if ((~a_stb)||(~r_stb)||(w_accepted))//Reset whenever word gets written
begin
r_cword <= r_word;
end else if ((match)&&(fmatch)) // &&(r_word == a_addrword))
begin
r_cword <= r_word;
if (zmatch) // matchaddr == 1
r_cword[35:30] <= { 5'h3, r_word[30] };
else if (hmatch) // 2 <= matchaddr <= 9
r_cword[35:30] <= { 2'b10, adr_hlfd, r_word[30] };
else // if (adr_diff < 10'd521)
r_cword[35:24] <= { 2'b01, adr_dbld[8:6],
r_word[30], adr_dbld[5:0] };
end else
r_cword <= r_word;
end
 
// Can we do this without a clock delay?
assign o_stb = a_stb;
assign o_cword = (r_stb)?(r_cword):(a_addrword);
endmodule
 
/rtl/lleqspi.v
0,0 → 1,318
///////////////////////////////////////////////////////////////////////////
//
// Filename: lleqspi.v
//
// Project: Wishbone Controlled Quad SPI Flash Controller
//
// Purpose: Reads/writes a word (user selectable number of bytes) of data
// to/from a Quad SPI port. The port is understood to be
// a normal SPI port unless the driver requests four bit mode.
// When not in use, unlike our previous SPI work, no bits will
// toggle.
//
// 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 EQSPI_IDLE 3'h0
`define EQSPI_START 3'h1
`define EQSPI_BITS 3'h2
`define EQSPI_READY 3'h3
`define EQSPI_HOLDING 3'h4
`define EQSPI_STOP 3'h5
`define EQSPI_STOP_B 3'h6
`define EQSPI_RECYCLE 3'h7
 
// Modes
`define EQSPI_MOD_SPI 2'b00
`define EQSPI_MOD_QOUT 2'b10 // Write
`define EQSPI_MOD_QIN 2'b11 // Read
 
module lleqspi(i_clk,
// Module interface
i_wr, i_hold, i_word, i_len, i_spd, i_dir, i_recycle,
o_word, o_valid, o_busy,
// QSPI interface
o_sck, o_cs_n, o_mod, o_dat, i_dat);
input i_clk;
// Chip interface
// Can send info
// i_dir = 1, i_spd = 0, i_hold = 0, i_wr = 1,
// i_word = { 1'b0, 32'info to send },
// i_len = # of bytes in word-1
input i_wr, i_hold;
input [31:0] i_word;
input [1:0] i_len; // 0=>8bits, 1=>16 bits, 2=>24 bits, 3=>32 bits
input i_spd; // 0 -> normal QPI, 1 -> QSPI
input i_dir; // 0 -> read, 1 -> write to SPI
input i_recycle; // 0 = 20ns, 1 = 50ns
output reg [31:0] o_word;
output wire o_valid;
output reg o_busy;
// Interface with the QSPI lines
output reg o_sck;
output reg o_cs_n;
output reg [1:0] o_mod;
output reg [3:0] o_dat;
input [3:0] i_dat;
 
// output wire [22:0] o_dbg;
// assign o_dbg = { state, spi_len,
// o_busy, o_valid, o_cs_n, o_sck, o_mod, o_dat, i_dat };
 
wire i_miso;
assign i_miso = i_dat[1];
 
// These are used in creating a delayed input.
reg rd_input, rd_spd, rd_valid;
 
reg r_spd, r_dir;
reg [3:0] r_recycle;
reg [5:0] spi_len;
reg [31:0] r_word;
reg [30:0] r_input;
reg [2:0] state;
initial state = `EQSPI_IDLE;
initial o_sck = 1'b1;
initial o_cs_n = 1'b1;
initial o_dat = 4'hd;
initial rd_valid = 1'b0;
initial o_busy = 1'b0;
initial r_input = 31'h000;
initial rd_valid = 1'b0;
always @(posedge i_clk)
begin
rd_input <= 1'b0;
rd_spd <= r_spd;
rd_valid <= 1'b0;
if ((state == `EQSPI_IDLE)&&(o_sck))
begin
o_cs_n <= 1'b1;
o_busy <= 1'b0;
o_mod <= `EQSPI_MOD_SPI;
r_word <= i_word;
r_spd <= i_spd;
r_dir <= i_dir;
o_dat <= 4'hc;
r_recycle <= (i_recycle)? 4'h8 : 4'h2; // 4'ha : 4'h4
spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8;
o_sck <= 1'b1;
if (i_wr)
begin
state <= `EQSPI_START;
o_cs_n <= 1'b0;
o_busy <= 1'b1;
end
end else if (state == `EQSPI_START)
begin // We come in here with sck high, stay here 'til sck is low
o_sck <= 1'b0;
if (o_sck == 1'b0)
begin
state <= `EQSPI_BITS;
spi_len<= spi_len - ( (r_spd)? 6'h4 : 6'h1 );
if (r_spd)
r_word <= { r_word[27:0], 4'h0 };
else
r_word <= { r_word[30:0], 1'b0 };
end
o_mod <= (r_spd) ? { 1'b1, r_dir } : `EQSPI_MOD_SPI;
o_cs_n <= 1'b0;
o_busy <= 1'b1;
if (r_spd)
o_dat <= r_word[31:28];
else
o_dat <= { 3'b110, r_word[31] };
end else if (~o_sck)
begin
o_sck <= 1'b1;
o_busy <= ((state != `EQSPI_READY)||(~i_wr));
end else if (state == `EQSPI_BITS)
begin
// Should enter into here with at least a spi_len
// of one, perhaps more
o_sck <= 1'b0;
o_busy <= 1'b1;
if (r_spd)
begin
o_dat <= r_word[31:28];
r_word <= { r_word[27:0], 4'h0 };
spi_len <= spi_len - 6'h4;
if (spi_len == 6'h4)
state <= `EQSPI_READY;
end else begin
o_dat <= { 3'b110, r_word[31] };
r_word <= { r_word[30:0], 1'b0 };
spi_len <= spi_len - 6'h1;
if (spi_len == 6'h1)
state <= `EQSPI_READY;
end
 
rd_input <= 1'b1;
end else if (state == `EQSPI_READY)
begin
o_cs_n <= 1'b0;
o_busy <= 1'b1;
// This is the state on the last clock (both low and
// high clocks) of the data. Data is valid during
// this state. Here we chose to either STOP or
// continue and transmit more.
o_sck <= (i_hold); // No clocks while holding
if((~o_busy)&&(i_wr))// Acknowledge a new request
begin
state <= `EQSPI_BITS;
o_busy <= 1'b1;
o_sck <= 1'b0;
 
// Read the new request off the bus
r_spd <= i_spd;
r_dir <= i_dir;
// Set up the first bits on the bus
o_mod <= (i_spd) ? { 1'b1, i_dir } : `EQSPI_MOD_SPI;
if (i_spd)
begin
o_dat <= i_word[31:28];
r_word <= { i_word[27:0], 4'h0 };
// spi_len <= spi_len - 4;
spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8
- 6'h4;
end else begin
o_dat <= { 3'b110, i_word[31] };
r_word <= { i_word[30:0], 1'b0 };
spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8
- 6'h1;
end
 
// Read a bit upon any transition
rd_input <= 1'b1;
rd_valid <= 1'b1;
end else begin
o_sck <= 1'b1;
state <= (i_hold)?`EQSPI_HOLDING : `EQSPI_STOP;
o_busy <= (~i_hold);
 
// Read a bit upon any transition
rd_valid <= 1'b1;
rd_input <= 1'b1;
end
end else if (state == `EQSPI_HOLDING)
begin
// We need this state so that the o_valid signal
// can get strobed with our last result. Otherwise
// we could just sit in READY waiting for a new command.
//
// Incidentally, the change producing this state was
// the result of a nasty race condition. See the
// commends in wbqspiflash for more details.
//
rd_valid <= 1'b0;
o_cs_n <= 1'b0;
o_busy <= 1'b0;
if((~o_busy)&&(i_wr))// Acknowledge a new request
begin
state <= `EQSPI_BITS;
o_busy <= 1'b1;
o_sck <= 1'b0;
 
// Read the new request off the bus
r_spd <= i_spd;
r_dir <= i_dir;
// Set up the first bits on the bus
o_mod<=(i_spd)?{ 1'b1, i_dir } : `EQSPI_MOD_SPI;
if (i_spd)
begin
o_dat <= i_word[31:28];
r_word <= { i_word[27:0], 4'h0 };
spi_len<= { 1'b0, i_len, 3'b100 };
end else begin
o_dat <= { 3'b110, i_word[31] };
r_word <= { i_word[30:0], 1'b0 };
spi_len<= { 1'b0, i_len, 3'b111 };
end
end else begin
o_sck <= 1'b1;
state <= (i_hold)?`EQSPI_HOLDING : `EQSPI_STOP;
o_busy <= (~i_hold);
end
end else if (state == `EQSPI_STOP)
begin
o_sck <= 1'b1; // Stop the clock
rd_valid <= 1'b0; // Output may have just been valid, but no more
o_busy <= 1'b1; // Still busy till port is clear
state <= `EQSPI_STOP_B;
// Can't change modes for at least one cycle
// o_mod <= `EQSPI_MOD_SPI;
end else if (state == `EQSPI_STOP_B)
begin
o_cs_n <= 1'b1;
o_sck <= 1'b1;
// Do I need this????
// spi_len <= 3; // Minimum CS high time before next cmd
state <= `EQSPI_RECYCLE;
o_busy <= 1'b1;
o_mod <= `EQSPI_MOD_SPI;
end else begin // Recycle state
r_recycle <= r_recycle - 1'b1;
o_cs_n <= 1'b1;
o_sck <= 1'b1;
o_busy <= 1'b1;
o_mod <= `EQSPI_MOD_SPI;
o_dat <= 4'hc;
if (r_recycle[3:1] == 3'h0)
state <= `EQSPI_IDLE;
end
/*
end else begin // Invalid states, should never get here
state <= `EQSPI_STOP;
o_valid <= 1'b0;
o_busy <= 1'b1;
o_cs_n <= 1'b1;
o_sck <= 1'b1;
o_mod <= `EQSPI_MOD_SPI;
o_dat <= 4'hd;
end
*/
end
 
always @(posedge i_clk)
begin
if ((state == `EQSPI_IDLE)||(rd_valid))
r_input <= 31'h00;
else if ((rd_input)&&(r_spd))
r_input <= { r_input[26:0], i_dat };
else if (rd_input)
r_input <= { r_input[29:0], i_miso };
 
if ((rd_valid)&&(r_spd))
o_word <= { r_input[27:0], i_dat };
else if (rd_valid)
o_word <= { r_input[30:0], i_miso };
end
 
assign o_valid = rd_valid;
 
endmodule
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.