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

powered by: WebSVN 2.1.0

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