URL
https://opencores.org/ocsvn/xulalx25soc/xulalx25soc/trunk
Subversion Repositories xulalx25soc
Compare Revisions
- This comparison shows the changes necessary to convert path
/xulalx25soc
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/trunk/rtl/wbuinput.v
0,0 → 1,62
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: wbuinput.v |
// |
// Project: XuLA2 board |
// |
// 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, 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 |
/trunk/rtl/memdev.v
0,0 → 1,58
/////////////////////////////////////////////////////////////////////////// |
// |
// Filename: memdev.v |
// |
// Project: XuLA2 board |
// |
// 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 access--although getting to the |
// memory from the ZipCPU may cost another cycle or two in access. Either |
// way, operations can be pipelined for greater speed. |
// |
// |
// 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 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 [(DW-1):0] mem [0:((1<<AW)-1)]; |
always @(posedge i_clk) |
o_wb_data <= mem[i_wb_addr]; |
always @(posedge i_clk) |
if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we)) |
mem[i_wb_addr] <= i_wb_data; |
always @(posedge i_clk) |
o_wb_ack <= (i_wb_cyc)&&(i_wb_stb); |
assign o_wb_stall = 1'b0; |
|
endmodule |
/trunk/rtl/wbusixchar.v
0,0 → 1,80
/////////////////////////////////////////////////////////////////////////// |
// |
// Filename: wbusixchar.v |
// |
// Project: XuLA2 board |
// |
// 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, 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; |
|
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 |
|
/trunk/rtl/rtclight.v
0,0 → 1,80
link /home/dan/work/rnd/rtcclock/trunk/rtl/rtclight.v |
trunk/rtl/rtclight.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/wbudecompress.v
===================================================================
--- trunk/rtl/wbudecompress.v (nonexistent)
+++ trunk/rtl/wbudecompress.v (revision 2)
@@ -0,0 +1,118 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: wbudecompress.v
+//
+// Project: XuLA2 board
+//
+// 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, 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;
+
+ wire cmd_write_not_compressed = (i_word[35:33] == 3'h3);
+
+ 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)
+ compression_tbl[wr_addr] <= { i_word[32:31], i_word[29:0] };
+
+ // Clock 0, calculate the table address ... 1 is the smallest address
+ wire [7:0] cmd_addr;
+ assign cmd_addr = wr_addr - { i_word[32:31], i_word[29:24] };
+
+ // Clock one, read the table value
+ reg [31:0] cword;
+ always @(posedge i_clk)
+ cword <= compression_tbl[cmd_addr];
+
+ // Let's also calculate the address, in case this is a compressed
+ // address word
+ reg [24:0] r_addr;
+ always @(posedge i_clk)
+ case(i_word[32:30])
+ 3'b000: r_addr <= { 19'h0, i_word[29:24] };
+ 3'b010: r_addr <= { 13'h0, i_word[29:18] };
+ 3'b100: r_addr <= { 7'h0, i_word[29:12] };
+ 3'b110: r_addr <= { 1'h0, i_word[29: 6] };
+ 3'b001: r_addr <= { {(19){ i_word[29]}}, i_word[29:24] };
+ 3'b011: r_addr <= { {(13){ i_word[29]}}, i_word[29:18] };
+ 3'b101: r_addr <= { {( 7){ i_word[29]}}, i_word[29:12] };
+ 3'b111: r_addr <= { {( 1){ i_word[29]}}, i_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 (~i_word[34])
+ rd_len <= 10'h01 + { 6'h00, i_word[33:31] };
+ else
+ rd_len <= 10'h08 + { 1'b0, i_word[33:31], i_word[29:24] };
+
+
+ // Clock one, copy the input strobe, and input word
+ reg r_stb;
+ reg [35:0] r_word;
+ always @(posedge i_clk)
+ r_stb <= i_stb;
+ always @(posedge i_clk)
+ r_word <= i_word;
+
+ // Clock two, now that the table value is valid, let's set our output
+ // word.
+ always @(posedge i_clk)
+ o_stb <= r_stb;
+ always @(posedge i_clk)
+ if (r_word[35:30] == 6'b101110)
+ o_word <= r_word;
+ else casez(r_word[35:30])
+ 6'b001??0: o_word <= { 4'h0, w_addr[31:0] };
+ 6'b001??1: o_word <= { 3'h1, w_addr[31:30], 1'b1, w_addr[29:0] };
+ 6'b010???: o_word <=
+ { 3'h3, cword[31:30], r_word[30], cword[29:0] };
+ 6'b10????: o_word <= { 5'b11000, r_word[30],
+ 20'h00, rd_len };
+ 6'b11????: o_word <= { 5'b11000, r_word[30],
+ 20'h00, rd_len };
+ default: o_word <= r_word;
+ endcase
+endmodule
+
Index: trunk/rtl/cpu/wbarbiter.v
===================================================================
--- trunk/rtl/cpu/wbarbiter.v (nonexistent)
+++ trunk/rtl/cpu/wbarbiter.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/aux/wbarbiter.v
\ No newline at end of file
trunk/rtl/cpu/wbarbiter.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/div.v
===================================================================
--- trunk/rtl/cpu/div.v (nonexistent)
+++ trunk/rtl/cpu/div.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/core/div.v
\ No newline at end of file
trunk/rtl/cpu/div.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/wbwatchdog.v
===================================================================
--- trunk/rtl/cpu/wbwatchdog.v (nonexistent)
+++ trunk/rtl/cpu/wbwatchdog.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/peripherals/wbwatchdog.v
\ No newline at end of file
trunk/rtl/cpu/wbwatchdog.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/icontrol.v
===================================================================
--- trunk/rtl/cpu/icontrol.v (nonexistent)
+++ trunk/rtl/cpu/icontrol.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/peripherals/icontrol.v
\ No newline at end of file
trunk/rtl/cpu/icontrol.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/zipbones.v
===================================================================
--- trunk/rtl/cpu/zipbones.v (nonexistent)
+++ trunk/rtl/cpu/zipbones.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/zipbones.v
\ No newline at end of file
trunk/rtl/cpu/zipbones.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/cpudefs.v
===================================================================
--- trunk/rtl/cpu/cpudefs.v (nonexistent)
+++ trunk/rtl/cpu/cpudefs.v (revision 2)
@@ -0,0 +1,271 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Filename: cpudefs.v
+//
+// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
+//
+// 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.
+//
+//
+// 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
+//
+//
+///////////////////////////////////////////////////////////////////////////////
+`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
+//
+//
+//
+// 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
Index: trunk/rtl/cpu/pfcache.v
===================================================================
--- trunk/rtl/cpu/pfcache.v (nonexistent)
+++ trunk/rtl/cpu/pfcache.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/core/pfcache.v
\ No newline at end of file
trunk/rtl/cpu/pfcache.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/wbdblpriarb.v
===================================================================
--- trunk/rtl/cpu/wbdblpriarb.v (nonexistent)
+++ trunk/rtl/cpu/wbdblpriarb.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/aux/wbdblpriarb.v
\ No newline at end of file
trunk/rtl/cpu/wbdblpriarb.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/wbpriarbiter.v
===================================================================
--- trunk/rtl/cpu/wbpriarbiter.v (nonexistent)
+++ trunk/rtl/cpu/wbpriarbiter.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/aux/wbpriarbiter.v
\ No newline at end of file
trunk/rtl/cpu/wbpriarbiter.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/pipemem.v
===================================================================
--- trunk/rtl/cpu/pipemem.v (nonexistent)
+++ trunk/rtl/cpu/pipemem.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/core/pipemem.v
\ No newline at end of file
trunk/rtl/cpu/pipemem.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/idecode.v
===================================================================
--- trunk/rtl/cpu/idecode.v (nonexistent)
+++ trunk/rtl/cpu/idecode.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/core/idecode.v
\ No newline at end of file
trunk/rtl/cpu/idecode.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/wbdmac.v
===================================================================
--- trunk/rtl/cpu/wbdmac.v (nonexistent)
+++ trunk/rtl/cpu/wbdmac.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/peripherals/wbdmac.v
\ No newline at end of file
trunk/rtl/cpu/wbdmac.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/memops.v
===================================================================
--- trunk/rtl/cpu/memops.v (nonexistent)
+++ trunk/rtl/cpu/memops.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/core/memops.v
\ No newline at end of file
trunk/rtl/cpu/memops.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/prefetch.v
===================================================================
--- trunk/rtl/cpu/prefetch.v (nonexistent)
+++ trunk/rtl/cpu/prefetch.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/core/prefetch.v
\ No newline at end of file
trunk/rtl/cpu/prefetch.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/zipjiffies.v
===================================================================
--- trunk/rtl/cpu/zipjiffies.v (nonexistent)
+++ trunk/rtl/cpu/zipjiffies.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/peripherals/zipjiffies.v
\ No newline at end of file
trunk/rtl/cpu/zipjiffies.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/zipcounter.v
===================================================================
--- trunk/rtl/cpu/zipcounter.v (nonexistent)
+++ trunk/rtl/cpu/zipcounter.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/peripherals/zipcounter.v
\ No newline at end of file
trunk/rtl/cpu/zipcounter.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/ziptimer.v
===================================================================
--- trunk/rtl/cpu/ziptimer.v (nonexistent)
+++ trunk/rtl/cpu/ziptimer.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/peripherals/ziptimer.v
\ No newline at end of file
trunk/rtl/cpu/ziptimer.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/zipsystem.v
===================================================================
--- trunk/rtl/cpu/zipsystem.v (nonexistent)
+++ trunk/rtl/cpu/zipsystem.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/zipsystem.v
\ No newline at end of file
trunk/rtl/cpu/zipsystem.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/pipefetch.v
===================================================================
--- trunk/rtl/cpu/pipefetch.v (nonexistent)
+++ trunk/rtl/cpu/pipefetch.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/core/pipefetch.v
\ No newline at end of file
trunk/rtl/cpu/pipefetch.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/busdelay.v
===================================================================
--- trunk/rtl/cpu/busdelay.v (nonexistent)
+++ trunk/rtl/cpu/busdelay.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/aux/busdelay.v
\ No newline at end of file
trunk/rtl/cpu/busdelay.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/cpuops.v
===================================================================
--- trunk/rtl/cpu/cpuops.v (nonexistent)
+++ trunk/rtl/cpu/cpuops.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/core/cpuops.v
\ No newline at end of file
trunk/rtl/cpu/cpuops.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/cpu/zipcpu.v
===================================================================
--- trunk/rtl/cpu/zipcpu.v (nonexistent)
+++ trunk/rtl/cpu/zipcpu.v (revision 2)
@@ -0,0 +1 @@
+link ../../../../zipcpu/trunk/rtl/core/zipcpu.v
\ No newline at end of file
trunk/rtl/cpu/zipcpu.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/rtcdate.v
===================================================================
--- trunk/rtl/rtcdate.v (nonexistent)
+++ trunk/rtl/rtcdate.v (revision 2)
@@ -0,0 +1 @@
+link /home/dan/work/rnd/rtcclock/trunk/rtl/rtcdate.v
\ No newline at end of file
trunk/rtl/rtcdate.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/wbgpio.v
===================================================================
--- trunk/rtl/wbgpio.v (nonexistent)
+++ trunk/rtl/wbgpio.v (revision 2)
@@ -0,0 +1,65 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: wbgpio.v
+//
+// Project: XuLA2 board
+//
+// Purpose:
+//
+//
+// 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 wbgpio(i_clk, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_data, o_wb_data,
+ i_gpio, o_gpio, o_int);
+ parameter NIN=16, NOUT=16, DEFAULT=16'h00;
+ input i_clk;
+ //
+ input i_wb_cyc, i_wb_stb, i_wb_we;
+ input [31:0] i_wb_data;
+ output wire [31:0] o_wb_data;
+ //
+ input [(NIN-1):0] i_gpio;
+ output reg [(NOUT-1):0] o_gpio;
+ //
+ output reg o_int;
+
+ // 9LUT's, 16 FF's
+ always @(posedge i_clk)
+ if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we))
+ o_gpio <= ((o_gpio)&(~i_wb_data[(NOUT+16-1):16]))
+ |((i_wb_data[(NOUT-1):0])&(i_wb_data[(NOUT+16-1):16]));
+
+ reg [(NIN-1):0] x_gpio, r_gpio;
+ // 3 LUTs, 33 FF's
+ always @(posedge i_clk)
+ begin
+ x_gpio <= i_gpio;
+ r_gpio <= x_gpio;
+ o_int <= (x_gpio != r_gpio);
+ end
+
+ assign o_wb_data = { {(16-NIN){1'b0}}, r_gpio,
+ {(16-NOUT){1'b0}}, o_gpio };
+endmodule
Index: trunk/rtl/toplevel.v
===================================================================
--- trunk/rtl/toplevel.v (nonexistent)
+++ trunk/rtl/toplevel.v (revision 2)
@@ -0,0 +1,218 @@
+`timescale 10ns / 100ps
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: toplevel.v
+//
+// Project: XuLA2 board
+//
+// Purpose: This is the _top_level_ verilog file for the XuLA2-LX25
+// SoC project. Everything else fits underneath here (logically).
+// This is also the only file that will not go through Verilator. Specific
+// to this file are the Xilinx primitives necessary to build for the
+// XuLA2 board--with the only exception being the ICAPE_SPARTAN6 interface.
+//
+//
+// 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 HELLO_WORLD
+// `define ECHO_TEST
+//
+module toplevel(i_clk_12mhz,
+ i_ram_feedback_clk,
+ o_sf_cs_n, o_sd_cs_n, o_spi_sck, o_spi_mosi, i_spi_miso,
+ o_ram_clk, o_ram_cke, o_ram_cs_n, o_ram_ras_n, o_ram_cas_n,
+ o_ram_we_n, o_ram_bs, o_ram_addr, o_ram_udqm, o_ram_ldqm,
+ io_ram_data,
+ i_gpio, o_gpio, o_pwm, i_rx_uart, o_tx_uart);
+ input i_clk_12mhz;
+ input i_ram_feedback_clk;
+ //
+ // SPI connection(s): Flash and SD Card
+ output wire o_sf_cs_n;
+ output wire o_sd_cs_n;
+ output wire o_spi_sck;
+ output wire o_spi_mosi;
+ input i_spi_miso;
+ //
+ // SD RAM
+ output wire o_ram_clk, o_ram_cke;
+ output wire o_ram_cs_n, o_ram_ras_n, o_ram_cas_n, o_ram_we_n;
+ output wire [1:0] o_ram_bs;
+ output wire [12:0] o_ram_addr;
+ output wire o_ram_udqm, o_ram_ldqm;
+ inout wire [15:0] io_ram_data;
+ //
+ // General purpose I/O
+ // output [31:0] io_chan;
+ input [13:0] i_gpio;
+ output wire [14:0] o_gpio;
+ output wire o_pwm;
+ input i_rx_uart;
+ output wire o_tx_uart;
+
+/////
+ wire [7:0] rx_data, tx_data;
+ wire rx_stb, tx_stb, tx_busy;
+ wire clk_s, reset_s, intermediate_clk, intermediate_clk_n,
+ ck_zero_0;
+ wire ck_zero_1;
+
+ DCM_SP #(
+ .CLKDV_DIVIDE(2.0),
+ .CLKFX_DIVIDE(3),
+ .CLKFX_MULTIPLY(20),
+ .CLKIN_DIVIDE_BY_2("FALSE"),
+ .CLKIN_PERIOD(83.333333),
+ .CLKOUT_PHASE_SHIFT("NONE"),
+ .CLK_FEEDBACK("1X"),
+ .DESKEW_ADJUST("SYSTEM_SYNCHRONOUS"),
+ .DLL_FREQUENCY_MODE("LOW"),
+ .DUTY_CYCLE_CORRECTION("TRUE"),
+ .PHASE_SHIFT(0),
+ .STARTUP_WAIT("TRUE")
+ ) u0( .CLKIN(i_clk_12mhz),
+ .CLK0(ck_zero_0),
+ .CLKFB(ck_zero_0),
+ .CLKFX(clk_s),
+ // .CLKFX180(intermediate_clk_n),
+ .PSEN(1'b0),
+ .RST(1'b0));
+
+ DCM_SP #(
+ .CLKDV_DIVIDE(2),
+ .CLKFX_MULTIPLY(2),
+ .CLKFX_DIVIDE(2),
+ .CLKOUT_PHASE_SHIFT("FIXED"),
+ .CLK_FEEDBACK("1X"),
+ .DESKEW_ADJUST("SYSTEM_SYNCHRONOUS"),
+ .DLL_FREQUENCY_MODE("LOW"),
+ .DUTY_CYCLE_CORRECTION("TRUE"),
+ // At a clock of 92MHz ...
+ // Didn't work at -64, -70, -76 is worse than the other two
+ // -56: Write works, 0x96 reads work
+ // -48: Write fails, 0x0183 or 0x351 is first write that fails
+ // -40: Write fails, 0x071a,176a,0x576
+ // -56 was my working choice at 92 MHz
+ // That would be about a 2.4ns delay from clock to
+ // data.
+ // Suddenly needed to shift to 80 MHz.
+ // -56 no longer sort of works
+ // -49 writes seem to work, reads ... not so much
+ // -45 writes no longer working ??
+ // Read fails @ 0x891, 0x58e, @0x3d65, @0x0aec,
+ // @0x11b8, @0beb, @0x01014
+ // Trying a different approach: register in i_ram_feedback_clk,
+ // followed by o_ram_clk, instead of registering on
+ // clk_s second. Starting build at 1857
+ // Okay, so that was an error, now they are referenced to
+ // intermediate_clk, and I still need to try
+ // intermediate_clk_n if that doesn't work.
+ // THIS NEEDS A DELAY ADJUSTMENT: WBSDRAMNG adjusted from
+ // 6 to 5, and rebuild started at 1914. (finished by 1930)
+ // This one has read bugs at 0x027, 0x030, 0x039, 0x021
+ // etc. So we are worse.
+ // (We also failed timing--I did nothing to fix that)
+ //
+ // tho ... even if this works, it is wrong. The data lines
+ // going into wbsdramng need to be clocked on the system clock
+ // on entrance. Thus, the last always@ block must clock these
+ // lines on clk_s. This is fixed, and cannot change.
+ // This leaves us with a couple options for clocking the first
+ // always block:
+ //
+ // i_ram_feedback_clk, posedge (the right answer ... but
+ // giving me problems)
+ // clk_s pos/neg edge
+ // intermediate_clk posedge (Build started at 1932)
+ // Result: much worse!!
+ // intermediate_clk_n posedge (delay of 6 needed, not
+ // tested as a result.
+ //
+ //
+ .PHASE_SHIFT(-45),
+ .STARTUP_WAIT("TRUE")
+ ) u1( .CLKIN(clk_s),
+ .CLK0(ck_zero_1),
+ .CLKFB(ck_zero_1),
+ .CLK180(intermediate_clk_n),
+ .PSEN(1'b0),
+ .RST(1'b0));
+ assign intermediate_clk = ck_zero_1;
+
+ ODDR2 u2( .Q(o_ram_clk),
+ .C0(intermediate_clk),
+ .C1(intermediate_clk_n),
+ .CE(1'b1), .D0(1'b1), .D1(1'b0), .R(1'b0), .S(1'b0));
+
+ // Generate active-high reset.
+ /*
+ reg r_reset;
+ initial r_reset = 1'b1;
+ always @(posedge i_clk_12mhz)
+ r_reset <= 1'b0;
+ */
+ assign reset_s = 1'b0;
+
+ jtagser jtagtxrx(clk_s, rx_stb, rx_data, tx_stb, tx_data, tx_busy);
+
+
+ wire [15:0] ram_data;
+ wire ram_drive_data;
+ reg [15:0] r_ram_data;
+
+ busmaster #(24,15,14)
+ wbbus(clk_s, reset_s,
+ // External JTAG bus control
+ rx_stb, rx_data, tx_stb, tx_data, tx_busy,
+ // Board lights and switches ... none
+ // SPI/SD-card flash
+ o_sf_cs_n, o_sd_cs_n, o_spi_sck, o_spi_mosi, i_spi_miso,
+ // SDRAM interface
+ // o_ram_clk, // SDRAM clock = clk_100mhz_s = clk_s
+ o_ram_cs_n, // Chip select
+ o_ram_cke, // Clock enable
+ o_ram_ras_n, // Row address strobe
+ o_ram_cas_n, // Column address strobe
+ o_ram_we_n, // Write enable
+ o_ram_bs, // Bank select
+ o_ram_addr, // Address lines
+ ram_drive_data,
+ r_ram_data, // Data lines (input)
+ ram_data, // Data lines (output)
+ { o_ram_udqm, o_ram_ldqm },
+ // GPIO
+ i_gpio, o_gpio, o_pwm, i_rx_uart, o_tx_uart
+ );
+
+ assign io_ram_data = (ram_drive_data) ? ram_data : 16'bzzzz_zzzz_zzzz_zzzz;
+
+ reg [15:0] r_ram_data_ext_clk;
+ // always @(posedge intermediate_clk_n)
+ always @(posedge clk_s)
+ r_ram_data_ext_clk <= io_ram_data;
+ always @(posedge clk_s)
+ r_ram_data <= r_ram_data_ext_clk;
+
+endmodule
Index: trunk/rtl/ICAP_SPARTAN6.v
===================================================================
--- trunk/rtl/ICAP_SPARTAN6.v (nonexistent)
+++ trunk/rtl/ICAP_SPARTAN6.v (revision 2)
@@ -0,0 +1,52 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: ICAP_SPARTAN6.v
+//
+// Project: XuLA2 board
+//
+// Purpose: Verilator cannot build the ICAP_SPARTAN6 primitive for the
+// XuLA2 board. This file is provided for Verilator to build
+// instead. It is *not* a fully functional ICAP_SPARTAN6 primitive by
+// any stretch of the imagination, but it makes the build process work.
+// Reads and writes should "succeed", the values read or written however
+// will be meaningless.
+//
+//
+// 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 ICAP_SPARTAN6(CLK, CE, WRITE, I, O, BUSY);
+ input CLK, CE, WRITE;
+ input [15:0] I;
+ output wire [15:0] O;
+ output wire BUSY;
+
+ reg [15:0] rv;
+ initial rv = 16'h0000;
+ always @(posedge CLK)
+ if ((CE)&&(WRITE))
+ rv <= I;
+ assign O = rv;
+ assign BUSY = 1'b0;
+endmodule
Index: trunk/rtl/20151230-rtl.tjz
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: trunk/rtl/20151230-rtl.tjz
===================================================================
--- trunk/rtl/20151230-rtl.tjz (nonexistent)
+++ trunk/rtl/20151230-rtl.tjz (revision 2)
trunk/rtl/20151230-rtl.tjz
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: trunk/rtl/jtagser.v
===================================================================
--- trunk/rtl/jtagser.v (nonexistent)
+++ trunk/rtl/jtagser.v (revision 2)
@@ -0,0 +1,155 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: jtagser.v
+//
+// Project: XuLA2 board
+//
+// Purpose: All interaction between the FPGA and the host computer on a
+// XuLA board takes place via the JTAG port and the USER
+// instruction. There is no serial port, such as I have had on the other
+// boards I have worked with. (Actually, this SoC project will have a
+// UART port, but that port will not command the bus ...) Nevertheless, I
+// still need to convert this JTAG interface into one that looks like a
+// 32-bit wishbone bus in order to be compatible with all of my other
+// work. This module is part of that conversion. This module turns bits
+// shifted into the JTAG, when it is in the shift-dr state, into bytes
+// plus a strobe output to the rest of the FPGA (you can handle a strobe
+// at all times, right?). Likewise, it takes bytes in for transmitting
+// back to the host and turns them into bits sent across this port.
+//
+//
+// 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.
+//
+// License: GPL, v3, as defined and found on www.gnu.org,
+// http://www.gnu.org/licenses/gpl.html
+//
+//
+///////////////////////////////////////////////////////////////////////////
+//
+//
+module jtagser(i_clk,
+ o_rx_stb, o_rx_data, i_tx_stb, i_tx_data, o_tx_busy);
+ input i_clk;
+ //
+ output reg o_rx_stb;
+ output reg [7:0] o_rx_data;
+ //
+ input i_tx_stb;
+ input [7:0] i_tx_data;
+ output reg o_tx_busy;
+
+ wire w_capture, w_drck, w_reset, w_runtest, w_sel, w_shift, w_update,
+ i_tck, i_tdi, i_tms;
+ reg o_tdo;
+ BSCAN_SPARTAN6 #(.JTAG_CHAIN(1)) BSCANE2_inst(
+ .CAPTURE(w_capture), // CAPTURE output from TAP controller
+ .DRCK(w_drck), // Gated TCK output. When SEL is asserted,
+ // DRCK toggles when CAPTURE or SHIFT are asserted
+ .RESET(w_reset), // RESET output from tap controller
+ .RUNTEST(w_runtest),
+ .SEL(w_sel),
+ .SHIFT(w_shift), // SHIFT output from TAP controller
+ .TCK(i_tck), // Fabric connection to TCK pin
+ .TDI(i_tdi), // Fabric connection to TDI pin
+ .TMS(i_tms), // Fabric connection to TMS pin
+ .UPDATE(w_update), // Update output from TAP controller
+ .TDO(o_tdo)); // Test Data output (TDO) input pin for user func
+
+ reg r_tck, ck_tck, last_tck, edge_tck, r_tdi, ck_tdi,
+ r_shift, ck_shift, r_sel, ck_sel;
+ initial r_tck = 1'b0;
+ initial ck_tck = 1'b0;
+ initial last_tck = 1'b0;
+ initial edge_tck = 1'b0;
+ always @(posedge i_clk)
+ begin // 10 FF's, 1/2 - 1 LUT
+ r_tck <= i_tck; ck_tck <= r_tck;
+ r_shift <= w_shift; ck_shift <= r_shift;
+ r_sel <= w_sel; ck_sel <= r_sel;
+ r_tdi <= i_tdi; ck_tdi <= r_tdi;
+ //
+ last_tck <= ck_tck;
+ edge_tck <= (ck_tck)&&(~last_tck);
+ //
+ end
+
+ reg [2:0] state;
+ initial state <= 0;
+ always @(posedge i_clk) // Exactly 1 6-LUT and 3 FF's
+ if (edge_tck)
+ begin
+ if ((~ck_sel)||(~ck_shift))
+ state <= 0;
+ else if ((ck_sel)&&(ck_shift))
+ state <= state + 3'h1;
+ end
+
+ // Our receive data ... we'll ignore anything less than 8-bits, or
+ // any fractions of a byte.
+ always @(posedge i_clk)
+ if (edge_tck)
+ o_rx_data <= { ck_tdi, o_rx_data[7:1] };
+
+ reg nxt_clk_stb;
+ initial nxt_clk_stb = 1'b0;
+ always @(posedge i_clk)
+ if (edge_tck)
+ nxt_clk_stb <= (edge_tck)&&(state == 3'h7)&&(ck_sel)&&(ck_shift);
+ initial o_rx_stb = 1'b0;
+ always @(posedge i_clk)
+ if (edge_tck)
+ o_rx_stb <= nxt_clk_stb;
+ else o_rx_stb <=1'b0;
+
+ reg [7:0] tx_buf;
+ initial o_tdo = 1'b1;
+ always @(posedge i_clk) // 12 inputs, ... ? LUTs
+ if (edge_tck)
+ o_tdo <= tx_buf[state];
+
+ reg filled;
+ initial filled = 1'b0;
+ always @(posedge i_clk)
+ begin // 2-LUTs
+ if ((i_tx_stb)&&(~o_tx_busy))
+ filled <= 1'b1;
+ else if ((edge_tck)&&(state == 7))
+ filled <= 1'b0;
+ end
+ always @(posedge i_clk)
+ begin // tx_busy <- 8 6-bit LUTs
+ if ((i_tx_stb)&&(~o_tx_busy))
+ o_tx_busy <= 1'b1;
+ else if ((edge_tck)&&(state == 7))
+ o_tx_busy <= 1'b0;
+ else if (state == 0)
+ o_tx_busy <= (filled)||((ck_sel)&&(ck_shift));
+ else if (state == 7)
+ o_tx_busy <= 1'b1; // filled;
+ else
+ o_tx_busy <= 1'b1;
+ end
+ initial tx_buf = 8'hff;
+ always @(posedge i_clk) // 8 FF's, 16-LUTs
+ if ((i_tx_stb)&&(~o_tx_busy))
+ tx_buf <= i_tx_data;
+ else if ((edge_tck)&&(state == 7))
+ tx_buf <= 8'hff;
+
+endmodule
+
Index: trunk/rtl/wbucompactlines.v
===================================================================
--- trunk/rtl/wbucompactlines.v (nonexistent)
+++ trunk/rtl/wbucompactlines.v (revision 2)
@@ -0,0 +1,117 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: wbucompactlines.v
+//
+// Project: XuLA2 board
+//
+// 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, 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
+//
+//
+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
+ 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
Index: trunk/rtl/wbufifo.v
===================================================================
--- trunk/rtl/wbufifo.v (nonexistent)
+++ trunk/rtl/wbufifo.v (revision 2)
@@ -0,0 +1,108 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: wbufifo.v
+//
+// Project: XuLA2 board
+//
+// 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< for a copy.
+//
+// License: GPL, v3, as defined and found on www.gnu.org,
+// http://www.gnu.org/licenses/gpl.html
+//
+//
+///////////////////////////////////////////////////////////////////////////
+`define WBSPI_RESET 6'd0
+// `define WBSPI_RESET_QUADMODE 1
+`define WBSPI_IDLE 6'd2
+// `define WBQSPI_RDIDLE 3 // Idle, but in fast read mode
+// `define WBSPI_WBDECODE 4
+`define WBSPI_WAIT_WIP_CLEAR 6'd5
+`define WBSPI_CHECK_WIP_CLEAR 6'd6
+`define WBSPI_CHECK_WIP_DONE 6'd7
+`define WBSPI_WEN 6'd8
+`define WBSPI_PP 6'd9 // Program page
+// `define WBSPI_QPP 10 // Program page, 4 bit mode
+`define WBSPI_WR_DATA 6'd11
+`define WBSPI_WR_BUS_CYCLE 6'd12
+`define WBSPI_RD_DUMMY 6'd13
+// `define WBSPI_QRD_ADDRESS 14
+// `define WBSPI_QRD_DUMMY 15
+`define WBSPI_READ_CMD 6'd16
+`define WBSPI_READ_DATA 6'd17
+//`define WBSPI_WAIT_TIL_RDIDLE 18
+`define WBSPI_READ_ID_CMD 6'd19
+`define WBSPI_READ_ID 6'd20
+`define WBSPI_READ_STATUS 6'd21
+`define WBSPI_READ_CONFIG 6'd22
+`define WBSPI_WRITE_STATUS 6'd23
+`define WBSPI_WRITE_CONFIG 6'd24
+`define WBSPI_ERASE_WEN 6'd25
+`define WBSPI_ERASE_CMD 6'd26
+`define WBSPI_ERASE_BLOCK 6'd27
+`define WBSPI_CLEAR_STATUS 6'd28
+`define WBSPI_IDLE_CHECK_WIP 6'd29
+`define WBSPI_WAIT_TIL_IDLE 6'd30
+//
+module wbspiflash(i_clk_100mhz,
+ // Internal wishbone connections
+ i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we,
+ i_wb_addr, i_wb_data,
+ // Wishbone return values
+ o_wb_ack, o_wb_stall, o_wb_data,
+ // Quad Spi connections to the external device
+ o_spi_sck, o_spi_cs_n, i_spi_cs_n, o_spi_mosi, i_spi_miso,
+ o_interrupt);
+ parameter AW=18, // Address width, -2 for 32-bit word access
+ PW=6, // Page address width (256 bytes,64 words)
+ SW=10; // Sector address width (4kB, 1kW)
+ // parameter AW, PW, Sw; // Address, page, and sector width(s)
+ input i_clk_100mhz;
+ // Wishbone, inputs first
+ input i_wb_cyc, i_wb_data_stb, i_wb_ctrl_stb, i_wb_we;
+ input [(AW-1):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_spi_sck;
+ output wire o_spi_cs_n;
+ input i_spi_cs_n;
+ output wire o_spi_mosi;
+ input i_spi_miso;
+ // Interrupt line
+ output reg o_interrupt;
+ // output wire [31:0] o_debug;
+
+ reg spi_wr, spi_hold;
+ reg [31:0] spi_in;
+ reg [1:0] spi_len;
+ wire [31:0] spi_out;
+ wire spi_valid, spi_busy;
+ wire w_spi_sck, w_spi_cs_n;
+ wire w_spi_mosi;
+ // wire [22:0] spi_dbg;
+ lldspi lldriver(i_clk_100mhz,
+ spi_wr, spi_hold, spi_in, spi_len,
+ spi_out, spi_valid, spi_busy,
+ w_spi_sck, w_spi_cs_n, i_spi_cs_n, w_spi_mosi,
+ i_spi_miso);
+
+ // Erase status tracking
+ reg write_in_progress, write_protect;
+ reg [(AW-1-SW):0] erased_sector;
+ reg dirty_sector;
+ initial begin
+ write_in_progress = 1'b0;
+ erased_sector = 0;
+ dirty_sector = 1'b1;
+ write_protect = 1'b1;
+ end
+
+ reg [7:0] last_status;
+ reg spif_cmd, spif_override;
+ reg [(AW-1):0] spif_addr;
+ reg [31:0] spif_data;
+ reg [5:0] state;
+ reg spif_ctrl, spif_req;
+ wire [(AW-1-SW):0] spif_sector;
+ assign spif_sector = spif_addr[(AW-1):SW];
+
+ // assign o_debug = { spi_wr, spi_hold, state, spi_dbg };
+
+ initial state = `WBSPI_RESET;
+ initial o_wb_ack = 1'b0;
+ initial o_wb_stall = 1'b1;
+ initial spi_wr = 1'b0;
+ initial spi_len = 2'b00;
+ initial o_interrupt= 1'b0;
+ always @(posedge i_clk_100mhz)
+ begin
+ if (state == `WBSPI_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;
+ last_status <= 8'h00;
+ state <= `WBSPI_IDLE;
+ spif_req <= 1'b0;
+ end else if (state == `WBSPI_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;
+ // Data register access
+ if ((i_wb_data_stb)&&(i_wb_cyc))
+ begin
+
+ if (i_wb_we) // Request to write a page
+ begin
+ 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 <= `WBSPI_WEN;
+
+ o_wb_ack <= 1'b0;
+ o_wb_stall <= 1'b1;
+ end else if (write_protect)
+ begin // whether or not write-in_progress ...
+ // Do nothing on a write protect
+ // violation
+ //
+ o_wb_ack <= 1'b1;
+ o_wb_stall <= 1'b0;
+ end else begin // write is in progress, wait
+ // for it to complete
+ state <= `WBSPI_WAIT_WIP_CLEAR;
+ o_wb_ack <= 1'b0;
+ o_wb_stall <= 1'b1;
+ end
+ end else if (~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_in <= { 8'h0b,
+ {(22-AW){1'b0}},
+ i_wb_addr[(AW-1):0], 2'b00 };
+ state <= `WBSPI_RD_DUMMY;
+ spi_len <= 2'b11; // cmd+addr,32bits
+ end else begin
+ // A write is in progress ... need to stall
+ // the bus until the write is complete.
+ state <= `WBSPI_WAIT_WIP_CLEAR;
+ o_wb_ack <= 1'b0;
+ o_wb_stall <= 1'b1;
+ end
+ end else if ((i_wb_cyc)&&(i_wb_ctrl_stb)&&(i_wb_we))
+ begin
+ o_wb_stall <= 1'b1;
+ case(i_wb_addr[1:0])
+ 2'b00: begin // Erase command register
+ write_protect <= ~i_wb_data[28];
+ o_wb_stall <= 1'b0;
+
+ if((i_wb_data[31])&&(~write_in_progress))
+ begin
+ // Command an erase--ack it immediately
+
+ o_wb_ack <= 1'b1;
+ o_wb_stall <= 1'b0;
+
+ if ((i_wb_data[31])&&(~write_protect))
+ begin
+ spi_wr <= 1'b1;
+ spi_len <= 2'b00;
+ // Send a write enable command
+ spi_in <= { 8'h06, 24'h00 };
+ state <= `WBSPI_ERASE_CMD;
+ o_wb_stall <= 1'b1;
+ end
+ end else if (i_wb_data[31])
+ begin
+ state <= `WBSPI_WAIT_WIP_CLEAR;
+ o_wb_ack <= 1'b1;
+ o_wb_stall <= 1'b1;
+ end else
+ o_wb_ack <= 1'b1;
+ o_wb_stall <= 1'b0;
+ end
+ 2'b01: begin
+ /*
+ // Write the configuration register
+ o_wb_ack <= 1'b1;
+ o_wb_stall <= 1'b1;
+
+ // Need to send a write enable command first
+ spi_wr <= 1'b1;
+ spi_len <= 2'b00; // 8 bits
+ // Send a write enable command
+ spi_in <= { 8'h06, 24'h00 };
+ state <= `WBSPI_WRITE_CONFIG;
+ */
+ o_wb_ack <= 1'b1; // Ack immediately
+ o_wb_stall <= 1'b0; // No stall, but do nothing
+ end
+ 2'b10: begin
+ /*
+ // Write the status register
+ o_wb_ack <= 1'b1; // Ack immediately
+ o_wb_stall <= 1'b1; // Stall other cmds
+ // Need to send a write enable command first
+ spi_wr <= 1'b1;
+ spi_len <= 2'b00; // 8 bits
+ // Send a write enable command
+ spi_in <= { 8'h06, 24'h00 };
+ state <= `WBSPI_WRITE_STATUS;
+ */
+ o_wb_ack <= 1'b1; // Ack immediately
+ o_wb_stall <= 1'b0; // No stall, but do nothing
+ end
+ 2'b11: begin // Write the ID register??? makes no sense
+ o_wb_ack <= 1'b1;
+ o_wb_stall <= 1'b0;
+ end
+ endcase
+ end else if ((i_wb_cyc)&&(i_wb_ctrl_stb)) // &&(~i_wb_we))
+ begin
+ case(i_wb_addr[1:0])
+ 2'b00: begin // Read local register
+ if (write_in_progress) // Read status
+ begin// register, is write still in progress?
+ state <= `WBSPI_READ_STATUS;
+ spi_wr <= 1'b1;
+ spi_len <= 2'b01;// 8 bits out, 8 bits in
+ spi_in <= { 8'h05, 24'h00};
+
+ o_wb_ack <= 1'b0;
+ o_wb_stall <= 1'b1;
+ end else begin // Return w/o talking to device
+ o_wb_ack <= 1'b1;
+ o_wb_stall <= 1'b0;
+ o_wb_data <= { write_in_progress,
+ dirty_sector, spi_busy,
+ ~write_protect,
+ {(28-AW){1'b0}},
+ erased_sector, {(SW){1'b0}} };
+ end end
+ 2'b01: begin // Read configuration register
+ state <= `WBSPI_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 <= `WBSPI_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 <= `WBSPI_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 else if ((~i_wb_cyc)&&(write_in_progress))
+ begin
+ state <= `WBSPI_IDLE_CHECK_WIP;
+ spi_wr <= 1'b1;
+ spi_len <= 2'b01; // 8 bits out, 8 bits in
+ spi_in <= { 8'h05, 24'h00};
+
+ o_wb_ack <= 1'b0;
+ o_wb_stall <= 1'b1;
+ end
+ end else if (state == `WBSPI_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 <= `WBSPI_CHECK_WIP_CLEAR;
+ end
+ end else if (state == `WBSPI_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
+ spif_req<= (spif_req) && (i_wb_cyc);
+ if ((spi_valid)&&(~spi_out[0]))
+ begin
+ state <= `WBSPI_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 == `WBSPI_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;
+ spif_req<= (spif_req) && (i_wb_cyc);
+ if ((o_spi_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
+ spi_in <= { 8'h0b, {(22-AW){1'b0}},
+ spif_addr[(AW-1):0], 2'b00 };
+ state <= `WBSPI_RD_DUMMY;
+ spi_len <= 2'b11; // Send cmd and addr
+ 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 <= `WBSPI_WEN;
+ end
+ 4'b0110: begin // Read status register
+ state <= `WBSPI_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 <= `WBSPI_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 <= `WBSPI_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 == `WBSPI_WEN)
+ begin // We came here after issuing a write enable command
+ spi_wr <= 1'b0;
+ o_wb_ack <= 1'b0;
+ o_wb_stall <= 1'b1;
+ spif_req<= (spif_req) && (i_wb_cyc);
+ if ((~spi_busy)&&(o_spi_cs_n)&&(~spi_wr)) // Let's come to a full stop
+ state <= `WBSPI_PP;
+ end else if (state == `WBSPI_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, {(22-AW){1'b0}}, spif_addr, 2'b00 };
+ spi_len <= 2'b11;
+ spi_hold <= 1'b1;
+ spif_req<= (spif_req) && (i_wb_cyc);
+
+ // Once we get busy, move on
+ if (spi_busy)
+ state <= `WBSPI_WR_DATA;
+ if (spif_sector == erased_sector)
+ dirty_sector <= 1'b1;
+ end else if (state == `WBSPI_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 <= `WBSPI_WR_BUS_CYCLE;
+ end
+ spif_req<= (spif_req) && (i_wb_cyc);
+ end else if (state == `WBSPI_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 <= `WBSPI_WAIT_TIL_IDLE;
+ spi_hold <= 1'b0;
+ end else if (spi_wr)
+ begin // Give the SPI a chance to get busy on the last write
+ // Do nothing here.
+ end else if ((i_wb_data_stb)&&(i_wb_we)
+ &&(i_wb_addr == (spif_addr+1))
+ &&(i_wb_addr[(AW-1):PW]==spif_addr[(AW-1):PW]))
+ begin
+// CHECK ME!
+ 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 <= `WBSPI_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 <= `WBSPI_WAIT_TIL_IDLE;
+ end // Otherwise we stay here
+ end else if (state == `WBSPI_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_hold <= 1'b0;
+ spif_req<= (spif_req) && (i_wb_cyc);
+
+ if ((~spi_busy)&&(~o_spi_cs_n))
+ // Our command was accepted
+ state <= `WBSPI_READ_CMD;
+ end else if (state == `WBSPI_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_hold <= 1'b0;
+ spif_req<= (spif_req) && (i_wb_cyc);
+ if ((spi_valid)&&(spi_len == 2'b11))
+ state <= `WBSPI_READ_DATA;
+ end else if (state == `WBSPI_READ_DATA)
+ begin
+ // Pipelined read support
+ spi_wr <=((i_wb_cyc)&&(i_wb_data_stb)&&(~i_wb_we)&&(i_wb_addr== (spif_addr+1)));
+ spi_in <= 32'h00;
+ spi_len <= 2'b11;
+ // Don't 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)?`WBSPI_READ_DATA
+ : `WBSPI_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 <= `WBSPI_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 == `WBSPI_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_hold <= 1'b0;
+ spif_req <= (spif_req) && (i_wb_cyc);
+ if ((~spi_busy)&&(~o_spi_cs_n)&&(spi_len == 2'b11))
+ // Our command was accepted, now go read the result
+ state <= `WBSPI_READ_ID;
+ end else if (state == `WBSPI_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_spi_cs_n))
+ begin
+ state <= `WBSPI_IDLE;
+ o_wb_stall <= 1'b0;
+ end
+ end else if (state == `WBSPI_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,
+ {(28-AW){1'b0}},
+ erased_sector, {(SW){1'b0}} };
+ end else begin
+ o_wb_data <= { 24'h00, spi_out[7:0] };
+ end
+ end
+
+ if ((~spi_busy)&&(~spi_wr))
+ state <= `WBSPI_IDLE;
+ end else if (state == `WBSPI_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)
+ o_wb_data <= { 24'h00, spi_out[7:0] };
+
+ if ((~spi_busy)&&(~spi_wr))
+ begin
+ state <= `WBSPI_IDLE;
+ o_wb_ack <= spif_req;
+ o_wb_stall <= 1'b0;
+ spif_req <= 1'b0;
+ end
+ end else if (state == `WBSPI_WRITE_CONFIG)
+ begin // We enter immediately after commanding a WEN
+ o_wb_ack <= 1'b0;
+ o_wb_stall <= 1'b1;
+
+ spi_len <= 2'b10;
+ spi_in <= { 8'h01, last_status,
+ spif_data[7:2], 1'b0,spif_data[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 <= `WBSPI_WAIT_TIL_IDLE;
+ write_in_progress <= 1'b1;
+ end
+ end else if (state == `WBSPI_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 <= `WBSPI_CLEAR_STATUS;
+ else
+ state <= `WBSPI_WAIT_TIL_IDLE;
+ end
+ end else if (state == `WBSPI_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;
+ spif_req <= (spif_req) && (i_wb_cyc);
+
+ // Here's the erase command
+ //spi_in <= { 8'hd8, 4'h0, spif_data[17:14], 14'h000, 2'b00 };
+ spi_in <= { 8'h20, 4'h0, spif_data[(AW-1):SW],
+ {(SW){1'b0}}, 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[(AW-1):SW];
+ // 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_spi_cs_n))
+ begin // When our command is accepted, move to the next state
+ spi_wr <= 1'b1;
+ state <= `WBSPI_ERASE_BLOCK;
+ end
+ end else if (state == `WBSPI_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 <= `WBSPI_IDLE;
+ end
+ end else if (state == `WBSPI_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 };
+ last_status[6:5] <= 2'b00;
+ spif_req <= (spif_req) && (i_wb_cyc);
+ if ((spi_wr)&&(~spi_busy))
+ state <= `WBSPI_WAIT_TIL_IDLE;
+ end else if (state == `WBSPI_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
+ 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_spi_cs_n))
+ begin // We can now go to idle and process a command
+ o_wb_stall <= 1'b0;
+ o_wb_ack <= 1'b0;
+ state <= `WBSPI_IDLE;
+ end
+ end else // if (state == `WBSPI_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_spi_cs_n)&&(~spi_wr)) // Wait for a full
+ begin // clearing of the SPI port before moving on
+ state <= `WBSPI_IDLE;
+ o_wb_stall <= 1'b0;
+ o_wb_ack <= 1'b0; // Shouldn't be acking anything here
+ end
+ end
+ end
+
+ // Command and control during the reset sequence
+ assign o_spi_cs_n = w_spi_cs_n;
+ assign o_spi_sck = w_spi_sck;
+ assign o_spi_mosi = w_spi_mosi;
+endmodule
Index: trunk/rtl/wbudeword.v
===================================================================
--- trunk/rtl/wbudeword.v (nonexistent)
+++ trunk/rtl/wbudeword.v (revision 2)
@@ -0,0 +1,96 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: wbudeword.v
+//
+// Project: XuLA2 board
+//
+// 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, 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
+
Index: trunk/rtl/wbuexec.v
===================================================================
--- trunk/rtl/wbuexec.v (nonexistent)
+++ trunk/rtl/wbuexec.v (revision 2)
@@ -0,0 +1,244 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: wbuexec.v
+//
+// Project: XuLA2 board
+//
+// 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
+//
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
+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 reg o_busy;
+ // Wishbone outputs
+ output reg o_wb_cyc, o_wb_stb, 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;
+
+
+ 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)||(~o_wb_we))
+ &&(i_codword[35:30] != 6'h2e));
+
+ reg [9:0] r_acks_needed, r_len;
+
+ reg r_inc, r_wb_err, r_new_addr, r_eow;
+ initial r_wb_err = 1'b0;
+ initial r_new_addr = 1'b1;
+ always @(posedge i_clk)
+ if (i_rst)
+ begin
+ o_stb <= 1'b1;
+ o_codword <= { 6'h3, 30'h000 };
+ r_wb_err <= 1'b0;
+ o_wb_cyc <= 1'b0;
+ end else if (o_wb_cyc) // In the middle of a bus transaction
+ begin
+ o_stb <= 1'b0;
+
+ // Deal with bus errors
+ if (r_wb_err)
+ begin
+ if (w_eow)
+ o_wb_cyc <= 1'b0;
+ o_wb_stb <= 1'b0;
+ end else if ((i_wb_err)||(w_new_err))
+ begin
+ o_wb_cyc <= (~o_busy);
+ o_wb_stb <= 1'b0;
+ r_wb_err <= 1'b1;
+ //
+ o_stb <= 1'b1;
+ o_codword <= { 6'h5, 30'h0000 };
+ //
+ end else if ((o_wb_stb)&&(~i_wb_stall))
+ // Deal with the strobe line
+ begin // Strobe was accepted, busy should be '1' here
+ if (r_len != 0) // read
+ r_len <= r_len - 10'h01;
+ else
+ o_wb_stb <= 1'b0;
+
+ if (o_wb_we)
+ begin // Acknowledge a write
+ o_stb <= 1'b1;
+ o_codword <= { 6'h2, 30'h0000 };
+ end
+
+ if (r_inc)
+ o_wb_addr <= o_wb_addr + 32'h001;
+ end else if (w_newwr) begin
+ r_inc <= i_codword[30];
+ o_wb_data <= w_cod_data;
+ o_wb_stb <= 1'b1;
+ /*
+ end else if (w_newrd)
+ begin // This seems good, but it would stall the bus
+ // BUS ERROR!
+ o_wb_cyc <= 1'b0;
+ o_stb <= 1'b1;
+ o_codword <= { 4'h5, 32'h0000 };
+ */
+ end
+
+ if (w_eow)
+ r_eow <= 1'b1;
+
+ if ((r_wb_err)||(i_wb_err)||(w_new_err))
+ // On an error, flush any inputs ...
+ o_busy <= 1'b0;
+ else if ((w_eow)||(w_newwr)||(r_eow))
+ // On a new command, we're busy again
+ o_busy <= 1'b1;
+ else if((o_wb_we)&&(o_wb_stb)&&(~i_wb_stall)&&(r_len==0))
+ // Once our command completes, if it was a write
+ // command, then
+ o_busy <= 1'b0;
+ else if ((o_wb_we)&&(~o_wb_stb))
+ o_busy <= 1'b0;
+
+ //
+ // Now let's process the acknowledgements
+ //
+ if ((r_wb_err)||(i_wb_err))
+ begin
+ // Acks are irrelevant here
+ end else if (r_acks_needed != 10'h00)
+ begin
+ if ((i_wb_ack)&&(~o_wb_we))
+ begin // Return a read result
+ o_stb <= 1'b1;
+ o_codword <= { 3'h7, i_wb_data[31:30], r_inc,
+ i_wb_data[29:0] };
+ end
+
+ if ((i_wb_ack)&&(~w_newwr))
+ r_acks_needed <= r_acks_needed - 10'h001;
+ else if ((~i_wb_ack)&&(w_newwr))
+ r_acks_needed <= r_acks_needed + 10'h001;
+ end else if (r_acks_needed == 10'h0)
+ begin
+ if ((~o_wb_we)||(r_eow)||(w_eow)) // End our bus cycle
+ o_wb_cyc <= 1'b0;
+ else if (w_newwr)
+ begin
+ r_acks_needed <= r_acks_needed + 10'h001;
+ o_wb_data <= w_cod_data;
+ end
+ end
+ //
+ //
+ //
+ //
+ //
+ end else if (i_stb)
+ //
+ //
+ //
+ //
+ //
+ begin
+ // Default is not to send any codewords
+ o_stb <= 1'b0;
+ // Increment addresses?
+ r_inc <= i_codword[30];
+ // Will this be a write?
+ o_wb_we <= (~i_codword[35]);
+ // Do we need to broadcast a new address?
+ // r_new_addr <= 1'b0;
+ // Errors are all clear by now
+ r_wb_err <= 1'b0;
+ // Need to be not-busy when o_wb_cyc is low
+ o_busy <= 1'b0;
+ //
+ r_eow <= 1'b0;
+ if (i_codword[35:32] == 4'h0)
+ begin // Set a new address
+ r_new_addr <= 1'b1;
+ o_wb_addr <= i_codword[31:0];
+ end else if (i_codword[35:33] == 3'b001)
+ begin // Set a new relative address
+ o_wb_addr <= o_wb_addr
+ + { i_codword[32:31], i_codword[29:0] };
+ r_new_addr <= 1'b1;
+ end else if (i_codword[35:34] == 2'b11)
+ begin // Start a vector read
+ // Address is already set ...
+ // This also depends upon the decoder working
+ r_len <= i_codword[9:0] - 10'h01;
+ o_wb_cyc <= 1'b1;
+ o_wb_stb <= 1'b1;
+ r_acks_needed <= i_codword[9:0];
+ o_busy <= 1'b1;
+
+ if (r_new_addr)
+ begin
+ o_stb <= 1'b1;
+ o_codword <= { 4'h2, o_wb_addr };
+ r_new_addr <= 1'b0;
+ end
+ end else if (~i_codword[35])
+ begin // Start a write transaction, address is alrdy set
+ o_wb_cyc <= 1'b1;
+ o_wb_stb <= 1'b1;
+ o_wb_data <= w_cod_data;
+ o_busy <= 1'b1;
+ r_len <= 10'h00;
+ r_new_addr <= 1'b1;
+ r_acks_needed <= 10'h01;
+ end
+ end else begin
+ r_wb_err <= 1'b0;
+ o_busy <= 1'b0;
+ o_stb <= 1'b0;
+ end
+
+endmodule
Index: trunk/rtl/spiarbiter.v
===================================================================
--- trunk/rtl/spiarbiter.v (nonexistent)
+++ trunk/rtl/spiarbiter.v (revision 2)
@@ -0,0 +1,75 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: spiarbiter.v
+//
+// Project: XuLA2 board
+//
+// Purpose: The XuLA2 offers SPI access to both a FLASH and an SD Card.
+// This simple script arbitrates between the two of those to
+// determine who has access. Drivers for both chips may interact with
+// this arbiter as though it were a SPI device with one additional piece
+// of functionality: the clock line may not be brought low until access
+// has been granted to the chip. Thus, the controller wishing to access
+// its device should pull the CS line low, and then wait to read that
+// its grant line is high. Once CS is low and grant is high, it may
+// then bring CK low and start its transaction.
+//
+// When two or more controllers request access at the same time,
+// access will be given in priority order. Further, access is always
+// granted to device 'A' without request as long as device 'B' isn't
+// busy.
+//
+//
+// 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 spiarbiter(i_clk,
+ i_cs_a_n, i_ck_a, i_mosi_a,
+ i_cs_b_n, i_ck_b, i_mosi_b,
+ o_cs_a_n, o_cs_b_n, o_ck, o_mosi); // , i_en, o_err
+ input i_clk;
+ input i_cs_a_n, i_ck_a, i_mosi_a;
+ // output wire o_grant_a;
+ input i_cs_b_n, i_ck_b, i_mosi_b;
+ // output wire o_grant_b;
+ output wire o_cs_a_n, o_cs_b_n, o_ck, o_mosi;
+
+ reg a_owner;
+ initial a_owner = 1'b1;
+ always @(posedge i_clk)
+ if ((i_cs_a_n)&&(i_cs_b_n))
+ a_owner <= 1'b1; // Keep control
+ else if ((i_cs_a_n)&&(~i_cs_b_n))
+ a_owner <= 1'b0; // Give up control
+
+ // assign o_grant_a = a_owner;
+ // assign o_grant_b = (~a_owner);
+
+ assign o_cs_a_n = (~a_owner)||(~i_cs_a_n);
+ assign o_cs_b_n = ( a_owner)||(~i_cs_b_n);
+ assign o_ck = ( a_owner)?i_ck_a : i_ck_b;
+ assign o_mosi = ( a_owner)?i_mosi_a : i_mosi_b;
+
+endmodule
+
Index: trunk/rtl/wbutohex.v
===================================================================
--- trunk/rtl/wbutohex.v (nonexistent)
+++ trunk/rtl/wbutohex.v (revision 2)
@@ -0,0 +1,77 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: wbutohex.v
+//
+// Project: XuLA2 board
+//
+// 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, 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
+//
+//
+///////////////////////////////////////////////////////////////////////////
+//
+//
+//
+//
+// Copyright: 2015
+//
+//
+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
+
Index: trunk/rtl/wbubus.v
===================================================================
--- trunk/rtl/wbubus.v (nonexistent)
+++ trunk/rtl/wbubus.v (revision 2)
@@ -0,0 +1,137 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: wbubus.v
+//
+// Project: XuLA2 board
+//
+// 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, 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 [31:0] 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
+
+ // 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+1;
+ r_wdt_reset <= 1'b0;
+ end
+
+endmodule
+
Index: trunk/rtl/Makefile
===================================================================
--- trunk/rtl/Makefile (nonexistent)
+++ trunk/rtl/Makefile (revision 2)
@@ -0,0 +1,81 @@
+##########################################################################/
+##
+## Filename: Makefile
+##
+## Project: XuLA2 board
+##
+## Purpose: To direct the Verilator build of the SoC sources.
+##
+##
+## 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 archive
+YYMMDD=`date +%Y%m%d`
+CXX := g++
+FBDIR := .
+VDIRFB:= $(FBDIR)/obj_dir
+
+.PHONY: test
+test: $(VDIRFB)/Vbusmaster__ALL.a
+
+CPUDR := cpu
+CPUSOURCESnD := zipcpu.v cpuops.v pipefetch.v \
+ pfcache.v idecode.v \
+ pipemem.v prefetch.v wbpriarbiter.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: wbgpio.v wbpwmaudio.v rxuart.v txuart.v rtcdate.v rtclight.v
+SOURCES := busmaster.v wbscope.v wbsdram.v \
+ ioslave.v rtclight.v rtcdate.v \
+ wbspiflash.v lldspi.v \
+ $(CPUSOURCES) $(JTAGBUS) $(PERIPHERALS)
+
+$(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: $(SOURCES)
+
+$(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)/
+
Index: trunk/rtl/uartdev.v
===================================================================
--- trunk/rtl/uartdev.v (nonexistent)
+++ trunk/rtl/uartdev.v (revision 2)
@@ -0,0 +1,104 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: uartdev.v
+//
+// Project: XuLA2 board
+//
+// Purpose:
+//
+//
+// 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 uartdev(i_clk, i_rx_uart, o_tx_uart,
+ 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_rx_int, o_tx_int);
+ parameter DEFAULT_SETUP = { 2'b00, 1'b0, 1'b0, 2'b00, 24'd10417 };
+ input i_clk, i_rx_uart;
+ output wire o_tx_uart;
+ 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_rx_int, o_tx_int;
+
+ reg [29:0] r_setup;
+ reg r_tx_stb, rx_rdy;
+ reg [7:0] r_tx_data;
+ initial r_setup = DEFAULT_SETUP;
+ always @(posedge i_clk)
+ if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we))
+ begin
+ case(i_wb_addr)
+ 2'b00: r_setup <= i_wb_data[29:0];
+ 2'b10: begin
+ r_tx_data <= i_wb_data[7:0];
+ r_tx_stb <= 1'b1;
+ end
+ default: begin end
+ endcase
+ end else
+ r_tx_stb <= 1'b0;
+
+ wire rx_stb, rx_break, rx_parity_err, rx_frame_err, rx_ignored;
+ wire [7:0] rx_data;
+ rxuart rxmod(i_clk, 1'b0, r_setup, i_rx_uart,
+ rx_stb, rx_data, rx_break,
+ rx_parity_err, rx_frame_err, rx_ignored);
+
+ wire tx_break, tx_busy;
+ assign tx_break = 1'b0;
+ txuart txmod(i_clk, 1'b0, r_setup, tx_break, r_tx_stb, r_tx_data,
+ o_tx_uart, tx_busy);
+
+ reg [7:0] r_data;
+ always @(posedge i_clk)
+ if (rx_stb)
+ r_data <= rx_data;
+ always @(posedge i_clk)
+ begin
+ if (rx_stb)
+ rx_rdy <= (rx_rdy | rx_stb);
+
+ case(i_wb_addr)
+ 2'b00: o_wb_data <= { 2'b00, r_setup };
+ 2'b01: o_wb_data <= { 2'b00, r_setup };
+ 2'b10: o_wb_data <= { 31'h00,tx_busy };
+ 2'b11: begin
+ if ((i_wb_cyc)&&(i_wb_stb)&&(~i_wb_we))
+ rx_rdy <= 1'b0;
+ o_wb_data <= { 20'h00, rx_break, rx_frame_err, rx_parity_err, ~rx_rdy, r_data };
+ end
+ endcase
+ o_wb_ack <= (i_wb_cyc)&&(i_wb_stb);
+ end
+
+ assign o_wb_stall = 1'b0;
+ assign o_rx_int = rx_stb;
+ assign o_tx_int = ~tx_busy;
+
+endmodule
Index: trunk/rtl/wbpwmaudio.v
===================================================================
--- trunk/rtl/wbpwmaudio.v (nonexistent)
+++ trunk/rtl/wbpwmaudio.v (revision 2)
@@ -0,0 +1,141 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: wbpwmaudio.v
+//
+// Project: A Wishbone Controlled PWM (audio) controller
+//
+// Purpose:
+//
+//
+//
+// 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
+// for a copy.
+//
+// License: GPL, v3, as defined and found on www.gnu.org,
+// http://www.gnu.org/licenses/gpl.html
+//
+//
+///////////////////////////////////////////////////////////////////////////
+module wbpwmaudio(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,
+ o_pwm, o_int);
+ parameter DEFAULT_RELOAD = 32'd2268, // about 44.1 kHz @ 80MHz
+ //DEFAULT_RELOAD = 32'd2268,//about 44.1 kHz @ 100MHz
+ VARIABLE_RATE=0;
+ input i_clk;
+ input i_wb_cyc, i_wb_stb, i_wb_we;
+ input i_wb_addr;
+ input [31:0] i_wb_data;
+ output reg o_wb_ack;
+ output wire o_wb_stall;
+ output wire [31:0] o_wb_data;
+ output reg o_pwm;
+ output reg o_int;
+
+
+ // How often shall we create an interrupt? Every reload_value clocks!
+ // If VARIABLE_RATE==0, this value will never change and will be kept
+ // at the default reload rate (44.1 kHz, for a 100 MHz clock)
+ generate
+ if (VARIABLE_RATE != 0)
+ begin
+ reg [31:0] r_reload_value;
+ initial r_reload_value = DEFAULT_RELOAD;
+ always @(posedge i_clk) // Data write
+ if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr))
+ reload_value <= i_wb_data;
+ wire [31:0] w_reload_value;
+ assign w_reload_value = r_reload_value;
+ end else begin
+ wire [31:0] w_reload_value;
+ assign w_reload_value = DEFAULT_RELOAD;
+ end endgenerate
+
+ reg [31:0] reload_value, timer;
+ initial reload_value = DEFAULT_RELOAD;
+ always @(posedge i_clk)
+ if (timer == 0)
+ timer <= reload_value;
+ else
+ timer <= timer - 1;
+
+ reg [15:0] sample_out;
+ always @(posedge i_clk)
+ if (timer == 0)
+ sample_out <= next_sample;
+
+
+ reg [15:0] next_sample;
+ reg next_valid;
+ initial next_valid = 1'b1;
+ initial next_sample = 16'h8000;
+ always @(posedge i_clk) // Data write
+ if ((i_wb_cyc)&&(i_wb_stb)&&((~i_wb_addr)||(VARIABLE_RATE==0)))
+ begin
+ // Write with two's complement data, convert it
+ // internally to binary offset
+ next_sample <= { ~i_wb_data[15], i_wb_data[14:0] };
+ next_valid <= 1'b1;
+ end else if (timer == 0)
+ next_valid <= 1'b0;
+
+ initial o_int = 1'b0;
+ always @(posedge i_clk)
+ o_int <= (~next_valid);
+
+ reg [15:0] pwm_counter;
+ initial pwm_counter = 16'h00;
+ always @(posedge i_clk)
+ pwm_counter <= pwm_counter + 1;
+
+ wire [15:0] br_counter;
+ genvar k;
+ generate for(k=0; k<16; k=k+1)
+ begin
+ assign br_counter[k] = pwm_counter[15-k];
+ end endgenerate
+
+ always @(posedge i_clk)
+ o_pwm <= (sample_out < br_counter);
+
+ generate
+ if (VARIABLE_RATE == 0)
+ begin
+ assign o_wb_data = { 15'h00, o_int, sample_out };
+ end else begin
+ reg [31:0] r_wb_data;
+ always @(posedge i_clk)
+ if (i_wb_addr)
+ r_wb_data <= reload_value;
+ else
+ r_wb_data <= { 15'h00, o_int, sample_out };
+ assign o_wb_data = r_wb_data;
+ end endgenerate
+
+ 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
Index: trunk/rtl/wbuoutput.v
===================================================================
--- trunk/rtl/wbuoutput.v (nonexistent)
+++ trunk/rtl/wbuoutput.v (revision 2)
@@ -0,0 +1,109 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: wbuoutput.v
+//
+// Project: XuLA2 board
+//
+// 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, 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
Index: trunk/rtl/flash_config.v
===================================================================
--- trunk/rtl/flash_config.v (nonexistent)
+++ trunk/rtl/flash_config.v (revision 2)
@@ -0,0 +1,48 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: flashconfig.v
+//
+// Project: XuLA2 board
+//
+// 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
+// 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
+//
Index: trunk/rtl/wbureadcw.v
===================================================================
--- trunk/rtl/wbureadcw.v (nonexistent)
+++ trunk/rtl/wbureadcw.v (revision 2)
@@ -0,0 +1,126 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: wbureadcw.v
+//
+// Project: XuLA2 board
+//
+// 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, 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;
+
+ 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
+
+ reg [1:0] lastcw;
+ 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
+
Index: trunk/rtl/legal.v
===================================================================
--- trunk/rtl/legal.v (nonexistent)
+++ trunk/rtl/legal.v (revision 2)
@@ -0,0 +1,33 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename:
+//
+// Project: XuLA2 board
+//
+// Purpose:
+//
+//
+// 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
+//
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+//
Index: trunk/rtl/wbicapesimple.v
===================================================================
--- trunk/rtl/wbicapesimple.v (nonexistent)
+++ trunk/rtl/wbicapesimple.v (revision 2)
@@ -0,0 +1 @@
+link ../../../wbicapetwo/trunk/rtl/wbicapesimple.v
\ No newline at end of file
trunk/rtl/wbicapesimple.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/rxuart.v
===================================================================
--- trunk/rtl/rxuart.v (nonexistent)
+++ trunk/rtl/rxuart.v (revision 2)
@@ -0,0 +1,302 @@
+/////////////////////////////////////////////////////////////////////////
+//
+//
+// Filename: rxuart.v
+//
+// Project: FPGA library development (Spartan 3E development board)
+//
+// 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
+// Gisselquist Technology, LLC
+//
+// Copyright: 2015
+//
+//
+/////////////////////////////////////////////////////////////////////////
+//
+// This software is the ownership of Gisselquist Technology, LLC, and as
+// such it is proprietary. It is provided without any warrantees, either
+// express or implied, so that it may be tested. Upon completion, I ask
+// that working code be returned and not further distributed beyond those
+// that it is originally offered to.
+//
+// Thank you.
+//
+
+// 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;
+
+ always @(posedge i_clk)
+ o_break <=((chg_counter >= break_condition)&&(~ck_uart))? 1'b1:1'b0;
+
+ reg [3:0] state;
+ reg [27:0] baud_counter;
+ reg [7:0] data_reg;
+ reg calc_parity;
+ 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; // 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 ((ck_uart)&&(chg_counter >= break_condition))
+ // 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 ((~ck_uart)&&(chg_counter >= break_condition))
+ 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
+ data_reg <= 8'h00; o_data <= 8'h00; o_wr <= 1'b0;
+ baud_counter <= clocks_per_baud - 28'h01;
+ if ((ck_uart == 1'b0)&&(chg_counter > half_baud))
+ 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 (baud_counter == 0)
+ 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 - 1;
+ o_parity_err <= 1'b0;
+ o_frame_err <= 1'b0;
+ end
+ end
+
+endmodule
+
+
Index: trunk/rtl/txuart.v
===================================================================
--- trunk/rtl/txuart.v (nonexistent)
+++ trunk/rtl/txuart.v (revision 2)
@@ -0,0 +1,217 @@
+/////////////////////////////////////////////////////////////////////////
+//
+//
+// Filename: txuart.v
+//
+// Project: FPGA library development (Spartan 3E development board)
+//
+// 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
+// Gisselquist Technology, LLC
+//
+// Copyright: 2015
+//
+//
+/////////////////////////////////////////////////////////////////////////
+//
+// This software is the ownership of Gisselquist Technology, LLC, and as
+// such it is proprietary. It is provided without any warrantees, either
+// express or implied, so that it may be tested. Upon completion, I ask
+// that working code be returned and not further distributed beyond those
+// that it is originally offered to.
+//
+// Thank you.
+//
+`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, 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;
+
+ initial o_uart = 1'b1;
+ initial o_busy = 1'b1;
+ initial state = `TXU_IDLE;
+ // initial baud_counter = clocks_per_baud;
+ always @(posedge i_clk)
+ begin
+ if (i_reset)
+ begin
+ baud_counter <= clocks_per_baud;
+ o_uart <= 1'b1;
+ o_busy <= 1'b1;
+ state <= `TXU_IDLE;
+ lcl_data <= 8'h0;
+ calc_parity <= 1'b0;
+ end else if (i_break)
+ begin
+ baud_counter <= break_condition;
+ o_uart <= 1'b0;
+ state <= `TXU_BREAK;
+ calc_parity <= 1'b0;
+ o_busy <= 1'b1;
+ end else if (baud_counter != 0)
+ begin // o_busy needs to be set coming into here
+ baud_counter <= baud_counter - 1;
+ o_busy <= 1'b1;
+ end else if (state == `TXU_BREAK)
+ begin
+ state <= `TXU_IDLE;
+ o_busy <= 1'b1;
+ o_uart <= 1'b1;
+ calc_parity <= 1'b0;
+ // Give us two stop bits before becoming available
+ baud_counter <= clocks_per_baud<<2;
+ end else if (state == `TXU_IDLE) // STATE_IDLE
+ begin
+ // baud_counter <= 0;
+ r_setup <= i_setup;
+ calc_parity <= 1'b0;
+ if ((i_wr)&&(~o_busy))
+ begin // Immediately start us off with a start bit
+ o_uart <= 1'b0;
+ o_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;
+ o_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;
+ o_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 o_busy, since we need to wait
+ // for the baud clock to finish counting
+ // out this last bit.
+ end
+ end
+ end
+
+endmodule
+
+
+
+
Index: trunk/rtl/lldspi.v
===================================================================
--- trunk/rtl/lldspi.v (nonexistent)
+++ trunk/rtl/lldspi.v (revision 2)
@@ -0,0 +1,222 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: lldspi.v
+//
+// Project: XuLA2 board
+//
+// 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 two bit mode. (Not yet
+// supported.) When not in use, no bits will toggle.
+//
+// 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
+// for a copy.
+//
+// License: GPL, v3, as defined and found on www.gnu.org,
+// http://www.gnu.org/licenses/gpl.html
+//
+//
+///////////////////////////////////////////////////////////////////////////
+`define SPI_IDLE 3'h0
+`define SPI_START 3'h1
+`define SPI_BITS 3'h2
+`define SPI_READY 3'h3
+`define SPI_HOLDING 3'h4
+`define SPI_STOP 3'h5
+`define SPI_STOP_B 3'h6
+
+// Modes
+// `define SPI_MOD_SPI 2'b00
+// `define QSPI_MOD_QOUT 2'b10
+// `define QSPI_MOD_QIN 2'b11
+
+module lldspi(i_clk,
+ // Module interface
+ i_wr, i_hold, i_word, i_len,
+ o_word, o_valid, o_busy,
+ // QSPI interface
+ o_sck, o_cs_n, i_cs_n, o_mosi, i_miso);
+ input i_clk;
+ // Chip interface
+ // Can send info
+ // 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
+ output reg [31:0] o_word;
+ output reg o_valid, o_busy;
+ // Interface with the QSPI lines
+ output reg o_sck;
+ output reg o_cs_n;
+ input i_cs_n; // Feedback from the arbiter
+ output reg o_mosi;
+ input i_miso;
+
+ reg [5:0] spi_len;
+ reg [31:0] r_word;
+ reg [30:0] r_input;
+ reg [2:0] state;
+ initial state = `SPI_IDLE;
+ initial o_sck = 1'b1;
+ initial o_cs_n = 1'b1;
+ initial o_mosi = 1'b0;
+ initial o_valid = 1'b0;
+ initial o_busy = 1'b0;
+ initial r_input = 31'h000;
+ always @(posedge i_clk)
+ if ((state == `SPI_IDLE)&&(o_sck))
+ begin
+ o_cs_n <= 1'b1;
+ o_valid <= 1'b0;
+ o_busy <= 1'b0;
+ if (i_wr)
+ begin
+ r_word <= i_word;
+ state <= `SPI_START;
+ spi_len<= { 1'b0, i_len, 3'b000 } + 6'h8;
+ o_cs_n <= 1'b0;
+ o_busy <= 1'b1;
+ o_sck <= 1'b1;
+ end
+ end else if (state == `SPI_START)
+ begin // We come in here with sck high, stay here 'til sck is low
+ if (~i_cs_n) // Wait 'til the bus has been granted
+ o_sck <= 1'b0;
+ if (o_sck == 1'b0)
+ begin
+ state <= `SPI_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_valid <= 1'b0;
+ o_mosi <= r_word[31];
+ end else if (~o_sck)
+ begin
+ o_sck <= 1'b1;
+ o_busy <= ((state != `SPI_READY)||(~i_wr));
+ o_valid <= 1'b0;
+ end else if (state == `SPI_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 <= `SPI_READY;
+
+ o_valid <= 1'b0;
+ r_input <= { r_input[29:0], i_miso };
+ end else if (state == `SPI_READY)
+ begin
+ o_valid <= 1'b0;
+ 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 <= `SPI_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'b000 } + 6'h8-6'h1;
+
+ // Read a bit upon any transition
+ o_valid <= 1'b1;
+ r_input <= { r_input[29:0], i_miso };
+ o_word <= { r_input[30:0], i_miso };
+ end else begin
+ o_sck <= 1'b1;
+ state <= (i_hold)?`SPI_HOLDING : `SPI_STOP;
+ o_busy <= (~i_hold);
+
+ // Read a bit upon any transition
+ o_valid <= 1'b1;
+ r_input <= { r_input[29:0], i_miso };
+ o_word <= { r_input[30:0], i_miso };
+ end
+ end else if (state == `SPI_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.
+ //
+ o_valid <= 1'b0;
+ o_cs_n <= 1'b0;
+ o_busy <= 1'b0;
+ if((~o_busy)&&(i_wr))// Acknowledge a new request
+ begin
+ state <= `SPI_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 };
+ end else begin
+ o_sck <= 1'b1;
+ state <= (i_hold)?`SPI_HOLDING : `SPI_STOP;
+ o_busy <= (~i_hold);
+ end
+ end else if (state == `SPI_STOP)
+ begin
+ o_sck <= 1'b1; // Stop the clock
+ o_valid <= 1'b0; // Output may have just been valid, but no more
+ o_busy <= 1'b1; // Still busy till port is clear
+ state <= `SPI_STOP_B;
+ end else if (state == `SPI_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 <= `SPI_IDLE;
+ o_valid <= 1'b0;
+ o_busy <= 1'b1;
+ end else begin // Invalid states, should never get here
+ state <= `SPI_STOP;
+ o_valid <= 1'b0;
+ o_busy <= 1'b1;
+ o_cs_n <= 1'b1;
+ o_sck <= 1'b1;
+ end
+
+endmodule
+
Index: trunk/rtl/builddate.v
===================================================================
--- trunk/rtl/builddate.v (nonexistent)
+++ trunk/rtl/builddate.v (revision 2)
@@ -0,0 +1 @@
+link ../20151230-build.v
\ No newline at end of file
trunk/rtl/builddate.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/wbsdram.v
===================================================================
--- trunk/rtl/wbsdram.v (nonexistent)
+++ trunk/rtl/wbsdram.v (revision 2)
@@ -0,0 +1,489 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: wbsdram.v
+//
+// Project: XuLA2 board
+//
+// Purpose: Provide 32-bit wishbone access to the SDRAM memory on a XuLA2
+// LX-25 board. Specifically, on each access, the controller will
+// activate an appropriate bank of RAM (the SDRAM has four banks), and
+// then issue the read/write command. In the case of walking off the
+// bank, the controller will activate the next bank before you get to it.
+// Upon concluding any wishbone access, all banks will be precharged and
+// returned to idle.
+//
+// This particular implementation represents a second generation version
+// because my first version was too complex. To speed things up, this
+// version includes an extra wait state where the wishbone inputs are
+// clocked into a flip flop before any action is taken on them.
+//
+// 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
+// for a copy.
+//
+// License: GPL, v3, as defined and found on www.gnu.org,
+// http://www.gnu.org/licenses/gpl.html
+//
+//
+/////////////////////////////////////////////////////////////////////////////
+//
+`define DMOD_GETINPUT 1'b0
+`define DMOD_PUTOUTPUT 1'b1
+`define RAM_OPERATIONAL 2'b00
+`define RAM_POWER_UP 2'b01
+`define RAM_SET_MODE 2'b10
+`define RAM_INITIAL_REFRESH 2'b11
+
+module wbsdram(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,
+ o_ram_cs_n, o_ram_cke, o_ram_ras_n, o_ram_cas_n, o_ram_we_n,
+ o_ram_bs, o_ram_addr,
+ o_ram_dmod, i_ram_data, o_ram_data, o_ram_dqm,
+ o_debug);
+ parameter RDLY = 6;
+ input i_clk;
+ // Wishbone
+ // inputs
+ input i_wb_cyc, i_wb_stb, i_wb_we;
+ input [22:0] i_wb_addr;
+ input [31:0] i_wb_data;
+ // outputs
+ output wire o_wb_ack;
+ output reg o_wb_stall;
+ output wire [31:0] o_wb_data;
+ // SDRAM control
+ output wire o_ram_cke;
+ output reg o_ram_cs_n,
+ o_ram_ras_n, o_ram_cas_n, o_ram_we_n;
+ output reg [1:0] o_ram_bs;
+ output reg [12:0] o_ram_addr;
+ output reg o_ram_dmod;
+ input [15:0] i_ram_data;
+ output reg [15:0] o_ram_data;
+ output reg [1:0] o_ram_dqm;
+ output wire [31:0] o_debug;
+
+
+ // Calculate some metrics
+
+ //
+ // First, do we *need* a refresh now --- i.e., must we break out of
+ // whatever we are doing to issue a refresh command?
+ //
+ // The step size here must be such that 8192 charges may be done in
+ // 64 ms. Thus for a clock of:
+ // ClkRate(MHz) (64ms/1000(ms/s)*ClkRate)/8192
+ // 100 MHz 781
+ // 96 MHz 750
+ // 92 MHz 718
+ // 88 MHz 687
+ // 84 MHz 656
+ // 80 MHz 625
+ //
+ reg need_refresh;
+ reg [9:0] refresh_clk;
+ wire refresh_cmd;
+ assign refresh_cmd = (~o_ram_cs_n)&&(~o_ram_ras_n)&&(~o_ram_cas_n)&&(o_ram_we_n);
+ initial refresh_clk = 0;
+ always @(posedge i_clk)
+ begin
+ if (refresh_cmd)
+ refresh_clk <= 10'd625; // Make suitable for 80 MHz clk
+ else if (|refresh_clk)
+ refresh_clk <= refresh_clk - 10'h1;
+ end
+ initial need_refresh = 1'b0;
+ always @(posedge i_clk)
+ need_refresh <= (refresh_clk == 10'h00)&&(~refresh_cmd);
+
+ reg in_refresh;
+ reg [2:0] in_refresh_clk;
+ initial in_refresh_clk = 3'h0;
+ always @(posedge i_clk)
+ if (refresh_cmd)
+ in_refresh_clk <= 3'h6;
+ else if (|in_refresh_clk)
+ in_refresh_clk <= in_refresh_clk - 3'h1;
+ always @(posedge i_clk)
+ in_refresh <= (in_refresh_clk != 3'h0)||(refresh_cmd);
+
+
+ reg [2:0] bank_active [0:3];
+ reg [(RDLY-1):0] r_barrell_ack;
+ reg r_pending;
+ reg r_we;
+ reg [22:0] r_addr;
+ reg [31:0] r_data;
+ reg [12:0] bank_row [0:3];
+
+
+ //
+ // Second, do we *need* a precharge now --- must be break out of
+ // whatever we are doing to issue a precharge command?
+ //
+ // Keep in mind, the number of clocks to wait has to be reduced by
+ // the amount of time it may take us to go into a precharge state.
+ //
+ reg [3:0] need_precharge;
+ genvar k;
+ generate
+ for(k=0; k<4; k=k+1)
+ begin : precharge_genvar_loop
+ wire precharge_cmd;
+ assign precharge_cmd = ((~o_ram_cs_n)&&(~o_ram_ras_n)&&(o_ram_cas_n)&&(~o_ram_we_n)
+ &&((o_ram_addr[10])||(o_ram_bs == k[1:0])))
+ // Also on read or write with precharge
+ ||(~o_ram_cs_n)&&(o_ram_ras_n)&&(~o_ram_cas_n)&&(o_ram_addr[10]);
+
+ reg [9:0] precharge_clk;
+ initial precharge_clk = 0;
+ always @(posedge i_clk)
+ begin
+ if ((precharge_cmd)||(bank_active[k] == 0))
+ precharge_clk <= 10'd1000;
+ else if (|precharge_clk)
+ precharge_clk <= precharge_clk - 10'h1;
+ end
+ initial need_precharge[k] = 1'b0;
+ always @(posedge i_clk)
+ need_precharge[k] <= ~(|precharge_clk);
+ end // precharge_genvar_loop
+ endgenerate
+
+
+
+ reg [15:0] clocks_til_idle;
+ reg [1:0] r_state;
+ wire bus_cyc;
+ assign bus_cyc = ((i_wb_cyc)&&(i_wb_stb)&&(~o_wb_stall));
+ reg nxt_dmod;
+
+ // Pre-process pending operations
+ wire pending;
+ initial r_pending = 1'b0;
+ reg [22:5] fwd_addr;
+ always @(posedge i_clk)
+ if (bus_cyc)
+ begin
+ r_pending <= 1'b1;
+ r_we <= i_wb_we;
+ r_addr <= i_wb_addr;
+ r_data <= i_wb_data;
+ fwd_addr <= i_wb_addr[22:5] + 18'h01;
+ end else if ((~o_ram_cs_n)&&(o_ram_ras_n)&&(~o_ram_cas_n))
+ r_pending <= 1'b0;
+ else if (~i_wb_cyc)
+ r_pending <= 1'b0;
+
+ reg r_bank_valid;
+ initial r_bank_valid = 1'b0;
+ always @(posedge i_clk)
+ if (bus_cyc)
+ r_bank_valid <=((bank_active[i_wb_addr[9:8]][2])
+ &&(bank_row[i_wb_addr[9:8]]==r_addr[22:10]));
+ else
+ r_bank_valid <= ((bank_active[r_addr[9:8]][2])
+ &&(bank_row[r_addr[9:8]]==r_addr[22:10]));
+ reg fwd_bank_valid;
+ initial fwd_bank_valid = 0;
+ always @(posedge i_clk)
+ fwd_bank_valid <= ((bank_active[fwd_addr[9:8]][2])
+ &&(bank_row[fwd_addr[9:8]]==fwd_addr[22:10]));
+
+ assign pending = (r_pending)&&(o_wb_stall);
+
+ // Address MAP:
+ // 23-bits bits in, 24-bits out
+ //
+ // 222 1111 1111 1100 0000 0000
+ // 210 9876 5432 1098 7654 3210
+ // rrr rrrr rrrr rrBB cccc cccc 0
+ // 8765 4321 0
+ //
+ initial r_barrell_ack = 0;
+ initial r_state = `RAM_POWER_UP;
+ initial clocks_til_idle = 16'd20500;
+ initial o_wb_stall = 1'b1;
+ initial o_ram_dmod = `DMOD_GETINPUT;
+ initial nxt_dmod = `DMOD_GETINPUT;
+ initial o_ram_cs_n = 1'b0;
+ initial o_ram_ras_n = 1'b1;
+ initial o_ram_cas_n = 1'b1;
+ initial o_ram_we_n = 1'b1;
+ initial o_ram_dqm = 2'b11;
+ assign o_ram_cke = 1'b1;
+ initial bank_active[0] = 3'b000;
+ initial bank_active[1] = 3'b000;
+ initial bank_active[2] = 3'b000;
+ initial bank_active[3] = 3'b000;
+ always @(posedge i_clk)
+ if (r_state == `RAM_OPERATIONAL)
+ begin
+ o_wb_stall <= (r_pending)||(bus_cyc);
+ r_barrell_ack <= r_barrell_ack >> 1;
+ nxt_dmod <= `DMOD_GETINPUT;
+ o_ram_dmod <= nxt_dmod;
+
+ //
+ bank_active[0] <= { bank_active[0][2], bank_active[0][2:1] };
+ bank_active[1] <= { bank_active[1][2], bank_active[1][2:1] };
+ bank_active[2] <= { bank_active[2][2], bank_active[2][2:1] };
+ bank_active[3] <= { bank_active[3][2], bank_active[3][2:1] };
+ //
+ o_ram_cs_n <= (~i_wb_cyc);
+ // o_ram_cke <= 1'b1;
+ o_ram_dqm <= 2'b0;
+ if (|clocks_til_idle[2:0])
+ clocks_til_idle[2:0] <= clocks_til_idle[2:0] - 3'h1;
+
+ // Default command is a
+ // NOOP if (i_wb_cyc)
+ // Device deselect if (~i_wb_cyc)
+ // o_ram_cs_n <= (~i_wb_cyc) above, NOOP
+ o_ram_ras_n <= 1'b1;
+ o_ram_cas_n <= 1'b1;
+ o_ram_we_n <= 1'b1;
+
+ // Don't drive the bus normally, let it float unless we wish
+ // to give it a command
+ o_ram_data <= r_data[15:0];
+
+ if ((~i_wb_cyc)||(|need_precharge)||(need_refresh))
+ begin // Issue a precharge all command (if any banks are open),
+ // otherwise an autorefresh command
+ if ((bank_active[0][2:1]==2'b10)
+ ||(bank_active[1][2:1]==2'b10)
+ ||(bank_active[2][2:1]==2'b10)
+ ||(bank_active[3][2:1]==2'b10))
+ begin
+ // Do nothing this clock
+ // Can't precharge a bank immediately after
+ // activating it
+ end else if (bank_active[0][2]
+ ||(bank_active[1][2])
+ ||(bank_active[2][2])
+ ||(bank_active[3][2]))
+ begin // Close all active banks
+ o_ram_cs_n <= 1'b0;
+ o_ram_ras_n <= 1'b0;
+ o_ram_cas_n <= 1'b1;
+ o_ram_we_n <= 1'b0;
+ o_ram_addr[10] <= 1'b1;
+ bank_active[0][2] <= 1'b0;
+ bank_active[1][2] <= 1'b0;
+ bank_active[2][2] <= 1'b0;
+ bank_active[3][2] <= 1'b0;
+ end else if ((|bank_active[0])
+ ||(|bank_active[1])
+ ||(|bank_active[2])
+ ||(|bank_active[3]))
+ // Can't precharge yet, the bus is still busy
+ begin end else if ((~in_refresh)&&((refresh_clk[9:8]==2'b00)||(need_refresh)))
+ begin // Send autorefresh command
+ o_ram_cs_n <= 1'b0;
+ o_ram_ras_n <= 1'b0;
+ o_ram_cas_n <= 1'b0;
+ o_ram_we_n <= 1'b1;
+ end // Else just send NOOP's, the default command
+ end else if (nxt_dmod)
+ begin
+ // Last half of a two cycle write
+ o_ram_data <= r_data[15:0];
+ end else if (in_refresh)
+ begin
+ // NOOPS only here, until we are out of refresh
+ end else if ((pending)&&(~r_bank_valid)&&(bank_active[r_addr[9:8]]==3'h0))
+ begin // Need to activate the requested bank
+ o_ram_cs_n <= 1'b0;
+ o_ram_ras_n <= 1'b0;
+ o_ram_cas_n <= 1'b1;
+ o_ram_we_n <= 1'b1;
+ o_ram_addr <= r_addr[22:10];
+ o_ram_bs <= r_addr[9:8];
+ // clocks_til_idle[2:0] <= 1;
+ bank_active[r_addr[9:8]][2] <= 1'b1;
+ bank_row[r_addr[9:8]] <= r_addr[22:10];
+ //
+ end else if ((pending)&&(~r_bank_valid)
+ &&(bank_active[r_addr[9:8]]==3'b111))
+ begin // Need to close an active bank
+ o_ram_cs_n <= 1'b0;
+ o_ram_ras_n <= 1'b0;
+ o_ram_cas_n <= 1'b1;
+ o_ram_we_n <= 1'b0;
+ // o_ram_addr <= r_addr[22:10];
+ o_ram_addr[10]<= 1'b0;
+ o_ram_bs <= r_addr[9:8];
+ // clocks_til_idle[2:0] <= 1;
+ bank_active[r_addr[9:8]][2] <= 1'b0;
+ // bank_row[r_addr[9:8]] <= r_addr[22:10];
+ end else if ((pending)&&(~r_we)
+ &&(bank_active[r_addr[9:8]][2])
+ &&(r_bank_valid)
+ &&(clocks_til_idle[2:0] < 4))
+ begin // Issue the read command
+ o_ram_cs_n <= 1'b0;
+ o_ram_ras_n <= 1'b1;
+ o_ram_cas_n <= 1'b0;
+ o_ram_we_n <= 1'b1;
+ o_ram_addr <= { 4'h0, r_addr[7:0], 1'b0 };
+ o_ram_bs <= r_addr[9:8];
+ clocks_til_idle[2:0] <= 4;
+
+ o_wb_stall <= 1'b0;
+ r_barrell_ack[(RDLY-1)] <= 1'b1;
+ end else if ((pending)&&(r_we)
+ &&(bank_active[r_addr[9:8]][2])
+ &&(r_bank_valid)
+ &&(clocks_til_idle[2:0] == 0))
+ begin // Issue the write command
+ o_ram_cs_n <= 1'b0;
+ o_ram_ras_n <= 1'b1;
+ o_ram_cas_n <= 1'b0;
+ o_ram_we_n <= 1'b0;
+ o_ram_addr <= { 4'h0, r_addr[7:0], 1'b0 };
+ o_ram_bs <= r_addr[9:8];
+ clocks_til_idle[2:0] <= 3'h1;
+
+ o_wb_stall <= 1'b0;
+ r_barrell_ack[1] <= 1'b1;
+ o_ram_data <= r_data[31:16];
+ //
+ o_ram_dmod <= `DMOD_PUTOUTPUT;
+ nxt_dmod <= `DMOD_PUTOUTPUT;
+ end else if ((r_pending)&&(r_addr[7:0] >= 8'hf0)
+ &&(~fwd_bank_valid))
+ begin
+ // Do I need to close the next bank I'll need?
+ if (bank_active[fwd_addr[9:8]][2:1]==2'b11)
+ begin // Need to close the bank first
+ o_ram_cs_n <= 1'b0;
+ o_ram_ras_n <= 1'b0;
+ o_ram_cas_n <= 1'b1;
+ o_ram_we_n <= 1'b0;
+ o_ram_addr[10] <= 1'b0;
+ o_ram_bs <= fwd_addr[9:8];
+ bank_active[fwd_addr[9:8]][2] <= 1'b0;
+ end else if (bank_active[fwd_addr[9:8]]==3'b000)
+ begin
+ // Need to (pre-)activate the next bank
+ o_ram_cs_n <= 1'b0;
+ o_ram_ras_n <= 1'b0;
+ o_ram_cas_n <= 1'b1;
+ o_ram_we_n <= 1'b1;
+ o_ram_addr <= fwd_addr[22:10];
+ o_ram_bs <= fwd_addr[9:8];
+ // clocks_til_idle[3:0] <= 1;
+ bank_active[fwd_addr[9:8]] <= 3'h4;
+ bank_row[fwd_addr[9:8]] <= fwd_addr[22:10];
+ end
+ end
+ end else if (r_state == `RAM_POWER_UP)
+ begin
+ // All signals must be held in NOOP state during powerup
+ o_ram_dqm <= 2'b11;
+ // o_ram_cke <= 1'b1;
+ o_ram_cs_n <= 1'b0;
+ o_ram_ras_n <= 1'b1;
+ o_ram_cas_n <= 1'b1;
+ o_ram_we_n <= 1'b1;
+ o_ram_dmod <= `DMOD_GETINPUT;
+ if (clocks_til_idle == 0)
+ begin
+ r_state <= `RAM_INITIAL_REFRESH;
+ clocks_til_idle[3:0] <= 4'ha;
+ o_ram_cs_n <= 1'b0;
+ o_ram_ras_n <= 1'b0;
+ o_ram_cas_n <= 1'b1;
+ o_ram_we_n <= 1'b0;
+ o_ram_addr[10] <= 1'b1;
+ end else
+ clocks_til_idle <= clocks_til_idle - 16'h01;
+
+ o_wb_stall <= 1'b1;
+ r_barrell_ack[(RDLY-1):0] <= 0;
+ end else if (r_state == `RAM_INITIAL_REFRESH)
+ begin
+ //
+ o_ram_cs_n <= 1'b0;
+ o_ram_ras_n <= 1'b0;
+ o_ram_cas_n <= 1'b0;
+ o_ram_we_n <= 1'b1;
+ o_ram_dmod <= `DMOD_GETINPUT;
+ o_ram_addr <= { 3'b000, 1'b0, 2'b00, 3'b010, 1'b0, 3'b001 };
+ if (clocks_til_idle[3:0] == 4'h0)
+ begin
+ r_state <= `RAM_SET_MODE;
+ o_ram_we_n <= 1'b0;
+ clocks_til_idle[3:0] <= 4'h2;
+ end else
+ clocks_til_idle[3:0] <= clocks_til_idle[3:0] - 4'h1;
+
+ o_wb_stall <= 1'b1;
+ r_barrell_ack[(RDLY-1):0] <= 0;
+ end else if (r_state == `RAM_SET_MODE)
+ begin
+ // Set mode cycle
+ o_ram_cs_n <= 1'b1;
+ o_ram_ras_n <= 1'b0;
+ o_ram_cas_n <= 1'b0;
+ o_ram_we_n <= 1'b0;
+ o_ram_dmod <= `DMOD_GETINPUT;
+
+ if (clocks_til_idle[3:0] == 4'h0)
+ r_state <= `RAM_OPERATIONAL;
+ else
+ clocks_til_idle[3:0] <= clocks_til_idle[3:0]-4'h1;
+
+ o_wb_stall <= 1'b1;
+ r_barrell_ack[(RDLY-1):0] <= 0;
+ end
+
+
+ reg [15:0] last_ram_data;
+ always @(posedge i_clk)
+ last_ram_data <= i_ram_data;
+ assign o_wb_ack = r_barrell_ack[0];
+ assign o_wb_data = { last_ram_data, i_ram_data };
+
+ //
+ // The following outputs are not necessary for the functionality of
+ // the SDRAM, but they can be used to feed an external "scope" to
+ // get an idea of what the internals of this SDRAM are doing.
+ //
+ // Just be aware of the r_we: it is set based upon the currently pending
+ // transaction, or (if none is pending) based upon the last transaction.
+ // If you want to capture the first value "written" to the device,
+ // you'll need to write a nothing value to the device to set r_we.
+ // The first value "written" to the device can be caught in the next
+ // interaction after that.
+ //
+ assign o_debug = { i_wb_cyc, i_wb_stb, i_wb_we, o_wb_ack, o_wb_stall,
+ o_ram_cs_n, o_ram_ras_n, o_ram_cas_n, o_ram_we_n, o_ram_bs,
+ o_ram_dmod, r_pending,
+ // 13 of 32
+ o_ram_addr[10:0], // 11 more
+ (r_we) ? { i_wb_data[23:20], i_wb_data[3:0] }
+ : { o_wb_data[23:20], o_wb_data[3:0] }
+ // i_ram_data[7:0]
+ };
+endmodule
Index: trunk/rtl/wbscopc.v
===================================================================
--- trunk/rtl/wbscopc.v (nonexistent)
+++ trunk/rtl/wbscopc.v (revision 2)
@@ -0,0 +1 @@
+link ../../../wbscope/trunk/rtl/wbscopc.v
\ No newline at end of file
trunk/rtl/wbscopc.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/wbicape6.v
===================================================================
--- trunk/rtl/wbicape6.v (nonexistent)
+++ trunk/rtl/wbicape6.v (revision 2)
@@ -0,0 +1 @@
+link ../../../wbicapetwo/trunk/rtl/wbicape6.v
\ No newline at end of file
trunk/rtl/wbicape6.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/ioslave.v
===================================================================
--- trunk/rtl/ioslave.v (nonexistent)
+++ trunk/rtl/ioslave.v (revision 2)
@@ -0,0 +1,184 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: ioslave
+//
+// Project: XuLA2 board
+//
+// Purpose: This handles a bunch of small, simple I/O registers. To be
+// included here, the I/O register must take exactly a single
+// clock to access and never stall.
+//
+// Particular peripherals include:
+// - the interrupt controller
+// - Realtime Clock
+// - Realtime clock Date
+// - A bus error register--records the address of the last
+// bus error. Cannot be written to, save by a bus error.
+// Other peripherals have been removed due to a lack of bus address space.
+//
+//
+// 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 "builddate.v"
+module ioslave(i_clk,
+ // 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,
+ // GPIO wires
+ i_gpio,
+ o_gpio,
+ // Other registers
+ i_bus_err_addr,
+ brd_interrupts, o_ints_to_zip_cpu, o_interrupt);
+ parameter NGPO=15, NGPI=15;
+ input i_clk;
+ // Wishbone control
+ // inputs...
+ input i_wb_cyc, i_wb_stb, i_wb_we;
+ input [4:0] i_wb_addr;
+ input [31:0] i_wb_data;
+ // outputs...
+ output reg o_wb_ack;
+ output wire o_wb_stall;
+ output wire [31:0] o_wb_data;
+ // GPIO
+ input [(NGPI-1):0] i_gpio;
+ output wire [(NGPO-1):0] o_gpio;
+ // Other registers
+ input [31:0] i_bus_err_addr;
+ input [5:0] brd_interrupts;
+ output wire [7:0] o_ints_to_zip_cpu;
+ output wire o_interrupt;
+
+
+ wire i_uart_rx_int, i_uart_tx_int, i_scop_int, i_flash_int,i_pwm_int;
+ assign i_uart_tx_int = brd_interrupts[5];
+ assign i_uart_rx_int = brd_interrupts[4];
+ assign i_pwm_int = brd_interrupts[3];
+ assign i_scop_int = brd_interrupts[2];
+ assign i_flash_int = brd_interrupts[1];
+
+ // reg [31:0] pwrcount;
+ // reg [31:0] rtccount;
+ wire [31:0] ictrl_data, gpio_data, date_data;
+
+ reg [31:0] r_wb_data;
+ reg r_wb_addr;
+ always @(posedge i_clk)
+ begin
+ r_wb_addr <= i_wb_addr[4];
+ // if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we)&&(~i_wb_addr[4]))
+ // begin
+ // casez(i_wb_addr[3:0])
+ // // 4'h0: begin end // Reset register
+ // // 4'h1: begin end // Status/Control register
+ // // 4'h2: begin end // Reset register
+ // // 4'h3: begin end // Interrupt Control register
+ // // 4'h4: // R/O Power count
+ // // 4'h5: // RTC count
+ // default: begin end
+ // endcase
+ // end else
+ if ((i_wb_cyc)&&(i_wb_stb)&&(~i_wb_we))
+ begin
+ casez(i_wb_addr[3:0])
+ 4'h02: r_wb_data <= `DATESTAMP;
+ 4'h03: r_wb_data <= ictrl_data;
+ 4'h04: r_wb_data <= i_bus_err_addr;
+ 4'h05: r_wb_data <= date_data;
+ 4'h06: r_wb_data <= gpio_data;
+ default: r_wb_data <= 32'h0000;
+ endcase
+ end
+ end
+
+ // The interrupt controller
+ wire ck_int;
+ wire [7:0] interrupt_vector;
+ assign interrupt_vector = {
+ i_uart_tx_int, i_uart_rx_int, i_pwm_int, gpio_int,
+ i_scop_int, i_flash_int, ck_int, brd_interrupts[0] };
+ icontrol #(8) intcontroller(i_clk, 1'b0,
+ ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we)
+ &&(i_wb_addr==5'h3)), i_wb_data,
+ ictrl_data, interrupt_vector,
+ o_interrupt);
+
+ /*
+ // The ticks since power up register
+ initial pwrcount = 32'h00;
+ always @(posedge i_clk)
+ if (~ (&pwrcount))
+ pwrcount <= pwrcount+1;
+
+ // The time since power up register
+ reg [15:0] subrtc;
+ reg subpps;
+ initial rtccount = 32'h00;
+ initial subrtc = 16'h00;
+ always @(posedge i_clk)
+ { subpps, subrtc } <= subrtc + 16'd43;
+ always @(posedge i_clk)
+ rtccount <= rtccount + ((subpps)? 32'h1 : 32'h0);
+ */
+
+ //
+ // GPIO controller
+ //
+ wire gpio_int;
+ wbgpio #(NGPI, NGPO)
+ gpiodev(i_clk, i_wb_cyc, (i_wb_stb)&&(i_wb_addr[4:0]==5'h6),
+ i_wb_we, i_wb_data, gpio_data, i_gpio, o_gpio,gpio_int);
+
+ //
+ // 4'b1xxx
+ // BUS access to a real time clock (not calendar, just clock)
+ //
+ //
+ wire [31:0] ck_data;
+ wire ck_ppd;
+ rtclight #(32'h35afe5)
+ theclock(i_clk, i_wb_cyc, (i_wb_stb)&&(i_wb_addr[4]),
+ i_wb_we, i_wb_addr[2:0], i_wb_data,
+ ck_data, ck_int, ck_ppd);
+
+ wire date_ack, date_stall;
+ rtcdate thedate(i_clk, ck_ppd,
+ i_wb_cyc, (i_wb_stb)&&(i_wb_addr[3:0]==4'h5),
+ i_wb_we, i_wb_data,
+ date_ack, date_stall, date_data);
+
+ always @(posedge i_clk)
+ o_wb_ack <= (i_wb_stb)&&(i_wb_cyc);
+ assign o_wb_stall = 1'b0;
+
+ assign o_wb_data = (r_wb_addr)? ck_data : r_wb_data;
+
+ //
+ //
+ assign o_ints_to_zip_cpu = { i_uart_tx_int, i_uart_rx_int,
+ i_pwm_int, gpio_int, i_scop_int, i_flash_int,
+ ck_int, o_interrupt };
+endmodule
Index: trunk/rtl/wbscope.v
===================================================================
--- trunk/rtl/wbscope.v (nonexistent)
+++ trunk/rtl/wbscope.v (revision 2)
@@ -0,0 +1 @@
+link ../../../wbscope/trunk/rtl/wbscope.v
\ No newline at end of file
trunk/rtl/wbscope.v
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/rtl/busmaster.v
===================================================================
--- trunk/rtl/busmaster.v (nonexistent)
+++ trunk/rtl/busmaster.v (revision 2)
@@ -0,0 +1,633 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: busmaster.v
+//
+// Project: XuLA2 board
+//
+// Purpose: This is the highest level, Verilator simulatable, portion of
+// the XuLA2 core. You should be able to successfully Verilate
+// this file, and then build a test bench that tests and proves the
+// capability of anything within here.
+//
+// In general, this means the file is little more than a wishbone
+// interconnect that connects multiple devices together. User-JTAG
+// commands come in via i_rx_stb and i_rx_data. These are converted into
+// wishbone bus interactions, the results of which come back out via
+// o_tx_data and o_tx_stb.
+//
+//
+// 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 INCLUDE_ZIPCPU
+// `define NO_ZIP_WBU_DELAY
+`define IMPLEMENT_ONCHIP_RAM
+`define FANCY_ICAP_ACCESS
+`define FLASH_ACCESS
+// `define FLASH_SCOPE
+// `define CFG_SCOPE
+`define SDRAM_SCOPE
+`define ZIP_SCOPE
+// `define SDCARD_ACCESS
+module busmaster(i_clk, i_rst,
+ i_rx_stb, i_rx_data, o_tx_stb, o_tx_data, i_tx_busy,
+ // The SPI Flash lines
+ o_sf_cs_n, o_sd_cs_n, o_spi_sck, o_spi_mosi, i_spi_miso,
+ // The SDRAM lines
+ o_ram_cs_n, o_ram_cke, o_ram_ras_n, o_ram_cas_n,
+ o_ram_we_n, o_ram_bs, o_ram_addr,
+ o_ram_drive_data, i_ram_data, o_ram_data,
+ o_ram_dqm,
+ // Generic GPIO
+ i_gpio, o_gpio, o_pwm,
+ i_rx_uart, o_tx_uart);
+ parameter ZIP_ADDRESS_WIDTH=24, NGPO=15, NGPI=15,
+ ZA=ZIP_ADDRESS_WIDTH;
+ input i_clk, i_rst;
+ // The bus commander, via an external JTAG 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;
+ // SPI flash control
+ output wire o_sf_cs_n, o_sd_cs_n;
+ output wire o_spi_sck, o_spi_mosi;
+ input i_spi_miso;
+ // SDRAM control
+ output wire o_ram_cs_n, o_ram_cke;
+ output wire o_ram_ras_n, o_ram_cas_n, o_ram_we_n;
+ output wire [12:0] o_ram_addr;
+ output wire [1:0] o_ram_bs;
+ output wire o_ram_drive_data;
+ input [15:0] i_ram_data;
+ output wire [15:0] o_ram_data;
+ output wire [1:0] o_ram_dqm;
+ input [(NGPI-1):0] i_gpio;
+ output wire [(NGPO-1):0] o_gpio;
+ output wire o_pwm;
+ input i_rx_uart;
+ output wire o_tx_uart;
+
+
+ //
+ //
+ // Master wishbone wires
+ //
+ //
+ wire wb_cyc, wb_stb, wb_we, wb_stall, wb_ack, wb_err;
+ wire [31:0] wb_data, wb_idata, wb_addr;
+
+ //
+ //
+ // First BUS master source: The JTAG
+ //
+ //
+ 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;
+ assign wbu_zip_sel =((wbu_cyc)&&(wbu_addr[31: 1]== 31'h083));
+ 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,
+`ifdef INCLUDE_ZIPCPU
+ ((~wbu_zip_sel)&&(wbu_ack))
+ ||((wbu_zip_sel)&&(zip_dbg_ack)),
+ ((~wbu_zip_sel)&&(wbu_stall))
+ ||((wbu_zip_sel)&&(zip_dbg_stall)),
+ wbu_err, (wbu_zip_sel)?zip_dbg_data:dwb_idata,
+`else
+ wbu_ack, wbu_stall,
+ wbu_err, dwb_idata,
+`endif
+ w_interrupt,
+ o_tx_stb, o_tx_data, i_tx_busy);
+
+
+ //
+ //
+ // Second BUS master source: The ZipCPU
+ //
+ //
+ wire zip_cyc, zip_stb, zip_we, zip_cpu_int;
+ wire [(ZA-1):0] w_zip_addr;
+ wire [31:0] zip_addr, zip_data;
+ // and then coming from devices
+ wire zip_ack, zip_stall, zip_err;
+ wire dwb_we, dwb_stb, dwb_cyc, dwb_ack, dwb_stall, dwb_err;
+ wire [31:0] dwb_addr, dwb_odata;
+ wire [7:0] w_ints_to_zip_cpu;
+`ifdef INCLUDE_ZIPCPU
+ wire [31:0] zip_debug;
+ zipsystem #(24'h2000,ZA,8,1,8)
+ zippy(i_clk, 1'b0,
+ // Zippys wishbone interface
+ zip_cyc, zip_stb, zip_we, w_zip_addr, zip_data,
+ zip_ack, zip_stall, dwb_idata, zip_err,
+ w_ints_to_zip_cpu, 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,
+ zip_debug);
+ 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
+ //
+ //
+ /*
+ wbarbiter #(32,32) wbu_zip_arbiter(i_clk, i_rst,
+ // The UART interface Master
+ wbu_addr, wbu_data, wbu_we, (wbu_stb)&&(~wbu_zip_sel),
+ (wbu_cyc)&&(~wbu_zip_sel), wbu_ack, wbu_stall, wbu_err,
+ // The ZIP CPU Master
+ zip_addr, zip_data, zip_we, zip_stb,
+ zip_cyc, zip_ack, zip_stall, zip_err,
+ // Common bus returns
+ dwb_addr,dwb_odata,dwb_we,dwb_stb, dwb_cyc, dwb_ack, dwb_stall, dwb_err);
+ */
+ wbpriarbiter #(32,32) wbu_zip_arbiter(i_clk,
+ // The ZIP CPU Master -- gets priority in the arbiter
+ zip_cyc, zip_stb, zip_we, zip_addr, zip_data,
+ zip_ack, zip_stall, zip_err,
+ // The JTAG interface Master, secondary priority,
+ // will suffer a 1clk delay in arbitration
+ (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);
+
+`else
+ assign zip_cyc = 1'b0;
+ assign zip_stb = 1'b0;
+ assign zip_we = 1'b0;
+ assign zip_cpu_int = 1'b0;
+ assign zip_addr = 32'h000;
+ assign zip_data = 32'h000;
+
+ reg r_zip_dbg_ack;
+ initial r_zip_dbg_ack = 1'b0;
+ always @(posedge i_clk)
+ r_zip_dbg_ack <= ((wbu_cyc)&&(wbu_zip_sel)&(wbu_stb));
+ assign zip_dbg_ack = r_zip_dbg_ack;
+ assign zip_dbg_stall = 1'b0;
+ assign zip_dbg_data = 32'h000;
+
+ assign dwb_addr = wbu_addr;
+ assign dwb_odata = wbu_data;
+ assign dwb_we = wbu_we;
+ assign dwb_stb = (wbu_stb);
+ assign dwb_cyc = (wbu_cyc);
+ assign wbu_ack = dwb_ack;
+ assign wbu_stall = dwb_stall;
+ assign dwb_idata = wb_idata;
+ assign wbu_err = dwb_err;
+`endif
+
+
+ //
+ //
+ // And because the ZIP CPU and the Arbiter create an unacceptable
+ // delay, we fail timing. So we add in a delay cycle ...
+ //
+ //
+`ifdef NO_ZIP_WBU_DELAY
+ assign wb_cyc = dwb_cyc;
+ assign wb_stb = dwb_stb;
+ assign wb_we = dwb_we;
+ assign wb_addr = dwb_addr;
+ assign wb_data = dwb_odata;
+ assign dwb_idata = wb_idata;
+ assign dwb_ack = wb_ack;
+ assign dwb_stall = wb_stall;
+ assign dwb_err = wb_err;
+`else
+ 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);
+`endif
+
+
+
+ wire io_sel, pwm_sel, uart_sel, flash_sel, flctl_sel, scop_sel,
+ cfg_sel, mem_sel, sdram_sel, sdcard_sel,
+ none_sel, many_sel, io_bank;
+ wire io_ack, flash_ack, scop_ack, cfg_ack, mem_ack,
+ sdram_ack, sdcard_ack, uart_ack, pwm_ack;
+ wire io_stall, flash_stall, scop_stall, cfg_stall, mem_stall,
+ sdram_stall, sdcard_stall, uart_stall, pwm_stall;
+
+ wire [31:0] io_data, flash_data, scop_data, cfg_data, mem_data,
+ sdram_data, sdcard_data, uart_data, pwm_data;
+ reg [31:0] bus_err_addr;
+
+ assign wb_ack = (wb_cyc)&&((io_ack)||(uart_ack)||(pwm_ack)
+ ||(scop_ack)||(cfg_ack)
+ ||(mem_ack)||(flash_ack)||(sdram_ack)
+ ||(sdcard_ack)
+ ||((none_sel)&&(1'b1)));
+ assign wb_stall = ((io_sel)&&(io_stall))
+ ||((uart_sel)&&(uart_stall))
+ ||((pwm_sel)&&(pwm_stall))
+ ||((scop_sel)&&(scop_stall))
+ ||((cfg_sel)&&(cfg_stall))
+ ||((mem_sel)&&(mem_stall))
+ ||((sdram_sel)&&(sdram_stall))
+ ||((sdcard_sel)&&(sdcard_stall))
+ ||((flash_sel||flctl_sel)&&(flash_stall));
+ // (none_sel)&&(1'b0)
+
+ /*
+ assign wb_idata = (io_ack)?io_data
+ : ((scop_ack)?scop_data
+ : ((cfg_ack)?cfg_data
+ : ((mem_ack)?mem_data
+ : ((flash_ack)?flash_data
+ : 32'h00))));
+ */
+ assign wb_idata = (io_ack|scop_ack)?((io_ack )? io_data : scop_data)
+ : ((uart_ack|pwm_ack)?((uart_ack)?uart_data: pwm_data)
+ : ((cfg_ack) ? cfg_data
+ : ((sdram_ack|sdcard_ack)
+ ?((sdram_ack)? sdram_data : sdcard_data)
+ : ((mem_ack)?mem_data:flash_data)))); // if (flash_ack)
+ assign wb_err = ((wb_cyc)&&(wb_stb)&&(none_sel || many_sel)) || many_ack;
+
+ // Addresses ...
+ // 0000 xxxx configuration/control registers
+ // 001x xxxx Down-sampler taps (64 taps, 2 at a time)
+ // 1xxx xxxx Up-sampler taps
+ // 1 xxxx xxxx xxxx xxxx xxxx Up-sampler taps
+ assign io_bank = (wb_cyc)&&(wb_addr[31:5] == 27'h8);
+ assign io_sel = (io_bank)&&(~flctl_sel)
+ &&(~pwm_sel)&&(~uart_sel)&&(~scop_sel);
+ assign pwm_sel =((io_bank)&&(wb_addr[4: 1]== 4'h4));
+ assign uart_sel =((io_bank)&&((wb_addr[4:1]== 4'h5)||(wb_addr[4:0]==5'h7)));
+ assign flctl_sel=((io_bank)&&(wb_addr[4: 2]== 3'h3));
+ assign scop_sel =((io_bank)&&(wb_addr[4: 3]== 2'h3));
+ assign cfg_sel =((wb_cyc)&&(wb_addr[31: 6]== 26'h05));
+ // zip_sel is not on the bus at this point
+ assign mem_sel =((wb_cyc)&&(wb_addr[31:13]== 19'h01));
+ assign flash_sel=((wb_cyc)&&(wb_addr[31:18]== 14'h01));
+ assign sdcard_sel=1'b0;
+ assign sdram_sel=((wb_cyc)&&(wb_addr[31:23]== 9'h01));
+ assign none_sel =((wb_cyc)&&(wb_stb)&&(~(io_sel||flctl_sel||scop_sel||cfg_sel||mem_sel||sdram_sel||sdcard_sel||flash_sel)));
+ assign many_sel =((wb_cyc)&&(wb_stb)&&(
+ {3'h0, io_sel}
+ +{3'h0, uart_sel}
+ +{3'h0, pwm_sel}
+ +{3'h0, flctl_sel}
+ +{3'h0, scop_sel}
+ +{3'h0, cfg_sel}
+ +{3'h0, mem_sel}
+ +{3'h0, sdram_sel}
+ +{3'h0, sdcard_sel}
+ +{3'h0, flash_sel} > 1));
+
+ wire many_ack;
+ assign many_ack =((wb_cyc)&&(
+ {3'h0, io_ack}
+ +{3'h0, uart_ack}
+ +{3'h0, pwm_ack}
+ +{3'h0, scop_ack}
+ +{3'h0, cfg_ack}
+ +{3'h0, mem_ack}
+ +{3'h0, sdram_ack}
+ +{3'h0, sdcard_ack}
+ +{3'h0, flash_ack} > 1));
+
+ always @(posedge i_clk)
+ if (wb_err)
+ bus_err_addr <= wb_addr;
+
+ wire flash_interrupt, scop_interrupt,
+ uart_rx_int, uart_tx_int, pwm_int;
+ // The I/O processor, herein called an ioslave
+ ioslave #(NGPO, NGPI) runio(i_clk,
+ wb_cyc, (io_sel)&&(wb_stb), wb_we, wb_addr[4:0],
+ wb_data, io_ack, io_stall, io_data,
+ i_gpio, o_gpio,
+ bus_err_addr,
+ { uart_tx_int, uart_rx_int, pwm_int, scop_interrupt,
+ flash_interrupt, zip_cpu_int },
+ w_ints_to_zip_cpu,
+ w_interrupt);
+ // 8684
+ // 1'bx, 4'h0, scop_sel, scop_ack, ~scop_stall,
+ // wb_err, ~vga_interrupt, 2'b00, flash_interrupt
+ //
+
+ //
+ // UART device
+ //
+ uartdev serialport(i_clk, i_rx_uart, o_tx_uart,
+ wb_cyc, (wb_stb)&&(uart_sel), wb_we,
+ { ~wb_addr[2], wb_addr[0]},
+ wb_data, uart_ack, uart_stall, uart_data,
+ uart_rx_int, uart_tx_int);
+
+ //
+ // PWM (audio) device
+ //
+ wbpwmaudio pwmdev(i_clk,
+ wb_cyc, (wb_stb)&&(pwm_sel), wb_we, wb_addr[0],
+ wb_data, pwm_ack, pwm_stall, pwm_data, o_pwm, pwm_int);
+
+
+ //
+ // FLASH MEMORY CONFIGURATION ACCESS
+ //
+ wire flash_cs_n, flash_sck, flash_mosi;
+`ifdef FLASH_ACCESS
+ wbspiflash flashmem(i_clk,
+ wb_cyc,(wb_stb&&flash_sel),(wb_stb)&&(flctl_sel),wb_we,
+ wb_addr[17:0], wb_data,
+ flash_ack, flash_stall, flash_data,
+ flash_sck, flash_cs_n, o_sf_cs_n, flash_mosi, i_spi_miso,
+ flash_interrupt);
+`else
+ reg r_flash_ack;
+ initial r_flash_ack = 1'b0;
+ always @(posedge i_clk)
+ r_flash_ack <= (wb_cyc)&&(wb_stb)&&((flash_sel)||(flctl_sel));
+
+ assign flash_ack = r_flash_ack;
+ assign flash_stall = 1'b0;
+ assign flash_data = 32'h0000;
+ assign flash_interrupt = 1'b0;
+
+ assign flash_cs_n = 1'b1;
+ assign flash_sck = 1'b1;
+ assign flash_mosi = 1'b1;
+
+ This is an error
+`endif
+
+`ifdef FLASH_ACCESS
+`ifdef SDCARD_ACCESS
+ spiarbiter spichk(i_clk,
+ flash_cs_n, flash_sck, flash_mosi,
+ sdcard_cs_n, sdcard_sck, sdcard_mosi,
+ o_sf_cs_n, o_sd_cs_n, o_spi_sck, o_spi_mosi);
+ This is an error
+`else
+ // Flash access, but no SD card access
+ assign o_sf_cs_n = flash_cs_n;
+ assign o_sd_cs_n = 1'b1;
+ assign o_spi_sck = flash_sck;
+ assign o_spi_mosi = flash_mosi;
+`endif // SDCARD_ACCESS && FLASH_ACCESS
+`else // FLASH_ACCESS
+`ifdef SDCARD_ACCESS
+ // SDCard access, but no flash access
+ assign o_sf_cs_n = 1'b1;
+ assign o_sd_cs_n = sdcard_cs_n;
+ assign o_spi_sck = sdcard_sck;
+ assign o_spi_mosi = sdcard_mosi;
+`else
+ // No SPI access ...
+ assign o_sf_cs_n = 1'b1;
+ assign o_sd_cs_n = 1'b1;
+ assign o_spi_sck = 1'b1;
+ assign o_spi_mosi = 1'b1;
+`endif // SDCARD_ACCESS, w/o FLASH_ACCESS
+`endif // !FLASH_ACCESS
+
+
+ //
+ // MULTIBOOT/ICAPE2 CONFIGURATION ACCESS
+ //
+ wire [31:0] cfg_scope;
+`ifdef FANCY_ICAP_ACCESS
+ wbicape6 fpga_cfg(i_clk, wb_cyc,(cfg_sel)&&(wb_stb), wb_we,
+ wb_addr[5:0], wb_data,
+ cfg_ack, cfg_stall, cfg_data,
+ cfg_scope);
+`else
+ assign cfg_scope = 32'h0000;
+ reg r_cfg_ack;
+ initial r_cfg_ack = 1'b0;
+ always @(posedge i_clk)
+ r_cfg_ack <= ((wb_cyc)&&(cfg_sel)&&(wb_stb)&&(~cfg_stall));
+ assign cfg_ack = r_cfg_ack;
+ assign cfg_stall = 1'b0;
+ assign cfg_data = 32'h0000;
+`endif
+
+
+ //
+ // RAM MEMORY ACCESS
+ //
+`ifdef IMPLEMENT_ONCHIP_RAM
+ memdev #(13) ram(i_clk, wb_cyc, (wb_stb)&&(mem_sel), wb_we,
+ wb_addr[12:0], wb_data, mem_ack, mem_stall, mem_data);
+`else
+ reg r_mem_ack;
+ always @(posedge i_clk)
+ r_mem_ack = (wb_cyc)&&(wb_stb)&&(mem_sel);
+ assign mem_data = 32'h000;
+ assign mem_stall = 1'b0;
+ assign mem_ack = r_mem_ack;
+`endif
+
+
+ //
+ // SDRAM Memory Access
+ //
+ wire [31:0] sdram_debug;
+`ifndef BYPASS_SDRAM_ACCESS
+ wbsdram sdram(i_clk,
+ wb_cyc, (wb_stb)&&(sdram_sel),
+ wb_we, wb_addr[22:0], wb_data,
+ sdram_ack, sdram_stall, sdram_data,
+ o_ram_cs_n, o_ram_cke, o_ram_ras_n, o_ram_cas_n, o_ram_we_n,
+ o_ram_bs, o_ram_addr,
+ o_ram_drive_data, i_ram_data, o_ram_data, o_ram_dqm,
+ sdram_debug);
+`else
+ reg r_sdram_ack;
+ initial r_sdram_ack = 1'b0;
+ always @(posedge i_clk)
+ r_sdram_ack <= (wb_cyc)&&(wb_stb)&&(sdram_sel);
+ assign sdram_ack = r_sdram_ack;
+ assign sdram_stall = 1'b0;
+ assign sdram_data = 32'h0000;
+
+ assign o_ram_ce_n = 1'b1;
+ assign o_ram_ras_n = 1'b1;
+ assign o_ram_cas_n = 1'b1;
+ assign o_ram_we_n = 1'b1;
+
+ assign sdram_debug = 32'h0000;
+`endif
+
+ //
+ //
+ // WISHBONE SCOPES
+ //
+ //
+ //
+ //
+`ifdef FLASH_SCOPE
+ reg [31:0] r_flash_debug, last_flash_debug;
+ wire [31:0] scop_flash_data;
+ wire scop_flash_ack, scop_flash_stall, scop_flash_interrupt;
+ always @(posedge i_clk)
+ r_flash_debug <= flash_debug;
+ always @(posedge i_clk)
+ last_flash_debug <= r_flash_debug;
+ wbscope spiscope(i_clk, 1'b1, (~o_spi_cs_n), r_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);
+`else
+ wire [31:0] scop_flash_data;
+ wire scop_flash_ack, scop_flash_stall, scop_flash_interrupt;
+ assign scop_flash_data = 32'h00;
+ assign scop_flash_ack = (wb_stb)&&(scop_sel)&&(wb_addr[2:1]==2'b00);
+ assign scop_flash_stall = 1'b0;
+ assign scop_flash_interrupt = 1'b0;
+`endif
+
+
+ wire [31:0] scop_cfg_data;
+ wire scop_cfg_ack, scop_cfg_stall, scop_cfg_interrupt;
+`ifdef CFG_SCOPE
+ wire scop_cfg_trigger;
+ assign scop_cfg_trigger = (wb_cyc)&&(wb_stb)&&(cfg_sel);
+ wbscope #(5'ha) wbcfgscope(i_clk, 1'b1, scop_cfg_trigger, cfg_scope,
+ // Wishbone interface
+ i_clk, wb_cyc, ((wb_stb)&&(scop_sel)&&(wb_addr[2:1]==2'b01)),
+ wb_we, wb_addr[0], wb_data,
+ scop_cfg_ack, scop_cfg_stall, scop_cfg_data,
+ scop_cfg_interrupt);
+`else
+ assign scop_cfg_data = 32'h00;
+ assign scop_cfg_ack = (wb_stb)&&(scop_sel)&&(wb_addr[2:1]==2'b01);
+ assign scop_cfg_stall = 1'b0;
+ assign scop_cfg_interrupt = 1'b0;
+`endif
+
+ wire [31:0] scop_ram_data;
+ wire scop_ram_ack, scop_ram_stall, scop_ram_interrupt;
+`ifdef SDRAM_SCOPE
+ wire sdram_trigger;
+ assign sdram_trigger = sdram_sel;
+ // assign sdram_trigger = ((wbu_cyc)&&(wbu_zip_sel)&&(wbu_stb)&&(~wbu_addr[0])),
+ wire sdram_write;
+ assign sdram_write = ((wb_cyc)&&(sdram_sel)&&(wb_stb)&&(wb_we)&&(~sdram_stall));
+ /*
+ reg r_trigger;
+ reg [31:0] last_data;
+ always @(posedge i_clk)
+ if (sdram_write)
+ last_data <= wb_data;
+ initial r_trigger = 1'b0;
+ always @(posedge i_clk)
+ if ((sdram_write)&&(last_data == wb_data))
+ r_trigger <= 1'b1;
+ else
+ r_trigger <= 1'b0;
+ */
+
+ wbscope #(5'hd) sdramscope(i_clk, 1'b1, sdram_trigger,
+ sdram_debug,
+ // zip_debug,
+ // Wishbone interface
+ i_clk, wb_cyc, ((wb_stb)&&(scop_sel)&&(wb_addr[2:1]==2'b10)), wb_we, wb_addr[0],
+ wb_data,
+ scop_ram_ack, scop_ram_stall, scop_ram_data,
+ scop_ram_interrupt);
+`else
+ assign scop_ram_data = 32'h00;
+ assign scop_ram_ack = (wb_stb)&&(scop_sel)&&(wb_addr[2:1]==2'b10);
+ assign scop_ram_stall = 1'b0;
+ assign scop_ram_interrupt = 1'b0;
+`endif
+
+ wire [31:0] scop_zip_data;
+ wire scop_zip_ack, scop_zip_stall, scop_zip_interrupt;
+`ifdef ZIP_SCOPE
+ wire zip_trigger;
+ assign zip_trigger=(wbu_zip_sel)&&(wbu_we)&&(wbu_stb)&&(~wbu_addr[0]);
+ wbscope #(5'hd) zipscope(i_clk, 1'b1, zip_trigger,
+ zip_debug,
+ // Wishbone interface
+ i_clk, wb_cyc, ((wb_stb)&&(scop_sel)&&(wb_addr[2:1]==2'b11)), wb_we, wb_addr[0],
+ wb_data,
+ scop_zip_ack, scop_zip_stall, scop_zip_data,
+ scop_zip_interrupt);
+`else
+ assign scop_zip_data = 32'h00;
+ assign scop_zip_ack = (wb_stb)&&(scop_sel)&&(wb_addr[2:1]==2'b11);
+ assign scop_zip_stall = 1'b0;
+ assign scop_zip_interrupt = 1'b0;
+`endif
+
+
+ assign scop_interrupt = scop_flash_interrupt || scop_cfg_interrupt
+ || scop_ram_interrupt || scop_zip_interrupt;
+ assign scop_ack = scop_cfg_ack | scop_flash_ack | scop_ram_ack | scop_zip_ack;
+ assign scop_stall = ((~wb_addr[2])?
+ ((wb_addr[1])?scop_flash_stall:scop_cfg_stall)
+ : ((wb_addr[1])?scop_ram_stall:scop_zip_stall));
+ assign scop_data = ((scop_cfg_ack)?scop_cfg_data
+ : ((scop_flash_ack) ? scop_flash_data
+ : ((scop_ram_ack) ? scop_ram_data
+ : scop_zip_data)));
+
+
+ reg r_sdcard_ack;
+ initial r_sdcard_ack = 1'b0;
+ always @(posedge i_clk)
+ r_sdcard_ack <= (wb_cyc)&&(wb_stb)&&(sdcard_sel);
+ assign sdcard_stall = 1'b0;
+ assign sdcard_ack = r_sdcard_ack;
+ assign sdcard_data = 32'h0000;
+endmodule
+
+// 0x8684 interrupts ...???
Index: trunk/rtl/wbuidleint.v
===================================================================
--- trunk/rtl/wbuidleint.v (nonexistent)
+++ trunk/rtl/wbuidleint.v (revision 2)
@@ -0,0 +1,125 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: wbuidleint.v
+//
+// Project: XuLA2 board
+//
+// 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, 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
Index: trunk/rtl/wbucompress.v
===================================================================
--- trunk/rtl/wbucompress.v (nonexistent)
+++ trunk/rtl/wbucompress.v (revision 2)
@@ -0,0 +1,258 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: wbucompress.v
+//
+// Project: XuLA2 board
+//
+// 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, 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;
+ /*
+ reg [35:0] r_word;
+ always @(posedge i_clk)
+ if (a_stb)
+ r_word <= a_addrword;
+ */
+ 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 r_compressed, 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<