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

Subversion Repositories s6soc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /s6soc/trunk
    from Rev 50 to Rev 51
    Reverse comparison

Rev 50 → Rev 51

/rtl/Makefile
37,14 → 37,15
##
##
.PHONY: all
all: busmaster altbusmaster
all: busmaster altbusmaster cpudefs.h
YYMMDD=`date +%Y%m%d`
CPUD := cpu
RAWZIP := zipbones.v zipcpu.v cpudefs.v \
prefetch.v idecode.v cpuops.v memops.v \
wbdblpriarb.v
wbdblpriarb.v dblfetch.v
ZIPSRC := $(addprefix $(CPUD)/,$(RAWZIP))
BUSSRC := builddate.v llqspi.v wbscope.v memdev.v spio.v wbgpio.v wbpwmaudio.v
BUSSRC := builddate.v llqspi.v wbscope.v memdev.v spio.v wbgpio.v wbpwmaudio.v\
qflashxpress.v
MAINSRC := busmaster.v builddate.v flash_config.v wbqspiflash.v \
$(BUSSRC) $(ZIPSRC)
# toplevel.v rxuart.v txuart.v
57,26 → 58,31
verilator -trace -cc -y $(CPUD) busmaster.v
$(VOBJ)/Vbusmaster.h: $(VOBJ)/Vbusmaster.cpp
 
$(VOBJ)/Vbusmaster__ALL.a: $(VOBJ)/Vbusmaster.cpp $(VOBJ)/Vbusmaster.h
cd $(VOBJ); make --no-print-directory -f Vbusmaster.mk
 
$(VOBJ)/Valtbusmaster.cpp: $(ALTSRC)
verilator -trace -cc -y $(CPUD) altbusmaster.v
$(VOBJ)/Valtbusmaster.h: $(VOBJ)/Valtbusmaster.cpp
 
$(VOBJ)/Vbusmaster__ALL.a: $(VOBJ)/Vbusmaster.cpp $(VOBJ)/Vbusmaster.h
cd $(VOBJ); make --no-print-directory -f Vbusmaster.mk
$(VOBJ)/Valtbusmaster__ALL.a: $(VOBJ)/Valtbusmaster.cpp $(VOBJ)/Valtbusmaster.h
cd $(VOBJ); make --no-print-directory -f Valtbusmaster.mk
 
$(VOBJ)/Vdblfetch.cpp: $(ALTSRC)
verilator -trace -cc -y $(CPUD) dblfetch.v
$(VOBJ)/Vdblfetch.mk: $(VOBJ)/Vdblfetch.cpp
$(VOBJ)/Vdblfetch.h: $(VOBJ)/Vdblfetch.cpp
 
$(VOBJ)/V%__ALL.a: $(VOBJ)/V%.mk
cd $(VDIRFB); make -f V$*.mk
make -f V$*.mk -C obj_dir
 
$(VOBJ)/Valtbusmaster__ALL.a: $(VOBJ)/Valtbusmaster.cpp $(VOBJ)/Valtbusmaster.h
cd $(VOBJ); make --no-print-directory -f Valtbusmaster.mk
 
cpudefs.h: cpudefs.v
cpudefs.h: cpu/cpudefs.v
@echo "Building cpudefs.h"
@echo "// " > $@
@echo "// Do not edit this file, it is automatically generated!" >> $@
@echo "// To generate this file, \"make cpudefs.h\" in the rtl directory." >> $@
@echo "// " >> $@
@grep "^\`" $^ | sed -e '{ s/^`/#/ }' >> $@
@sed -e '{ s/^`/#/ }' $< | sed -e ' s/cpudefs.v/cpudefs.h/' >> $@
 
.PHONY: busmaster
busmaster: $(VOBJ)/Vbusmaster__ALL.a
/rtl/altbusmaster.v
43,9 → 43,10
//
// `define IMPLEMENT_ONCHIP_RAM
`define FLASH_ACCESS
// `define DBG_SCOPE // About 204 LUTs, at 2^6 addresses
`define DBG_SCOPE // About 204 LUTs, at 2^6 addresses
// `define COMPRESSED_SCOPE
`define WBUBUS
// `define LOWLOGIC_FLASH
module altbusmaster(i_clk, i_rst,
// DEPP I/O Control
i_depp_astb_n, i_depp_dstb_n, i_depp_write_n,
63,8 → 64,8
o_uart_setup,
// GPIO lines
i_gpio, o_gpio);
parameter BUS_ADDRESS_WIDTH=23,
BAW=BUS_ADDRESS_WIDTH; // 24bits->2,258,23b->2181
parameter BUS_ADDRESS_WIDTH=23;
localparam BAW=BUS_ADDRESS_WIDTH; // 24bits->2,258,23b->2181
// 2^14 bytes requires a LGMEMSZ of 14, and 12 address bits ranging from
// 0 to 11. As with many other devices, the wb_cyc line is more for
// form than anything else--it is ignored by the memory itself.
86,7 → 87,12
input i_tx_busy;
output wire o_uart_rts_n;
// SPI flash control
output wire o_qspi_cs_n, o_qspi_sck;
output wire o_qspi_cs_n;
`ifdef LOWLOGIC_FLASH
output wire [1:0] o_qspi_sck;
`else // LOWLOGIC_FLASH
output wire o_qspi_sck;
`endif // LOWLOGIC_FLASH
output wire [3:0] o_qspi_dat;
input [3:0] i_qspi_dat;
output wire [1:0] o_qspi_mod;
173,11 → 179,11
wire none_sel, many_sel;
 
wire io_sel, flash_sel, flctl_sel, scop_sel, mem_sel;
wire flash_ack, scop_ack, cfg_ack, mem_ack, many_ack;
wire io_stall, flash_stall, scop_stall, cfg_stall, mem_stall;
wire flash_ack, scop_ack, mem_ack, many_ack;
wire io_stall, flash_stall, scop_stall, mem_stall;
reg io_ack;
 
wire [31:0] flash_data, scop_data, cfg_data, mem_data, pwm_data,
wire [31:0] flash_data, scop_data, mem_data, pwm_data,
spio_data, gpio_data, uart_data;
reg [31:0] io_data;
reg [(BAW-1):0] bus_err_addr;
309,11 → 315,16
`else
assign idle_n = 1'b1;
`endif
assign io_sel =((idle_n)&&(skipaddr[3:0]==4'h1));
assign scop_sel =((idle_n)&&(skipaddr[3:1]==3'h1)); // = 4'h2
assign flctl_sel= 1'b0; // ((wb_cyc)&&(skipaddr[3:0]==4'h3));
assign mem_sel =((idle_n)&&(skipaddr[3:2]==2'h1));
assign flash_sel=((idle_n)&&(skipaddr[3]));
assign io_sel = ((idle_n)&&(skipaddr[3:0]==4'b00_01));
`ifdef LOWLOGIC_FLASH
assign scop_sel = ((idle_n)&&(skipaddr[3:1]==3'b00_1)); // = 4'h2
assign flctl_sel= 1'b0; // The lowlogic flash has no control registers
`else // LOWLOGIC_FLASH
assign scop_sel = ((idle_n)&&(skipaddr[3:0]==4'b00_10)); // = 4'h2
assign flctl_sel= ((wb_cyc)&&(skipaddr[3:0]==4'b00_11));
`endif // LOWLOGIC_FLASH
assign mem_sel = ((idle_n)&&(skipaddr[3:2]==2'b01));
assign flash_sel= ((idle_n)&&(skipaddr[3]));
 
//
// none_sel
505,13 → 516,30
// FLASH MEMORY CONFIGURATION ACCESS
//
`ifdef FLASH_ACCESS
wbqspiflash #(LGFLASHSZ) flashmem(i_clk,
wb_cyc,(wb_stb)&&(flash_sel),(wb_stb)&&(flctl_sel),wb_we,
`ifdef LOWLOGIC_FLASH
wire w_flash_ack;
qflashxpress flashmem(i_clk,
wb_cyc,(wb_stb)&&(flash_sel),
wb_addr[(LGFLASHSZ-3):0],
w_flash_ack, flash_stall, flash_data,
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat);
 
assign flash_interrupt = 1'b0;
reg r_flash_ack;
initial r_flash_ack = 1'b0;
always @(posedge i_clk)
r_flash_ack <= (wb_stb)&&(flctl_sel);
assign flash_ack = (w_flash_ack)||(r_flash_ack);
`else // LOWLOGIC_FLASH
wbqspiflashp #(LGFLASHSZ) // Use the writable interface
flashmem(i_clk,
wb_cyc,(wb_stb)&&(flash_sel),(wb_stb)&&(flctl_sel),wb_we,
wb_addr[(LGFLASHSZ-3):0], wb_data,
flash_ack, flash_stall, flash_data,
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat,
flash_interrupt);
`else
`endif // LOWLOGIC_FLASH
`else // FLASH_ACCESS
reg r_flash_ack;
initial r_flash_ack = 1'b0;
always @(posedge i_clk)
526,7 → 554,7
assign o_qspi_cs_n = 1'b1;
assign o_qspi_mod = 2'b01;
assign o_qspi_dat = 4'b1111;
`endif
`endif // FLASH_ACCESS
 
//
// ON-CHIP RAM MEMORY ACCESS
552,36 → 580,42
//
//
//
wire [31:0] scop_cfg_data;
wire scop_cfg_ack, scop_cfg_stall, scop_cfg_interrupt;
`ifdef DBG_SCOPE
wire scop_cfg_trigger;
assign scop_cfg_trigger = (wb_stb)&&(cfg_sel);
wire scop_trigger = bus_dbg;
wire scop_trigger;
// assign scop_trigger = (flash_sel)&&(wb_stb); // bus_dbg;
assign scop_trigger = (wb_stb)&&(wb_we)&&(flctl_sel);
wire [31:0] flash_debug;
wire [1:0] sck;
`ifdef LOWLOGIC_FLASH
assign sck = o_qspi_sck;
`else // LOWLOGIC_FLASH
assign sck = { o_qspi_sck, o_qspi_sck };
`endif // LOWLOGIC_FLASH
assign flash_debug = {
wb_cyc, wb_stb,
flash_sel, flctl_sel, flash_ack, flash_stall,
o_qspi_cs_n, sck, o_qspi_mod, 1'b0,
o_qspi_dat, i_qspi_dat, flash_data[11:0]
};
`ifdef COMPRESSED_SCOPE
wbscopc #(5'ha)
`else
wbscope #(5'ha)
`endif
wbcfgscope(i_clk, 1'b1, scop_trigger, bus_debug,
thescope(i_clk, 1'b1, scop_trigger, flash_debug,
// Wishbone interface
i_clk, wb_cyc, (wb_stb)&&(scop_sel),
wb_we, wb_addr[0], wb_data,
scop_cfg_ack, scop_cfg_stall, scop_cfg_data,
scop_cfg_interrupt);
scop_ack, scop_stall, scop_data,
scop_interrupt);
`else
reg r_scop_cfg_ack;
reg r_scop_ack;
always @(posedge i_clk)
r_scop_cfg_ack <= (wb_stb)&&(scop_sel);
assign scop_cfg_ack = r_scop_cfg_ack;
assign scop_cfg_data = 32'h000;
assign scop_cfg_stall= 1'b0;
r_scop_ack <= (wb_stb)&&(scop_sel);
assign scop_ack = r_scop_ack;
assign scop_data = 32'h000;
assign scop_stall= 1'b0;
`endif
 
assign scop_interrupt = scop_cfg_interrupt;
assign scop_ack = scop_cfg_ack;
assign scop_stall = scop_cfg_stall;
assign scop_data = scop_cfg_data;
 
endmodule
 
/rtl/alttop.v
43,6 → 43,7
////////////////////////////////////////////////////////////////////////////////
//
//
// `define LOWLOGIC_FLASH
module alttop(i_clk_8mhz,
o_qspi_cs_n, o_qspi_sck, io_qspi_dat,
i_btn, o_led, o_pwm, o_pwm_shutdown_n, o_pwm_gain,
89,7 → 90,7
//
// Generate a usable clock for the rest of the board to run at.
//
wire ck_zero_0, clk_s;
wire ck_zero_0, clk_s, clk_sn;
 
// Clock frequency = (20 / 2) * 8Mhz = 80 MHz
// Clock period = 12.5 ns
110,6 → 111,7
.CLK0(ck_zero_0),
.CLKFB(ck_zero_0),
.CLKFX(clk_s),
.CLKFX180(clk_sn),
.PSEN(1'b0),
.RST(1'b0));
 
126,7 → 128,7
wire tx_busy;
wire [29:0] uart_setup;
 
// Baud rate is set by clock rate / baud rate desired. Thus,
// Baud rate is set by clock rate / baud rate desired. Thus,
// 80 MHz / 9600 Baud = 8333, or about 0x208d. We choose a slow
// speed such as 9600 Baud to help the CPU keep up with the serial
// port rate.
159,6 → 161,12
// This is an alternate version of the busmaster interface,
// offering no ZipCPU and access to reprogramming via the flash.
//
`ifdef LOWLOGIC_FLASH
wire [1:0] qspi_sck;
`else
wire qspi_sck;
`endif
wire qspi_cs_n;
wire [3:0] qspi_dat;
wire [1:0] qspi_bmod;
wire [15:0] w_gpio;
174,7 → 182,7
// External UART interface
rx_stb, rx_data, tx_stb, tx_data, tx_busy, w_uart_rts_n,
// SPI/SD-card flash
o_qspi_cs_n, o_qspi_sck, qspi_dat, io_qspi_dat, qspi_bmod,
qspi_cs_n, qspi_sck, qspi_dat, io_qspi_dat, qspi_bmod,
// Board lights and switches
i_btn, o_led, o_pwm, { o_pwm_shutdown_n, o_pwm_gain },
// Keypad connections
195,10 → 203,42
// port with one wire in and one wire out. This utilizes our
// control wires (qspi_bmod) to set the output lines appropriately.
//
assign io_qspi_dat = (~qspi_bmod[1])?({2'b11,1'bz,qspi_dat[0]})
//
// 2'b0? -- Normal SPI
// 2'b10 -- Quad Output
// 2'b11 -- Quad Input
`ifdef LOWLOGIC_FLASH
reg r_qspi_cs_n;
reg [1:0] r_qspi_bmod;
reg [3:0] r_qspi_dat, r_qspi_z;
reg [1:0] r_qspi_sck;
always @(posedge clk_s)
r_qspi_sck <= qspi_sck;
xoddr xqspi_sck({clk_s, clk_sn}, r_qspi_sck, o_qspi_sck);
initial r_qspi_cs_n = 1'b1;
initial r_qspi_z = 4'b1101;
always @(posedge clk_s)
begin
r_qspi_dat <= (qspi_bmod[1]) ? qspi_dat:{ 3'b111, qspi_dat[0]};
r_qspi_z <= (!qspi_bmod[1])? 4'b1101
: ((qspi_bmod[0]) ? 4'h0 : 4'hf);
r_qspi_cs_n <= qspi_cs_n;
end
 
assign o_qspi_cs_n = r_qspi_cs_n;
assign io_qspi_dat[0] = (r_qspi_z[0]) ? r_qspi_dat[0] : 1'bz;
assign io_qspi_dat[1] = (r_qspi_z[1]) ? r_qspi_dat[1] : 1'bz;
assign io_qspi_dat[2] = (r_qspi_z[2]) ? r_qspi_dat[2] : 1'bz;
assign io_qspi_dat[3] = (r_qspi_z[3]) ? r_qspi_dat[3] : 1'bz;
`else
assign io_qspi_dat = (!qspi_bmod[1])?({2'b11,1'bz,qspi_dat[0]})
:((qspi_bmod[0])?(4'bzzzz):(qspi_dat[3:0]));
 
`else
assign o_qspi_cs_n = qspi_cs_n;
assign o_qspi_sck = qspi_sck;
`endif // LOWLOGIC_FLASH
 
`else // BYPASS_LOGIC
reg [26:0] r_counter;
always @(posedge clk_s)
r_counter <= r_counter+1;
225,7 → 265,7
assign uart_setup = 30'h080002b6;
 
assign o_uart_rts_n = 1'b0;
`endif
`endif // BYPASS_LOGIC
//
// I2C support
//
232,7 → 272,7
// Supporting I2C requires a couple quick adjustments to our
// GPIO lines. Specifically, we'll allow that when the output
// (i.e. w_gpio) pins are high, then the I2C lines float. They
// will be (need to be) pulled up by a resistor in order to
// will be (need to be) pulled up by a resistor in order to
// match the I2C protocol, but this change makes them look/act
// more like GPIO pins.
//
/rtl/builddate.v
1,7 → 272,7
`define DATESTAMP 32'h20170309
`define DATESTAMP 32'h20170321
/rtl/busmaster.v
46,7 → 46,10
`define FLASH_ACCESS
`define DBG_SCOPE // About 204 LUTs, at 2^6 addresses
// `define COMPRESSED_SCOPE
`define HAS_RXUART
`define INCLUDE_CPU_RESET_LOGIC
`define LOWLOGIC_FLASH // Saves about 154 LUTs
`define USE_LITE_UART // Saves about 55 LUTs
module busmaster(i_clk, i_rst,
i_uart, o_uart_rts_n, o_uart, i_uart_cts_n,
// The SPI Flash lines
75,7 → 78,12
input i_uart, i_uart_cts_n;
output wire o_uart, o_uart_rts_n;
// SPI flash control
output wire o_qspi_cs_n, o_qspi_sck;
output wire o_qspi_cs_n;
`ifdef LOWLOGIC_FLASH
output wire [1:0] o_qspi_sck;
`else
output wire o_qspi_sck;
`endif
output wire [3:0] o_qspi_dat;
input [3:0] i_qspi_dat;
output wire [1:0] o_qspi_mod;
140,11 → 148,11
end
assign cpu_reset = btn_reset;
`else
assign cpu_reset = 1'b0;
assign cpu_reset = (watchdog_int);
`endif
 
zipbones #(CMOD_ZIPCPU_RESET_ADDRESS,ZA,6)
swic(i_clk, btn_reset, // 1'b0,
swic(i_clk, cpu_reset, // 1'b0,
// Zippys wishbone interface
wb_cyc, wb_stb, wb_we, w_zip_addr, wb_data, wb_sel,
wb_ack, wb_stall, wb_idata, wb_err,
437,7 → 445,8
wb_we, wb_data, spio_data,
o_kp_col, i_kp_row, i_btn, w_led,
keypad_int, button_int);
assign o_led = { w_led[3]|w_interrupt,w_led[2]|zip_cpu_int,w_led[1:0] };
assign o_led = { w_led[3]|w_interrupt,w_led[2]|zip_cpu_int,
w_led[1], w_led[0] };
 
//
// General purpose (sort of) I/O: (Bottom two bits robbed in each
459,17 → 468,40
//
assign uart_setup = UART_SETUP;
//
`ifdef HAS_RXUART
`ifdef USE_LITE_UART
rxuartlite #(UART_SETUP[23:0])
rcvuart(i_clk, i_uart, rx_stb, rx_data);
assign rx_break = 1'b0;
assign rx_parity_err = 1'b0;
assign rx_frame_err = 1'b0;
assign rx_ck_uart = 1'b0;
`else
rxuart #(UART_SETUP)
rcvuart(i_clk, 1'b0, uart_setup, i_uart, rx_stb, rx_data,
rx_break, rx_parity_err, rx_frame_err, rx_ck_uart);
`endif
`else
assign rx_break = 1'b0;
assign rx_parity_err = 1'b0;
assign rx_frame_err = 1'b0;
assign rx_ck_uart = 1'b0;
assign rx_stb = 1'b0;
assign rx_data = 8'h0;
`endif
//
wire tx_break, tx_busy;
reg tx_stb;
reg [7:0] tx_data;
assign tx_break = 1'b0;
`ifdef USE_LITE_UART
txuartlite #(UART_SETUP[23:0])
tcvuart(i_clk, tx_stb, tx_data, o_uart, tx_busy);
`else
txuart #(UART_SETUP)
tcvuart(i_clk, 1'b0, uart_setup, tx_break, tx_stb, tx_data,
i_uart_cts_n, o_uart, tx_busy);
`endif
 
//
// Rudimentary serial port control
487,6 → 519,7
end
else if ((tx_stb)&&(!tx_busy))
tx_stb <= 1'b0;
`ifdef HAS_RXUART
initial rx_rdy = 1'b0;
always @(posedge i_clk)
if (rx_stb)
495,11 → 528,15
begin
if((wb_stb)&&(io_sel)&&(wb_addr[3:0]==4'h7)&&(!wb_we))
rx_rdy <= rx_stb;
else if (rx_stb)
else
rx_rdy <= (rx_rdy | rx_stb);
end
assign o_uart_rts_n = (rx_rdy);
assign uart_data = { 23'h0, !rx_rdy, r_rx_data };
`else
assign o_uart_rts_n = 1'b1;
assign uart_data = 32'h00;
`endif
//
// uart_ack gets returned as part of io_ack, since that happens when
// io_sel and wb_stb are defined
513,6 → 550,15
// FLASH MEMORY CONFIGURATION ACCESS
//
`ifdef FLASH_ACCESS
`ifdef LOWLOGIC_FLASH
qflashxpress flashmem(i_clk,
wb_cyc,(wb_stb)&&(flash_sel),
wb_addr[(LGFLASHSZ-3):0],
flash_ack, flash_stall, flash_data,
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat);
 
assign flash_interrupt = 1'b0;
`else
wbqspiflash #(LGFLASHSZ) flashmem(i_clk,
wb_cyc,(wb_stb)&&(flash_sel),(wb_stb)&&(flctl_sel),wb_we,
wb_addr[(LGFLASHSZ-3):0], wb_data,
519,6 → 565,7
flash_ack, flash_stall, flash_data,
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat,
flash_interrupt);
`endif
`else
reg r_flash_ack;
initial r_flash_ack = 1'b0;
/rtl/cpu/cpudefs.v
41,7 → 41,7
// 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
// with this program. (It's in the $(ROOT)/doc directory. Run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
103,12 → 103,12
// mode.
//
//
// `define OPT_DIVIDE
`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.
// 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
122,36 → 122,11
//
//
//
// The instruction set defines an optional compressed instruction set (CIS)
// complement. These were at one time erroneously called Very Long Instruction
// Words. They are more appropriately referred to as compressed instructions.
// The compressed instruction format allows two instructions to be packed into
// the same instruction word. Some instructions can be compressed, not all.
// Compressed instructions take the same time to complete. Set OPT_CIS to
// include these double instructions as part of the instruction set. 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-CIS instructions, or CIS instruction pairs, atomically.
// This logic has been added into the ZipCPU, but it has not (yet) been
// tested thoroughly.
//
// Oh, and the debugger and the simulator also need to be updated as well
// to properly handle these.
//
// `define OPT_CIS // Adds about 80 LUTs on a Spartan 6
//
//
//
//
// OPT_SINGLE_FETCH controls whether or not the prefetch has a cache, and
// 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
// 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.
160,7 → 135,7
//
// 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
// 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:
//
172,10 → 147,66
// 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
//`define OPT_SINGLE_FETCH // 2047 total LUTs (savings of 181 from before)
//
//
// OPT_DOUBLE_FETCH is an alternative to OPT_SINGLE_FETCH. It is designed to
// increase performance primarily when using an instruction memory which has
// one cost for a random access, and a second (lower) cost for sequential
// access. The driving example behind this implementation was flash memory
// with 34 clocks for an initial access and 16 clocks for any subsequent access,
// but SDRAM memory with 27 clocks for an initial access and 1 clock for a
// subsequent access is also a good example. Even block RAM might be a good
// example, if there were any bus delays in getting to the RAM device. Using
// OPT_DOUBLE_FETCH also increases the pipeline speed, as it allows CIS
// instructions and therefore partial pipelining. (No work is done to resolve
// pipeline conflicts past the decode stage, as is the case with full pipeline
// mode.
//
// Do not define OPT_DOUBLE_FETCH if you wish to fully pipeline the CPU. Do
// not define both OPT_DOUBLE_FETCH and OPT_SINGLE_FETCH (the ifndef below
// should prevent that).
//
//
// // COST: about 79 LUTs over and above the SINGLE_FETCH cost [2091 LUTs]
`ifndef OPT_SINGLE_FETCH
`define OPT_DOUBLE_FETCH
`endif
//
//
//
// The ZipCPU ISA defines an optional compressed instruction set (CIS)
// complement. This compressed instruction format allows two instructions to
// be packed into the same instruction word. Some instructions can be so
// compressed, although not all. Compressed instructions take the same time to
// complete--they are just compressed within memory to spare troubles with the
// prefetch. Set OPT_CIS to include these compressed instructions as part of
// the instruction set.
//
//
// // COST: about 87 LUTs
//
`define OPT_CIS
//
//
//
//
// 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.
// With the OPT_TRADITIONAL_PFCACHE, BRA instructions cost only a single
// extra stall cycle, while LJMP instructions cost two (assuming the target is
// in the cache). Indeed, the result is that a BRA instruction can be used as
// the compiler's branch prediction optimizer: BRA's barely stall, while
// conditional branches will always suffer about 4 stall cycles or so.
//
// I recommend setting this flag, so as to turn early branching on---if you
// have the LUTs available to afford it.
//
// `define OPT_EARLY_BRANCHING
//
//
//
//
// 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
182,12 → 213,13
// is not defined).
//
`ifndef OPT_SINGLE_FETCH
`ifndef OPT_DOUBLE_FETCH
//
//
//
// OPT_PIPELINED is the natural result and opposite of using the single
// 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
// 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.
//
210,21 → 242,7
//
//
//
// 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
243,8 → 261,7
//
//
//
//
//
`endif // OPT_DOUBLE_FETCH
`endif // OPT_SINGLE_FETCH
//
//
/rtl/cpu/cpuops.v
128,8 → 128,8
assign mpy_result = r_mpy_a_input * r_mpy_b_input;
assign mpybusy = 1'b0;
 
reg mpypipe;
initial mpypipe = 1'b0;
reg mpypipe;
always @(posedge i_clk)
if (i_rst)
mpypipe <= 1'b0;
205,6 → 205,7
reg [2:0] mpypipe;
 
// First clock, latch in the inputs
initial mpypipe = 3'b0;
always @(posedge i_clk)
begin
// mpypipe indicates we have a multiply in the
/rtl/cpu/dblfetch.v
0,0 → 1,232
////////////////////////////////////////////////////////////////////////////////
//
// Filename: dblfetch.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: This is one step beyond the simplest instruction fetch,
// prefetch.v. dblfetch.v uses memory pipelining to fetch two
// instruction words in one cycle, figuring that the unpipelined CPU can't
// go through both at once, but yet recycles itself fast enough for the
// next instruction that would follow. It is designed to be a touch
// faster than the single instruction prefetch, although not as fast as
// the prefetch and cache found elsewhere.
//
// There are some gotcha's in this logic, however. For example, it's
// illegal to switch devices mid-transaction, since the second device
// might have different timing. I.e. the first device might take 8
// clocks to create an ACK, and the second device might take 2 clocks, the
// acks might therefore come on top of each other, or even out of order.
// But ... in order to keep logic down, we keep track of the PC in the
// o_wb_addr register. Hence, this register gets changed on any i_new_pc.
// The i_pc value associated with i_new_pc will only be valid for one
// clock, hence we can't wait to change. To keep from violating the WB
// rule, therefore, we *must* immediately stop requesting any transaction,
// and then terminate the bus request as soon as possible.
//
// This has consequences in terms of logic used, leaving this routine
// anything but simple--even though the number of wires affected by
// this is small (o_wb_cyc, o_wb_stb, and last_ack).
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory. Run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
module dblfetch(i_clk, i_rst, i_new_pc, i_clear_cache,
i_stall_n, i_pc, o_i, o_pc, o_v,
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_err, i_wb_data,
o_illegal);
parameter ADDRESS_WIDTH=32, AUX_WIDTH = 1;
localparam AW=ADDRESS_WIDTH;
input i_clk, i_rst, i_new_pc, i_clear_cache,
i_stall_n;
input [(AW-1):0] i_pc;
output reg [31:0] o_i;
output reg [(AW-1):0] o_pc;
output wire o_v;
// Wishbone outputs
output reg o_wb_cyc, o_wb_stb;
output wire o_wb_we;
output reg [(AW-1):0] o_wb_addr;
output wire [31:0] o_wb_data;
// And return inputs
input i_wb_ack, i_wb_stall, i_wb_err;
input [31:0] i_wb_data;
// And ... the result if we got an error
output reg o_illegal;
 
assign o_wb_we = 1'b0;
assign o_wb_data = 32'h0000;
 
reg last_ack, last_stb, invalid_bus_cycle;
 
reg [31:0] cache [0:1];
reg cache_read_addr, cache_write_addr;
reg [1:0] cache_valid;
 
initial o_wb_cyc = 1'b0;
initial o_wb_stb = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(i_wb_err))
begin
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
// last_stb <= 1'b0;
// last_ack <= 1'b0;
end else if (o_wb_cyc)
begin
if ((o_wb_stb)&&(!i_wb_stall))
begin
// last_stb <= 1'b1;
o_wb_stb <= !last_stb;
end
// if (i_wb_ack)
// last_ack <= 1'b1;
if ((i_new_pc)||(invalid_bus_cycle))
o_wb_stb <= 1'b0;
 
if ((i_wb_ack)&&(
// Relase the bus on the second ack
(last_ack)
// Or on the first ACK, if we've been told
// we have an invalid bus cycle
||((o_wb_stb)&&(i_wb_stall)&&(last_stb)&&(
(i_new_pc)||(invalid_bus_cycle)))
))
begin
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
end
 
if ((!last_stb)&&(i_wb_stall)&&((i_new_pc)||(invalid_bus_cycle)))
// Also release the bus with no acks, if we
// haven't made any requests
begin
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
end
end else if ((invalid_bus_cycle)
||((o_v)&&(i_stall_n)&&(cache_read_addr))) // Initiate a bus cycle
begin
o_wb_cyc <= 1'b1;
o_wb_stb <= 1'b1;
// last_stb <= 1'b0;
// last_ack <= 1'b0;
end
 
initial last_stb = 1'b0;
always @(posedge i_clk)
if ((o_wb_cyc)&&(o_wb_stb)&&(!i_wb_stall))
last_stb <= 1'b1;
else if (!o_wb_cyc)
last_stb <= 1'b0;
 
initial last_ack = 1'b0;
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
last_ack <= 1'b1;
else if ((o_wb_cyc)&&(o_wb_stb)&&(i_wb_stall)&&(
(i_new_pc)||(invalid_bus_cycle)))
last_ack <= 1'b1;
else if ((o_wb_cyc)&&(o_wb_stb)&&(!i_wb_stall)&&(!last_stb)&&(
(i_new_pc)||(invalid_bus_cycle)))
last_ack <= 1'b1;
else if (!o_wb_cyc)
last_ack <= 1'b0;
 
initial invalid_bus_cycle = 1'b0;
always @(posedge i_clk)
if (i_rst)
invalid_bus_cycle <= 1'b0;
else if ((i_new_pc)||(i_clear_cache))
invalid_bus_cycle <= 1'b1;
else if (!o_wb_cyc)
invalid_bus_cycle <= 1'b0;
 
initial o_wb_addr = {(AW){1'b1}};
always @(posedge i_clk)
if (i_new_pc)
o_wb_addr <= i_pc;
else if ((o_wb_stb)&&(!i_wb_stall)&&(!invalid_bus_cycle))
o_wb_addr <= o_wb_addr + 1'b1;
 
initial cache_write_addr = 1'b0;
always @(posedge i_clk)
if (!o_wb_cyc)
cache_write_addr <= 1'b0;
else if ((o_wb_cyc)&&(i_wb_ack))
cache_write_addr <= cache_write_addr + 1'b1;
 
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
cache[cache_write_addr] <= i_wb_data;
 
initial cache_read_addr = 1'b0;
always @(posedge i_clk)
if ((i_new_pc)||(invalid_bus_cycle)
||((o_v)&&(cache_read_addr)&&(i_stall_n)))
cache_read_addr <= 1'b0;
else if ((o_v)&&(i_stall_n))
cache_read_addr <= 1'b1;
 
always @(posedge i_clk)
if ((i_new_pc)||(invalid_bus_cycle))
cache_valid <= 2'b00;
else begin
if ((o_v)&&(i_stall_n))
cache_valid[cache_read_addr] <= 1'b0;
if ((o_wb_cyc)&&(i_wb_ack))
cache_valid[cache_write_addr] <= 1'b1;
end
 
initial o_i = {(32){1'b1}};
always @(posedge i_clk)
if ((i_stall_n)&&(o_wb_cyc)&&(i_wb_ack))
o_i <= i_wb_data;
else
o_i <= cache[cache_read_addr];
 
initial o_pc = 0;
always @(posedge i_clk)
if (i_new_pc)
o_pc <= i_pc;
else if ((o_v)&&(i_stall_n))
o_pc <= o_pc + 1'b1;
 
assign o_v = cache_valid[cache_read_addr];
 
initial o_illegal = 1'b0;
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_err))
o_illegal <= 1'b1;
else if ((!o_wb_cyc)&&((i_new_pc)||(invalid_bus_cycle)))
o_illegal <= 1'b0;
 
endmodule
/rtl/cpu/div.v
121,12 → 121,13
 
reg r_sign, pre_sign, r_z, r_c, last_bit;
reg [(LGBW-1):0] r_bit;
 
reg zero_divisor;
initial zero_divisor = 1'b0;
always @(posedge i_clk)
zero_divisor <= (r_divisor == 0)&&(r_busy);
 
// The Divide logic begins with r_busy. We use r_busy to determine
// whether or not the divide is in progress, vs being complete.
// Here, we clear r_busy on any reset and set it on i_wr (the request
// do to a divide). The divide ends when we are on the last bit,
// or equivalently when we discover we are dividing by zero.
initial r_busy = 1'b0;
always @(posedge i_clk)
if (i_rst)
136,6 → 137,12
else if ((last_bit)||(zero_divisor))
r_busy <= 1'b0;
 
// o_busy is very similar to r_busy, save for some key differences.
// Primary among them is that o_busy needs to (possibly) be true
// for an extra clock after r_busy clears. This would be that extra
// clock where we negate the result (assuming a signed divide, and that
// the result is supposed to be negative.) Otherwise, the two are
// identical.
initial o_busy = 1'b0;
always @(posedge i_clk)
if (i_rst)
147,19 → 154,50
else if (~r_busy)
o_busy <= 1'b0;
 
// If we are asked to divide by zero, we need to halt. The sooner
// we halt and report the error, the better. Hence, here we look
// for a zero divisor while being busy. The always above us will then
// look at this and halt a divide in the middle if we are trying to
// divide by zero.
//
// Note that this works off of the 2BW-1 length vector. If we can
// simplify that, it should simplify our logic as well.
initial zero_divisor = 1'b0;
always @(posedge i_clk)
if ((i_rst)||(i_wr))
// zero_divisor <= (r_divisor == 0)&&(r_busy);
if (i_rst)
zero_divisor <= 1'b0;
else if (i_wr)
zero_divisor <= (i_denominator == 0);
else if (!r_busy)
zero_divisor <= 1'b0;
 
// o_valid is part of the ZipCPU protocol. It will be set to true
// anytime our answer is valid and may be used by the calling module.
// Indeed, the ZipCPU will halt (and ignore us) once the i_wr has been
// set until o_valid gets set.
//
// Here, we clear o_valid on a reset, and any time we are on the last
// bit while busy (provided the sign is zero, or we are dividing by
// zero). Since o_valid is self-clearing, we don't need to clear
// it on an i_wr signal.
initial o_valid = 1'b0;
always @(posedge i_clk)
if (i_rst)
o_valid <= 1'b0;
else if (r_busy)
begin
if ((last_bit)||(zero_divisor))
o_valid <= (zero_divisor)||(~r_sign);
o_valid <= (zero_divisor)||(!r_sign);
end else if (r_sign)
begin
o_valid <= (~zero_divisor); // 1'b1;
o_valid <= (!zero_divisor); // 1'b1;
end else
o_valid <= 1'b0;
 
// Division by zero error reporting. Anytime we detect a zero divisor,
// we set our output error, and then hold it until we are valid and
// everything clears.
initial o_err = 1'b0;
always @(posedge i_clk)
if((i_rst)||(o_valid))
169,91 → 207,145
else
o_err <= 1'b0;
 
// r_bit
//
// Keep track of which "bit" of our divide we are on. This number
// ranges from 31 down to zero. On any write, we set ourselves to
// 5'h1f. Otherwise, while we are busy (but not within the pre-sign
// adjustment stage), we subtract one from our value on every clock.
always @(posedge i_clk)
if ((r_busy)&&(!pre_sign))
r_bit <= r_bit + {(LGBW){1'b1}};
else
r_bit <= {(LGBW){1'b1}};
 
// last_bit
//
// This logic replaces a lot of logic that was inside our giant state
// machine with ... something simpler. In particular, we'll use this
// logic to determine we are processing our last bit. The only trick
// is, this bit needs to be set whenever (r_busy) and (r_bit == 0),
// hence we need to set on (r_busy) and (r_bit == 1) so as to be set
// when (r_bit == 0).
initial last_bit = 1'b0;
always @(posedge i_clk)
if ((i_wr)||(pre_sign)||(i_rst))
if (r_busy)
last_bit <= (r_bit == {{(LGBW-1){1'b0}},1'b1});
else
last_bit <= 1'b0;
else if (r_busy)
last_bit <= (r_bit == {{(LGBW-1){1'b0}},1'b1});
 
// pre_sign
//
// This is part of the state machine. pre_sign indicates that we need
// a extra clock to take the absolute value of our inputs. It need only
// be true for the one clock, and then it must clear itself.
initial pre_sign = 1'b0;
always @(posedge i_clk)
// if (i_rst) r_busy <= 1'b0;
// else
if (i_wr)
begin
//
// Set our values upon an initial command. Here's
// where we come in and start.
//
// r_busy <= 1'b1;
//
o_quotient <= 0;
r_bit <= {(LGBW){1'b1}};
r_divisor <= { i_denominator, {(BW-1){1'b0}} };
r_dividend <= i_numerator;
r_sign <= 1'b0;
pre_sign <= i_signed;
else
pre_sign <= 1'b0;
 
// As a result of our operation, we need to set the flags. The most
// difficult of these is the "Z" flag indicating that the result is
// zero. Here, we'll use the same logic that sets the low-order
// bit to clear our zero flag, and leave the zero flag set in all
// other cases. Well ... not quite. If we need to flip the sign of
// our value, then we can't quite clear the zero flag ... yet.
always @(posedge i_clk)
if((r_busy)&&(r_divisor[(2*BW-2):(BW)] == 0)&&(!diff[BW]))
// If we are busy, the upper bits of our divisor are
// zero (i.e., we got the shift right), and the top
// (carry) bit of the difference is zero (no overflow),
// then we could subtract our divisor from our dividend
// and hence we add a '1' to the quotient, while setting
// the zero flag to false.
r_z <= 1'b0;
else if ((!r_busy)&&(!r_sign))
r_z <= 1'b1;
end else if (pre_sign)
 
// r_dividend
// This is initially the numerator. On a signed divide, it then becomes
// the absolute value of the numerator. We'll subtract from this value
// the divisor shifted as appropriate for every output bit we are
// looking for--just as with traditional long division.
always @(posedge i_clk)
if (pre_sign)
begin
//
// Note that we only come in here, for one clock, if
// our initial value may have been signed. If we are
// doing an unsigned divide, we then skip this step.
//
r_sign <= ((r_divisor[(2*BW-2)])^(r_dividend[(BW-1)]));
// Negate our dividend if necessary so that it becomes
// a magnitude only value
// If we are doing a signed divide, then take the
// absolute value of the dividend
if (r_dividend[BW-1])
r_dividend <= -r_dividend;
// Do the same with the divisor--rendering it into
// a magnitude only.
// The begin/end block is important so we don't lose
// the fact that on an else we don't do anything.
end else if((r_busy)&&(r_divisor[(2*BW-2):(BW)]==0)&&(!diff[BW]))
// This is the condition whereby we set a '1' in our
// output quotient, and we subtract the (current)
// divisor from our dividend. (The difference is
// already kept in the diff vector above.)
r_dividend <= diff[(BW-1):0];
else if (!r_busy)
// Once we are done, and r_busy is no longer high, we'll
// always accept new values into our dividend. This
// guarantees that, when i_wr is set, the new value
// is already set as desired.
r_dividend <= i_numerator;
 
initial r_divisor = 0;
always @(posedge i_clk)
if (pre_sign)
begin
if (r_divisor[(2*BW-2)])
r_divisor[(2*BW-2):(BW-1)] <= -r_divisor[(2*BW-2):(BW-1)];
//
// We only do this stage for a single clock, so go on
// with the rest of the divide otherwise.
pre_sign <= 1'b0;
r_divisor[(2*BW-2):(BW-1)]
<= -r_divisor[(2*BW-2):(BW-1)];
end else if (r_busy)
r_divisor <= { 1'b0, r_divisor[(2*BW-2):1] };
else
r_divisor <= { i_denominator, {(BW-1){1'b0}} };
 
// r_sign
// is a flag for our state machine control(s). r_sign will be set to
// true any time we are doing a signed divide and the result must be
// negative. In that case, we take a final logic stage at the end of
// the divide to negate the output. This flag is what tells us we need
// to do that. r_busy will be true during the divide, then when r_busy
// goes low, r_sign will be checked, then the idle/reset stage will have
// been reached. For this reason, we cannot set r_sign unless we are
// up to something.
initial r_sign = 1'b0;
always @(posedge i_clk)
if (pre_sign)
r_sign <= ((r_divisor[(2*BW-2)])^(r_dividend[(BW-1)]));
else if (r_busy)
r_sign <= (r_sign)&&(!zero_divisor);
else
r_sign <= 1'b0;
 
always @(posedge i_clk)
if (r_busy)
begin
// While the divide is taking place, we examine each bit
// in turn here.
//
r_bit <= r_bit + {(LGBW){1'b1}}; // r_bit = r_bit - 1;
r_divisor <= { 1'b0, r_divisor[(2*BW-2):1] };
if (|r_divisor[(2*BW-2):(BW)])
o_quotient <= { o_quotient[(BW-2):0], 1'b0 };
if ((r_divisor[(2*BW-2):(BW)] == 0)&&(!diff[BW]))
begin
end else if (diff[BW])
begin
//
// diff = r_dividend - r_divisor[(BW-1):0];
//
// If this value was negative, there wasn't
// enough value in the dividend to support
// pulling off a bit. We'll move down a bit
// therefore and try again.
//
end else begin
//
// Put a '1' into our output accumulator.
// Subtract the divisor from the dividend,
// and then move on to the next bit
//
r_dividend <= diff[(BW-1):0];
o_quotient[r_bit[(LGBW-1):0]] <= 1'b1;
r_z <= 1'b0;
o_quotient[0] <= 1'b1;
end
r_sign <= (r_sign)&&(~zero_divisor);
end else if (r_sign)
begin
r_sign <= 1'b0;
o_quotient <= -o_quotient;
end
else
o_quotient <= 0;
 
// Set Carry on an exact divide
wire w_n;
// Perhaps nothing uses this, but ... well, I suppose we could remove
// this logic eventually, just ... not yet.
always @(posedge i_clk)
r_c <= (r_busy)&&((diff == 0)||(r_dividend == 0));
 
// The last flag: Negative. This flag is set assuming that the result
// of the divide was negative (i.e., the high order bit is set). This
// will also be true of an unsigned divide--if the high order bit is
// ever set upon completion. Indeed, you might argue that there's no
// logic involved.
wire w_n;
assign w_n = o_quotient[(BW-1)];
 
assign o_flags = { 1'b0, w_n, r_c, r_z };
/rtl/cpu/idecode.v
55,6 → 55,7
module idecode(i_clk, i_rst, i_ce, i_stalled,
i_instruction, i_gie, i_pc, i_pf_valid,
i_illegal,
o_valid,
o_phase, o_illegal,
o_pc, o_gie,
o_dcdR, o_dcdA, o_dcdB, o_I, o_zI,
72,7 → 73,7
input i_gie;
input [(AW-1):0] i_pc;
input i_pf_valid, i_illegal;
output wire o_phase;
output wire o_valid, o_phase;
output reg o_illegal;
output reg [AW:0] o_pc;
output reg o_gie;
105,13 → 106,14
 
 
wire [4:0] w_op;
wire w_ldi, w_mov, w_cmptst, w_ldilo, w_ALU, w_brev, w_noop;
wire w_ldi, w_mov, w_cmptst, w_ldilo, w_ALU, w_brev,
w_noop, w_lock;
wire [4:0] w_dcdR, w_dcdB, w_dcdA;
wire w_dcdR_pc, w_dcdR_cc;
wire w_dcdA_pc, w_dcdA_cc;
wire w_dcdB_pc, w_dcdB_cc;
wire [3:0] w_cond;
wire w_wF, w_mem, w_sto, w_lod, w_div, w_fpu;
wire w_wF, w_mem, w_sto, w_div, w_fpu;
wire w_wR, w_rA, w_rB, w_wR_n;
wire w_ljmp, w_ljmp_dly, w_cis_ljmp;
wire [31:0] iword;
217,9 → 219,21
// If the result register is either CC or PC, and this would otherwise
// be a floating point instruction with floating point opcode of 0,
// then this is a NOOP.
assign w_lock = (!iword[31])&&(w_op[4:0]==5'h1d)&&(
((IMPLEMENT_FPU>0)&&(w_dcdR[3:1]==3'h7))
||(IMPLEMENT_FPU==0));
`ifdef OPT_PIPELINED
assign w_noop = (!iword[31])&&(w_op[4:0] == 5'h1f)&&(
((IMPLEMENT_FPU>0)&&(w_dcdR[3:1] == 3'h7))
||(IMPLEMENT_FPU==0));
`else
// Allow w_lock's to set the w_noop bit in the case of no pipelining
assign w_noop = (!iword[31])
&&((w_op[4:0] == 5'h1f)||(w_op[4:0]==5'h1d))
&&(
((IMPLEMENT_FPU>0)&&(w_dcdR[3:1] == 3'h7))
||(IMPLEMENT_FPU==0));
`endif
 
// dcdB - What register is used in the opB?
//
252,7 → 266,6
// 1 LUT
assign w_mem = (w_cis_op[4:3] == 2'b10)&&(w_cis_op[2:1] !=2'b00);
assign w_sto = (w_mem)&&( w_cis_op[0]);
assign w_lod = (w_mem)&&(!w_cis_op[0]);
// 1 LUT
assign w_div = (!iword[31])&&(w_op[4:1] == 4'h7);
// 2 LUTs
387,9 → 400,9
&&(w_dcdR[3:1]==3'h7)
&&(
(w_cis_op[2:0] != 3'h4) // BREAK
`ifdef OPT_PIPELINED
// `ifdef OPT_PIPELINED
&&(w_cis_op[2:0] != 3'h5) // LOCK
`endif
// `endif
// SIM instructions are always illegal
&&(w_cis_op[2:0] != 3'h7))) // NOOP
o_illegal <= 1'b1;
403,12 → 416,16
if (!o_phase)
o_gie<= i_gie;
 
if ((iword[31])&&(!o_phase))
o_pc <= { i_pc, 1'b1 };
else if ((iword[31])&&(i_pf_valid))
o_pc <= { i_pc, 1'b0 };
else
if (iword[31])
begin
if (o_phase)
o_pc <= o_pc + 1'b1;
else if (i_pf_valid)
o_pc <= { i_pc, 1'b1 };
end else begin
// The normal, non-CIS case
o_pc <= { i_pc + 1'b1, 1'b0 };
end
`else
o_gie<= i_gie;
o_pc <= { i_pc + 1'b1, 1'b0 };
460,9 → 477,7
((IMPLEMENT_FPU>0)&&(w_dcdR[3:1]==3'h7))
||(IMPLEMENT_FPU==0));
`ifdef OPT_PIPELINED
r_lock <= (!iword[31])&&(w_op[4:0]==5'h1d)&&(
((IMPLEMENT_FPU>0)&&(w_dcdR[3:1]==3'h7))
||(IMPLEMENT_FPU==0));
r_lock <= w_lock;
`endif
`ifdef OPT_CIS
r_nxt_half <= { iword[31], iword[14:0] };
588,14 → 603,15
always @(posedge i_clk)
if (i_rst)
r_valid <= 1'b0;
else if ((i_ce)&&(o_ljmp))
else if (i_ce)
r_valid <= ((i_pf_valid)||(o_phase)||(i_illegal))
&&(!o_ljmp)&&(!o_early_branch);
else if (!i_stalled)
r_valid <= 1'b0;
else if ((i_ce)&&(i_pf_valid))
r_valid <= 1'b1;
else if (~i_stalled)
r_valid <= 1'b0;
 
assign o_valid = r_valid;
 
 
assign o_I = { {(32-22){r_I[22]}}, r_I[21:0] };
 
endmodule
/rtl/cpu/memops.v
163,10 → 163,10
 
initial o_valid = 1'b0;
always @(posedge i_clk)
o_valid <= ((o_wb_cyc_gbl)||(o_wb_cyc_lcl))&&(i_wb_ack)&&(~o_wb_we);
o_valid <= (!i_rst)&&((o_wb_cyc_gbl)||(o_wb_cyc_lcl))&&(i_wb_ack)&&(~o_wb_we);
initial o_err = 1'b0;
always @(posedge i_clk)
o_err <= ((o_wb_cyc_gbl)||(o_wb_cyc_lcl))&&(i_wb_err);
o_err <= (!i_rst)&&((o_wb_cyc_gbl)||(o_wb_cyc_lcl))&&(i_wb_err);
assign o_busy = (o_wb_cyc_gbl)||(o_wb_cyc_lcl);
 
always @(posedge i_clk)
/rtl/cpu/prefetch.v
53,18 → 53,18
// mode which this prefetch does not support. In non--pipelined mode, the
// flash will require (16+6+6)*2 = 56 clocks plus 16 clocks per word read,
// or 72 clocks to fetch one instruction.
module prefetch(i_clk, i_rst, i_ce, i_stalled_n, i_pc, i_aux,
o_i, o_pc, o_aux, o_valid, o_illegal,
module prefetch(i_clk, i_rst, i_new_pc, i_clear_cache, i_stalled_n, i_pc,
o_i, o_pc, o_valid, o_illegal,
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data,
i_wb_ack, i_wb_stall, i_wb_err, i_wb_data);
parameter ADDRESS_WIDTH=32, AUX_WIDTH = 1, AW=ADDRESS_WIDTH;
input i_clk, i_rst, i_ce, i_stalled_n;
parameter ADDRESS_WIDTH=32;
localparam AW=ADDRESS_WIDTH;
input i_clk, i_rst, i_new_pc, i_clear_cache,
i_stalled_n;
input [(AW-1):0] i_pc;
input [(AUX_WIDTH-1):0] i_aux;
output reg [31:0] o_i;
output reg [(AW-1):0] o_pc;
output reg [(AUX_WIDTH-1):0] o_aux;
output reg o_valid, o_illegal;
output wire [(AW-1):0] o_pc;
output reg o_valid;
// Wishbone outputs
output reg o_wb_cyc, o_wb_stb;
output wire o_wb_we;
71,8 → 71,9
output reg [(AW-1):0] o_wb_addr;
output wire [31:0] o_wb_data;
// And return inputs
input i_wb_ack, i_wb_stall, i_wb_err;
input [31:0] i_wb_data;
input i_wb_ack, i_wb_stall, i_wb_err;
input [31:0] i_wb_data;
output reg o_illegal;
 
assign o_wb_we = 1'b0;
assign o_wb_data = 32'h0000;
84,47 → 85,54
initial o_wb_stb = 1'b0;
initial o_wb_addr= 0;
always @(posedge i_clk)
if ((i_rst)||(i_wb_ack))
if ((i_rst)||(i_wb_ack)||(i_wb_err))
begin
o_wb_cyc <= 1'b0;
o_wb_stb <= 1'b0;
end else if ((i_ce)&&(~o_wb_cyc)) // Initiate a bus cycle
begin
end else if ((!o_wb_cyc)&&((i_stalled_n)||(!o_valid)))
begin // Initiate a bus cycle
o_wb_cyc <= 1'b1;
o_wb_stb <= 1'b1;
end else if (o_wb_cyc) // Independent of ce
begin
if ((o_wb_cyc)&&(o_wb_stb)&&(~i_wb_stall))
if (~i_wb_stall)
o_wb_stb <= 1'b0;
if (i_wb_ack)
o_wb_cyc <= 1'b0;
end
 
reg invalid;
initial invalid = 1'b0;
always @(posedge i_clk)
if (i_rst) // Set the address to guarantee the result is invalid
o_wb_addr <= {(AW){1'b1}};
else if ((i_ce)&&(~o_wb_cyc))
if (!o_wb_cyc)
invalid <= 1'b0;
else if ((i_new_pc)||(i_clear_cache))
invalid <= (!o_wb_stb);
 
always @(posedge i_clk)
if (i_new_pc)
o_wb_addr <= i_pc;
else if ((!o_wb_cyc)&&(i_stalled_n)&&(!invalid))
o_wb_addr <= o_wb_addr + 1'b1;
 
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
o_aux <= i_aux;
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
if (i_wb_ack)
o_i <= i_wb_data;
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
o_pc <= o_wb_addr;
 
initial o_valid = 1'b0;
initial o_illegal = 1'b0;
always @(posedge i_clk)
if ((o_wb_cyc)&&(i_wb_ack))
if (i_rst)
begin
o_valid <= (i_pc == o_wb_addr)&&(~i_wb_err);
o_illegal <= (i_wb_err)&&(i_pc == o_wb_addr);
end else if (i_stalled_n)
o_valid <= 1'b0;
o_illegal <= 1'b0;
end else if ((o_wb_cyc)&&(i_wb_ack))
begin
o_valid <= (!i_wb_err)&&(!invalid);
o_illegal <= ( i_wb_err)&&(!invalid);
end else if ((i_stalled_n)||(i_clear_cache))
begin
o_valid <= 1'b0;
o_illegal <= 1'b0;
end
 
assign o_pc = o_wb_addr;
endmodule
/rtl/cpu/zipcpu.v
45,7 → 45,7
// as:
//
//
// assign (n)_ce = (n-1)_valid && (~(n)_stall)
// assign (n)_ce = (n-1)_valid && (!(n)_stall)
//
//
// always @(posedge i_clk)
261,7 → 261,6
dcd_ALU, dcd_M, dcd_DIV, dcd_FP,
dcd_wF, dcd_gie, dcd_break, dcd_lock,
dcd_pipe, dcd_ljmp;
reg r_dcd_valid;
wire dcd_valid;
wire [AW:0] dcd_pc /* verilator public_flat */;
wire [31:0] dcd_I;
298,10 → 297,6
wire [7:0] op_F;
wire op_ce, op_phase, op_pipe, op_change_data_ce;
// Some pipeline control wires
`ifdef OPT_PIPELINED
reg op_A_alu, op_A_mem;
reg op_B_alu, op_B_mem;
`endif
reg op_illegal;
wire op_break;
wire op_lock;
347,8 → 342,8
wire [31:0] div_result;
wire [3:0] div_flags;
 
assign div_ce = (master_ce)&&(~clear_pipeline)&&(op_valid_div)
&&(~mem_rdbusy)&&(~div_busy)&&(~fpu_busy)
assign div_ce = (master_ce)&&(!clear_pipeline)&&(op_valid_div)
&&(!mem_rdbusy)&&(!div_busy)&&(!fpu_busy)
&&(set_cond);
 
wire fpu_ce, fpu_error, fpu_busy, fpu_valid;
355,8 → 350,8
wire [31:0] fpu_result;
wire [3:0] fpu_flags;
 
assign fpu_ce = (master_ce)&&(~clear_pipeline)&&(op_valid_fpu)
&&(~mem_rdbusy)&&(~div_busy)&&(~fpu_busy)
assign fpu_ce = (master_ce)&&(!clear_pipeline)&&(op_valid_fpu)
&&(!mem_rdbusy)&&(!div_busy)&&(!fpu_busy)
&&(set_cond);
 
wire adf_ce_unconditional;
379,7 → 374,7
//
// MASTER: clock enable.
//
assign master_ce = ((~i_halt)||(alu_phase))&&(~o_break)&&(~sleep);
assign master_ce = ((!i_halt)||(alu_phase))&&(!o_break)&&(!sleep);
 
 
//
392,15 → 387,11
//
// PIPELINE STAGE #2 :: Instruction Decode
// Calculate stall conditions
assign dcd_ce = ((~dcd_valid)||(~dcd_stalled))&&(~clear_pipeline);
 
`ifdef OPT_PIPELINED
assign dcd_stalled = (dcd_valid)&&(op_stall);
`else
// If not pipelined, there will be no op_valid_ anything, and the
// op_stall will be false, dcd_X_stall will be false, thus we can simply
// do a ...
assign dcd_stalled = 1'b0;
`else // Not pipelined -- either double or single fetch
assign dcd_stalled = (dcd_valid)&&(op_stall);
`endif
//
// PIPELINE STAGE #3 :: Read Operands
418,7 → 409,7
assign op_stall = (op_valid)&&( // Only stall if we're loaded w/validins
// Stall if we're stopped, and not allowed to execute
// an instruction
// (~master_ce) // Already captured in alu_stall
// (!master_ce) // Already captured in alu_stall
//
// Stall if going into the ALU and the ALU is stalled
// i.e. if the memory is busy, or we are single
452,6 → 443,11
);
assign op_ce = ((dcd_valid)||(dcd_illegal)||(dcd_early_branch))&&(!op_stall);
 
`else
assign op_stall = (alu_busy)||(div_busy)||(fpu_busy)||(wr_reg_ce)
||(mem_busy)||(op_valid)||(!master_ce)||(wr_flags_ce);
assign op_ce = ((dcd_valid)||(dcd_illegal)||(dcd_early_branch))&&(!op_stall);
`endif
 
// BUT ... op_ce is too complex for many of the data operations. So
// let's make their circuit enable code simpler. In particular, if
458,12 → 454,7
// op_ doesn't need to be preserved, we can change it all we want
// ... right? The clear_pipeline code, for example, really only needs
// to determine whether op_valid is true.
assign op_change_data_ce = (~op_stall);
`else
assign op_stall = (op_valid)&&(~master_ce);
assign op_ce = ((dcd_valid)||(dcd_illegal)||(dcd_early_branch))&&(~clear_pipeline);
assign op_change_data_ce = 1'b1;
`endif
assign op_change_data_ce = (!op_stall);
 
//
// PIPELINE STAGE #4 :: ALU / Memory
479,16 → 470,16
// through the ALU. Break instructions are not allowed through
// the ALU.
`ifdef OPT_PIPELINED
assign alu_stall = (((~master_ce)||(mem_rdbusy)||(alu_busy))&&(op_valid_alu)) //Case 1&2
assign alu_stall = (((!master_ce)||(mem_rdbusy)||(alu_busy))&&(op_valid_alu)) //Case 1&2
||(prelock_stall)
||((op_valid)&&(op_break))
||(wr_reg_ce)&&(wr_write_cc)
||(div_busy)||(fpu_busy);
assign alu_ce = (master_ce)&&(op_valid_alu)&&(~alu_stall)
&&(~clear_pipeline);
assign alu_ce = (master_ce)&&(op_valid_alu)&&(!alu_stall)
&&(!clear_pipeline);
`else
assign alu_stall = (op_valid_alu)&&((~master_ce)||(op_break));
assign alu_ce = (master_ce)&&(op_valid_alu)&&(~alu_stall)&&(~clear_pipeline);
assign alu_stall = (op_valid_alu)&&((!master_ce)||(op_break));
assign alu_ce = (master_ce)&&(op_valid_alu)&&(!alu_stall)&&(!clear_pipeline);
`endif
//
 
496,26 → 487,14
// Note: if you change the conditions for mem_ce, you must also change
// alu_pc_valid.
//
`ifdef OPT_PIPELINED
assign mem_ce = (master_ce)&&(op_valid_mem)&&(~mem_stalled)
&&(~clear_pipeline);
`else
// If we aren't pipelined, then no one will be changing what's in the
// pipeline (i.e. clear_pipeline), while our only instruction goes
// through the ... pipeline.
//
// However, in hind sight this logic didn't work. What happens when
// something gets in the pipeline and then (due to interrupt or some
// such) needs to be voided? Thus we avoid simplification and keep
// what worked here.
assign mem_ce = (master_ce)&&(op_valid_mem)&&(~mem_stalled)
&&(~clear_pipeline);
`endif
assign mem_ce = (master_ce)&&(op_valid_mem)&&(!mem_stalled)
&&(!clear_pipeline);
 
`ifdef OPT_PIPELINED_BUS_ACCESS
assign mem_stalled = (~master_ce)||(alu_busy)||((op_valid_mem)&&(
assign mem_stalled = (!master_ce)||(alu_busy)||((op_valid_mem)&&(
(mem_pipe_stalled)
||(prelock_stall)
||((~op_pipe)&&(mem_busy))
||((!op_pipe)&&(mem_busy))
||(div_busy)
||(fpu_busy)
// Stall waiting for flags to be valid
527,7 → 506,7
`else
`ifdef OPT_PIPELINED
assign mem_stalled = (mem_busy)||((op_valid_mem)&&(
(~master_ce)
(!master_ce)
// Stall waiting for flags to be valid
// Or waiting for a write to the PC register
// Or CC register, since that can change the
534,15 → 513,15
// PC as well
||((wr_reg_ce)&&(wr_reg_id[4] == op_gie)&&((wr_write_pc)||(wr_write_cc)))));
`else
assign mem_stalled = (op_valid_mem)&&(~master_ce);
assign mem_stalled = (op_valid_mem)&&(!master_ce);
`endif
`endif
 
// ALU, DIV, or FPU CE ... equivalent to the OR of all three of these
assign adf_ce_unconditional = (master_ce)&&(~clear_pipeline)&&(op_valid)
&&(~op_valid_mem)&&(~mem_rdbusy)
&&((~op_valid_alu)||(~alu_stall))&&(~op_break)
&&(~div_busy)&&(~fpu_busy)&&(~clear_pipeline);
assign adf_ce_unconditional = (master_ce)&&(!clear_pipeline)&&(op_valid)
&&(!op_valid_mem)&&(!mem_rdbusy)
&&((!op_valid_alu)||(!alu_stall))&&(!op_break)
&&(!div_busy)&&(!fpu_busy)&&(!clear_pipeline);
 
//
//
549,38 → 528,46
// PIPELINE STAGE #1 :: Prefetch
//
//
wire pf_stalled;
assign pf_stalled = (dcd_stalled)||(dcd_phase);
 
wire pf_new_pc;
assign pf_new_pc = (new_pc)||((dcd_early_branch)&&(!clear_pipeline));
 
wire [(AW-1):0] pf_request_address;
assign pf_request_address = ((dcd_early_branch)&&(!clear_pipeline))
? dcd_branch_pc:pf_pc[(AW+1):2];
assign pf_gie = gie;
`ifdef OPT_SINGLE_FETCH
wire pf_ce;
 
assign pf_ce = (~pf_valid)&&(~dcd_valid)&&(~op_valid)&&(~alu_busy)&&(~mem_busy)&&(~alu_pc_valid)&&(~mem_pc_valid);
prefetch #(ADDRESS_WIDTH)
pf(i_clk, (i_rst), (pf_ce), (~dcd_stalled), pf_pc[(AW+1):2], gie,
pf_instruction, pf_instruction_pc, pf_gie,
pf(i_clk, (i_rst), pf_new_pc, w_clear_icache,
(!pf_stalled),
pf_request_address,
pf_instruction, pf_instruction_pc,
pf_valid, pf_illegal,
pf_cyc, pf_stb, pf_we, pf_addr, pf_data,
pf_ack, pf_stall, pf_err, i_wb_data);
 
initial r_dcd_valid = 1'b0;
always @(posedge i_clk)
if (clear_pipeline)
r_dcd_valid <= 1'b0;
else if (dcd_ce)
r_dcd_valid <= (pf_valid)||(pf_illegal);
else if (op_ce)
r_dcd_valid <= 1'b0;
assign dcd_valid = r_dcd_valid;
`else
`ifdef OPT_DOUBLE_FETCH
 
`else // Pipe fetch
wire [1:0] pf_dbg;
dblfetch #(ADDRESS_WIDTH)
pf(i_clk, i_rst, pf_new_pc,
w_clear_icache,
(!pf_stalled),
pf_request_address,
pf_instruction, pf_instruction_pc,
pf_valid,
pf_cyc, pf_stb, pf_we, pf_addr, pf_data,
pf_ack, pf_stall, pf_err, i_wb_data,
pf_illegal);
 
wire pf_stalled;
assign pf_stalled = (dcd_stalled)||(dcd_phase);
`else // Not single fetch and not double fetch
 
`ifdef OPT_TRADITIONAL_PFCACHE
wire [(AW-1):0] pf_request_address;
assign pf_request_address = ((dcd_early_branch)&&(!clear_pipeline))
? dcd_branch_pc:pf_pc[(AW+1):2];
pfcache #(LGICACHE, ADDRESS_WIDTH)
pf(i_clk, i_rst, (new_pc)||((dcd_early_branch)&&(~clear_pipeline)),
w_clear_icache,
pf(i_clk, i_rst, pf_new_pc, w_clear_icache,
// dcd_pc,
(!pf_stalled),
pf_request_address,
590,7 → 577,7
pf_illegal);
`else
pipefetch #(RESET_BUS_ADDRESS, LGICACHE, ADDRESS_WIDTH)
pf(i_clk, i_rst, (new_pc)||(dcd_early_branch),
pf(i_clk, i_rst, pf_new_pc,
w_clear_icache, (!pf_stalled),
(new_pc)?pf_pc[(AW+1):2]:dcd_branch_pc,
pf_instruction, pf_instruction_pc, pf_valid,
598,31 → 585,19
pf_ack, pf_stall, pf_err, i_wb_data,
(mem_cyc_lcl)||(mem_cyc_gbl),
pf_illegal);
`endif
`ifdef OPT_NO_USERMODE
assign pf_gie = 1'b0;
`else
assign pf_gie = gie;
`endif
`endif // OPT_TRADITIONAL_CACHE
`endif // OPT_DOUBLE_FETCH
`endif // OPT_SINGLE_FETCH
 
initial r_dcd_valid = 1'b0;
always @(posedge i_clk)
if ((clear_pipeline)||(w_clear_icache))
r_dcd_valid <= 1'b0;
else if (dcd_ce)
r_dcd_valid <= ((dcd_phase)||(pf_valid))
&&(~dcd_ljmp)&&(~dcd_early_branch);
else if (op_ce)
r_dcd_valid <= 1'b0;
assign dcd_valid = r_dcd_valid;
`endif
 
// If not pipelined, there will be no op_valid_ anything, and the
assign dcd_ce = (!dcd_valid)||(!dcd_stalled);
idecode #(AW, IMPLEMENT_MPY, EARLY_BRANCHING, IMPLEMENT_DIVIDE,
IMPLEMENT_FPU)
instruction_decoder(i_clk, (clear_pipeline),
(~dcd_valid)||(~op_stall), dcd_stalled, pf_instruction, pf_gie,
pf_instruction_pc, pf_valid, pf_illegal, dcd_phase,
instruction_decoder(i_clk,
(clear_pipeline)||(w_clear_icache),
dcd_ce,
dcd_stalled, pf_instruction, pf_gie,
pf_instruction_pc, pf_valid, pf_illegal,
dcd_valid, dcd_phase,
dcd_illegal, dcd_pc, dcd_gie,
{ dcd_Rcc, dcd_Rpc, dcd_R },
{ dcd_Acc, dcd_Apc, dcd_A },
729,9 → 704,7
`endif
 
always @(posedge i_clk)
`ifdef OPT_PIPELINED
if (op_ce)
`endif
begin
`ifdef OPT_PIPELINED
if ((wr_reg_ce)&&(wr_reg_id == dcd_A))
746,11 → 719,7
r_op_Av <= w_op_Av;
`ifdef OPT_PIPELINED
end else
begin // We were going to pick these up when they became valid,
// but for some reason we're stuck here as they became
// valid. Pick them up now anyway
// if (((op_A_alu)&&(alu_wR))||((op_A_mem)&&(mem_valid)))
// r_op_Av <= wr_gpreg_vl;
begin
if ((wr_reg_ce)&&(wr_reg_id == op_Aid)&&(op_rA))
r_op_Av <= wr_gpreg_vl;
`endif
798,11 → 767,9
// below, arriving at what we finally want in the (now wire net)
// op_F.
always @(posedge i_clk)
`ifdef OPT_PIPELINED
if (op_ce) // Cannot do op_change_data_ce here since op_F depends
// upon being either correct for a valid op, or correct
// for the last valid op
`endif
begin // Set the flag condition codes, bit order is [3:0]=VNCZ
case(dcd_F[2:0])
3'h0: r_op_F <= 7'h00; // Always
818,7 → 785,7
assign op_F = { r_op_F[3], r_op_F[6:0] };
 
wire w_op_valid;
assign w_op_valid = (~clear_pipeline)&&(dcd_valid)&&(~dcd_ljmp)&&(!dcd_early_branch);
assign w_op_valid = (!clear_pipeline)&&(dcd_valid)&&(!dcd_ljmp)&&(!dcd_early_branch);
initial op_valid = 1'b0;
initial op_valid_alu = 1'b0;
initial op_valid_mem = 1'b0;
845,9 → 812,9
op_valid<= (w_op_valid)||(dcd_illegal)&&(dcd_valid)||(dcd_early_branch);
op_valid_alu <= (w_op_valid)&&((dcd_ALU)||(dcd_illegal)
||(dcd_early_branch));
op_valid_mem <= (dcd_M)&&(~dcd_illegal)&&(w_op_valid);
op_valid_div <= (dcd_DIV)&&(~dcd_illegal)&&(w_op_valid);
op_valid_fpu <= (dcd_FP)&&(~dcd_illegal)&&(w_op_valid);
op_valid_mem <= (dcd_M)&&(!dcd_illegal)&&(w_op_valid);
op_valid_div <= (dcd_DIV)&&(!dcd_illegal)&&(w_op_valid);
op_valid_fpu <= (dcd_FP)&&(!dcd_illegal)&&(w_op_valid);
end else if ((adf_ce_unconditional)||(mem_ce))
begin
op_valid <= 1'b0;
866,7 → 833,6
// to be, step through it, and then replace it back. In this fashion,
// a debugger can step through code.
// assign w_op_break = (dcd_break)&&(r_dcd_I[15:0] == 16'h0001);
`ifdef OPT_PIPELINED
reg r_op_break;
 
initial r_op_break = 1'b0;
877,9 → 843,6
else if (!op_valid)
r_op_break <= 1'b0;
assign op_break = r_op_break;
`else
assign op_break = dcd_break;
`endif
 
`ifdef OPT_PIPELINED
generate
892,7 → 855,7
if (clear_pipeline)
r_op_lock <= 1'b0;
else if (op_ce)
r_op_lock <= (dcd_valid)&&(dcd_lock)&&(~clear_pipeline);
r_op_lock <= (dcd_valid)&&(dcd_lock)&&(!clear_pipeline);
assign op_lock = r_op_lock;
 
end else begin
925,21 → 888,27
always @(posedge i_clk)
if (op_ce)
begin
op_wF <= (dcd_wF)&&((~dcd_Rcc)||(~dcd_wR))
&&(~dcd_early_branch)&&(~dcd_illegal);
op_wR <= (dcd_wR)&&(~dcd_early_branch)&&(~dcd_illegal);
op_wF <= (dcd_wF)&&((!dcd_Rcc)||(!dcd_wR))
&&(!dcd_early_branch)&&(!dcd_illegal);
op_wR <= (dcd_wR)&&(!dcd_early_branch)&&(!dcd_illegal);
end
`else
always @(posedge i_clk)
begin
op_wF <= (dcd_wF)&&((~dcd_Rcc)||(~dcd_wR))
&&(~dcd_early_branch)&&(~dcd_illegal);
op_wR <= (dcd_wR)&&(~dcd_early_branch)&&(~dcd_illegal);
op_wF <= (dcd_wF)&&((!dcd_Rcc)||(!dcd_wR))
&&(!dcd_early_branch)&&(!dcd_illegal);
op_wR <= (dcd_wR)&&(!dcd_early_branch)&&(!dcd_illegal);
end
`endif
 
`ifdef VERILATOR
`ifdef OPT_PIPELINED
`ifdef SINGLE_FETCH
always @(*)
begin
op_sim = dcd_sim;
op_sim_immv = dcd_sim_immv;
end
`else
always @(posedge i_clk)
if (op_change_data_ce)
begin
946,20 → 915,15
op_sim <= dcd_sim;
op_sim_immv <= dcd_sim_immv;
end
`else
always @(*)
begin
op_sim = dcd_sim;
op_sim_immv = dcd_sim_immv;
end
`endif
`endif
 
`ifdef OPT_PIPELINED
reg [3:0] r_op_opn;
reg [4:0] r_op_R;
reg r_op_Rcc;
reg r_op_gie;
 
initial r_op_gie = 1'b0;
always @(posedge i_clk)
if (op_change_data_ce)
begin
978,24 → 942,9
end
assign op_opn = r_op_opn;
assign op_R = r_op_R;
`ifdef OPT_NO_USERMODE
assign op_gie = 1'b0;
`else
assign op_gie = r_op_gie;
`endif
assign op_Rcc = r_op_Rcc;
`else
assign op_opn = dcd_opn;
assign op_R = dcd_R;
`ifdef OPT_NO_USERMODE
assign op_gie = 1'b0;
`else
assign op_gie = dcd_gie;
`endif
// With no pipelining, there is no early branching. We keep it
always @(posedge i_clk)
op_pc <= (dcd_early_branch)?dcd_branch_pc:dcd_pc[AW:1];
`endif
 
assign op_Fl = (op_gie)?(w_uflags):(w_iflags);
 
`ifdef OPT_CIS
1087,9 → 1036,9
// decode circuit has told us that the hazard
// is clear, so we're okay then.
//
((~dcd_zI)&&(
((!dcd_zI)&&(
((op_R == dcd_B)&&(op_wR))
||((mem_rdbusy)&&(~dcd_pipe))
||((mem_rdbusy)&&(!dcd_pipe))
))
// Stall following any instruction that will
// set the flags, if we're going to need the
1097,10 → 1046,10
||(((op_wF)||(cc_invalid_for_dcd))&&(dcd_Bcc))
// Stall on any ongoing memory operation that
// will write to op_B -- captured above
// ||((mem_busy)&&(~mem_we)&&(mem_last_reg==dcd_B)&&(~dcd_zI))
// ||((mem_busy)&&(!mem_we)&&(mem_last_reg==dcd_B)&&(!dcd_zI))
)
||((dcd_rB)&&(dcd_Bcc)&&(cc_invalid_for_dcd));
assign dcd_F_stall = ((~dcd_F[3])
assign dcd_F_stall = ((!dcd_F[3])
||((dcd_rA)&&(dcd_Acc))
||((dcd_rB)&&(dcd_Bcc)))
&&(op_valid)&&(op_Rcc);
1169,7 → 1118,7
// alu_reg <= op_R;
alu_wR <= (op_wR)&&(set_cond);
alu_wF <= (op_wF)&&(set_cond);
end else if (~alu_busy) begin
end else if (!alu_busy) begin
// These are strobe signals, so clear them if not
// set for any particular clock
alu_wR <= (i_halt)&&(i_dbg_we);
1209,7 → 1158,7
reg dbgv;
initial dbgv = 1'b0;
always @(posedge i_clk)
dbgv <= (~i_rst)&&(i_halt)&&(i_dbg_we)&&(r_halted);
dbgv <= (!i_rst)&&(i_halt)&&(i_dbg_we)&&(r_halted);
reg [31:0] dbg_val;
always @(posedge i_clk)
dbg_val <= i_dbg_data;
1232,8 → 1181,8
reg [(AW-1):0] r_alu_pc;
always @(posedge i_clk)
if ((adf_ce_unconditional)
||((master_ce)&&(op_valid_mem)&&(~clear_pipeline)
&&(~mem_stalled)))
||((master_ce)&&(op_valid_mem)&&(!clear_pipeline)
&&(!mem_stalled)))
r_alu_pc <= op_pc;
assign alu_pc = r_alu_pc;
`else
1256,11 → 1205,11
always @(posedge i_clk)
if (clear_pipeline)
r_alu_pc_valid <= 1'b0;
else if ((adf_ce_unconditional)&&(!op_phase)) //Includes&&(~alu_clear_pipeline)
else if ((adf_ce_unconditional)&&(!op_phase))
r_alu_pc_valid <= 1'b1;
else if (((~alu_busy)&&(~div_busy)&&(~fpu_busy))||(clear_pipeline))
else if (((!alu_busy)&&(!div_busy)&&(!fpu_busy))||(clear_pipeline))
r_alu_pc_valid <= 1'b0;
assign alu_pc_valid = (r_alu_pc_valid)&&((~alu_busy)&&(~div_busy)&&(~fpu_busy));
assign alu_pc_valid = (r_alu_pc_valid)&&((!alu_busy)&&(!div_busy)&&(!fpu_busy));
always @(posedge i_clk)
if (i_rst)
mem_pc_valid <= 1'b0;
1326,7 → 1275,8
mem_ack, mem_stall, mem_err, i_wb_data);
 
`else // PIPELINED_BUS_ACCESS
memops #(AW,IMPLEMENT_LOCK,WITH_LOCAL_BUS) domem(i_clk, i_rst,(mem_ce)&&(set_cond), bus_lock,
memops #(AW,IMPLEMENT_LOCK,WITH_LOCAL_BUS) domem(i_clk, i_rst,
(mem_ce)&&(set_cond), bus_lock,
(op_opn[2:0]), op_Bv, op_Av, op_R,
mem_busy,
mem_valid, bus_err, mem_wreg, mem_result,
1336,7 → 1286,7
mem_ack, mem_stall, mem_err, i_wb_data);
assign mem_pipe_stalled = 1'b0;
`endif // PIPELINED_BUS_ACCESS
assign mem_rdbusy = ((mem_busy)&&(~mem_we));
assign mem_rdbusy = ((mem_busy)&&(!mem_we));
 
// Either the prefetch or the instruction gets the memory bus, but
// never both.
1389,7 → 1339,7
// Further, alu_wR includes (set_cond), so we don't need to
// check for that here either.
assign wr_reg_ce = (dbgv)||(mem_valid)
||((~clear_pipeline)&&(~alu_illegal)
||((!clear_pipeline)&&(!alu_illegal)
&&(((alu_wR)&&(alu_valid))
||(div_valid)||(fpu_valid)));
// Which register shall be written?
1431,7 → 1381,7
// Write back to the condition codes/flags register ...
// When shall we write to our flags register? alu_wF already
// includes the set condition ...
assign wr_flags_ce = ((alu_wF)||(div_valid)||(fpu_valid))&&(~clear_pipeline)&&(~alu_illegal);
assign wr_flags_ce = ((alu_wF)||(div_valid)||(fpu_valid))&&(!clear_pipeline)&&(!alu_illegal);
assign w_uflags = { 1'b0, uhalt_phase, ufpu_err_flag,
udiv_err_flag, ubus_err_flag, trap, ill_err_u,
ubreak, step, 1'b1, sleep,
1439,7 → 1389,7
assign w_iflags = { 1'b0, ihalt_phase, ifpu_err_flag,
idiv_err_flag, ibus_err_flag, trap, ill_err_i,
break_en, 1'b0, 1'b0, sleep,
((wr_flags_ce)&&(~alu_gie))?alu_flags:iflags };
((wr_flags_ce)&&(!alu_gie))?alu_flags:iflags };
 
 
// What value to write?
1455,7 → 1405,7
always @(posedge i_clk)
if ((wr_reg_ce)&&(wr_write_scc))
iflags <= wr_gpreg_vl[3:0];
else if ((wr_flags_ce)&&(~alu_gie))
else if ((wr_flags_ce)&&(!alu_gie))
iflags <= (div_valid)?div_flags:((fpu_valid)?fpu_flags
: alu_flags);
 
1486,10 → 1436,10
 
initial r_break_pending = 1'b0;
always @(posedge i_clk)
if ((clear_pipeline)||(~op_valid))
if ((clear_pipeline)||(!op_valid))
r_break_pending <= 1'b0;
else if (op_break)
r_break_pending <= (~alu_busy)&&(~div_busy)&&(~fpu_busy)&&(~mem_busy)&&(!wr_reg_ce);
r_break_pending <= (!alu_busy)&&(!div_busy)&&(!fpu_busy)&&(!mem_busy)&&(!wr_reg_ce);
else
r_break_pending <= 1'b0;
assign break_pending = r_break_pending;
1498,12 → 1448,12
`endif
 
 
assign o_break = ((break_en)||(~op_gie))&&(break_pending)
&&(~clear_pipeline)
||((~alu_gie)&&(bus_err))
||((~alu_gie)&&(div_error))
||((~alu_gie)&&(fpu_error))
||((~alu_gie)&&(alu_illegal)&&(!clear_pipeline));
assign o_break = ((break_en)||(!op_gie))&&(break_pending)
&&(!clear_pipeline)
||((!alu_gie)&&(bus_err))
||((!alu_gie)&&(div_error))
||((!alu_gie)&&(fpu_error))
||((!alu_gie)&&(alu_illegal)&&(!clear_pipeline));
 
// The sleep register. Setting the sleep register causes the CPU to
// sleep until the next interrupt. Setting the sleep register within
1520,7 → 1470,7
r_sleep_is_halt <= 1'b0;
else if ((wr_reg_ce)&&(wr_write_cc)
&&(wr_spreg_vl[`CPU_SLEEP_BIT])
&&(~wr_spreg_vl[`CPU_GIE_BIT]))
&&(!wr_spreg_vl[`CPU_GIE_BIT]))
r_sleep_is_halt <= 1'b1;
 
// Trying to switch to user mode, either via a WAIT or an RTU
1536,7 → 1486,7
always @(posedge i_clk)
if ((i_rst)||(w_switch_to_interrupt))
sleep <= 1'b0;
else if ((wr_reg_ce)&&(wr_write_cc)&&(~alu_gie))
else if ((wr_reg_ce)&&(wr_write_cc)&&(!alu_gie))
// In supervisor mode, we have no protections. The
// supervisor can set the sleep bit however he wants.
// Well ... not quite. Switching to user mode and
1546,7 → 1496,7
// don't set the sleep bit
// otherwise however it would o.w. be set
sleep <= (wr_spreg_vl[`CPU_SLEEP_BIT])
&&((~i_interrupt)||(~wr_spreg_vl[`CPU_GIE_BIT]));
&&((!i_interrupt)||(!wr_spreg_vl[`CPU_GIE_BIT]));
else if ((wr_reg_ce)&&(wr_write_cc)&&(wr_spreg_vl[`CPU_GIE_BIT]))
// In user mode, however, you can only set the sleep
// mode while remaining in user mode. You can't switch
1558,7 → 1508,7
always @(posedge i_clk)
if (i_rst)
step <= 1'b0;
else if ((wr_reg_ce)&&(~alu_gie)&&(wr_write_ucc))
else if ((wr_reg_ce)&&(!alu_gie)&&(wr_write_ucc))
step <= wr_spreg_vl[`CPU_STEP_BIT];
 
// The GIE register. Only interrupts can disable the interrupt register
1568,12 → 1518,12
`else
assign w_switch_to_interrupt = (gie)&&(
// On interrupt (obviously)
((i_interrupt)&&(~alu_phase)&&(~bus_lock))
((i_interrupt)&&(!alu_phase)&&(!bus_lock))
// If we are stepping the CPU
||(((alu_pc_valid)||(mem_pc_valid))&&(step)&&(~alu_phase)&&(~bus_lock))
||(((alu_pc_valid)||(mem_pc_valid))&&(step)&&(!alu_phase)&&(!bus_lock))
// If we encounter a break instruction, if the break
// enable isn't set.
||((master_ce)&&(break_pending)&&(~break_en))
||((master_ce)&&(break_pending)&&(!break_en))
// On an illegal instruction
||((alu_illegal)&&(!clear_pipeline))
// On division by zero. If the divide isn't
1587,10 → 1537,10
//
||(bus_err)
// If we write to the CC register
||((wr_reg_ce)&&(~wr_spreg_vl[`CPU_GIE_BIT])
||((wr_reg_ce)&&(!wr_spreg_vl[`CPU_GIE_BIT])
&&(wr_reg_id[4])&&(wr_write_cc))
);
assign w_release_from_interrupt = (~gie)&&(~i_interrupt)
assign w_release_from_interrupt = (!gie)&&(!i_interrupt)
// Then if we write the sCC register
&&(((wr_reg_ce)&&(wr_spreg_vl[`CPU_GIE_BIT])
&&(wr_write_scc))
1623,10 → 1573,10
always @(posedge i_clk)
if ((i_rst)||(w_release_from_interrupt))
r_trap <= 1'b0;
else if ((alu_gie)&&(wr_reg_ce)&&(~wr_spreg_vl[`CPU_GIE_BIT])
else if ((alu_gie)&&(wr_reg_ce)&&(!wr_spreg_vl[`CPU_GIE_BIT])
&&(wr_write_ucc)) // &&(wr_reg_id[4]) implied
r_trap <= 1'b1;
else if ((wr_reg_ce)&&(wr_write_ucc)&&(~alu_gie))
else if ((wr_reg_ce)&&(wr_write_ucc)&&(!alu_gie))
r_trap <= (r_trap)&&(wr_spreg_vl[`CPU_TRAP_BIT]);
 
reg r_ubreak;
1637,7 → 1587,7
r_ubreak <= 1'b0;
else if ((op_gie)&&(break_pending)&&(w_switch_to_interrupt))
r_ubreak <= 1'b1;
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce)&&(wr_write_ucc))
else if (((!alu_gie)||(dbgv))&&(wr_reg_ce)&&(wr_write_ucc))
r_ubreak <= (ubreak)&&(wr_spreg_vl[`CPU_BREAK_BIT]);
 
assign trap = r_trap;
1653,7 → 1603,7
// Only the debug interface can clear this bit
else if ((dbgv)&&(wr_write_scc))
ill_err_i <= (ill_err_i)&&(wr_spreg_vl[`CPU_ILL_BIT]);
else if ((alu_illegal)&&(~alu_gie)&&(!clear_pipeline))
else if ((alu_illegal)&&(!alu_gie)&&(!clear_pipeline))
ill_err_i <= 1'b1;
 
`ifdef OPT_NO_USERMODE
1669,7 → 1619,7
r_ill_err_u <= 1'b0;
// If the supervisor (or debugger) writes to this register,
// clearing the bit, then clear it
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce)&&(wr_write_ucc))
else if (((!alu_gie)||(dbgv))&&(wr_reg_ce)&&(wr_write_ucc))
r_ill_err_u <=((ill_err_u)&&(wr_spreg_vl[`CPU_ILL_BIT]));
else if ((alu_illegal)&&(alu_gie)&&(!clear_pipeline))
r_ill_err_u <= 1'b1;
1688,7 → 1638,7
ibus_err_flag <= 1'b0;
else if ((dbgv)&&(wr_write_scc))
ibus_err_flag <= (ibus_err_flag)&&(wr_spreg_vl[`CPU_BUSERR_BIT]);
else if ((bus_err)&&(~alu_gie))
else if ((bus_err)&&(!alu_gie))
ibus_err_flag <= 1'b1;
// User bus error flag -- if ever set, it will cause an interrupt to
// supervisor mode.
1701,7 → 1651,7
always @(posedge i_clk)
if ((i_rst)||(w_release_from_interrupt))
r_ubus_err_flag <= 1'b0;
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce)&&(wr_write_ucc))
else if (((!alu_gie)||(dbgv))&&(wr_reg_ce)&&(wr_write_ucc))
r_ubus_err_flag <= (ubus_err_flag)&&(wr_spreg_vl[`CPU_BUSERR_BIT]);
else if ((bus_err)&&(alu_gie))
r_ubus_err_flag <= 1'b1;
1723,7 → 1673,7
r_idiv_err_flag <= 1'b0;
else if ((dbgv)&&(wr_write_scc))
r_idiv_err_flag <= (r_idiv_err_flag)&&(wr_spreg_vl[`CPU_DIVERR_BIT]);
else if ((div_error)&&(~alu_gie))
else if ((div_error)&&(!alu_gie))
r_idiv_err_flag <= 1'b1;
 
assign idiv_err_flag = r_idiv_err_flag;
1736,7 → 1686,7
always @(posedge i_clk)
if ((i_rst)||(w_release_from_interrupt))
r_udiv_err_flag <= 1'b0;
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce)
else if (((!alu_gie)||(dbgv))&&(wr_reg_ce)
&&(wr_write_ucc))
r_udiv_err_flag <= (r_udiv_err_flag)&&(wr_spreg_vl[`CPU_DIVERR_BIT]);
else if ((div_error)&&(alu_gie))
1761,7 → 1711,7
r_ifpu_err_flag <= 1'b0;
else if ((dbgv)&&(wr_write_scc))
r_ifpu_err_flag <= (r_ifpu_err_flag)&&(wr_spreg_vl[`CPU_FPUERR_BIT]);
else if ((fpu_error)&&(fpu_valid)&&(~alu_gie))
else if ((fpu_error)&&(fpu_valid)&&(!alu_gie))
r_ifpu_err_flag <= 1'b1;
// User floating point error flag -- if ever set, it will cause
// a sudden switch interrupt to supervisor mode.
1769,7 → 1719,7
always @(posedge i_clk)
if ((i_rst)&&(w_release_from_interrupt))
r_ufpu_err_flag <= 1'b0;
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce)
else if (((!alu_gie)||(dbgv))&&(wr_reg_ce)
&&(wr_write_ucc))
r_ufpu_err_flag <= (r_ufpu_err_flag)&&(wr_spreg_vl[`CPU_FPUERR_BIT]);
else if ((fpu_error)&&(alu_gie)&&(fpu_valid))
1789,7 → 1739,7
always @(posedge i_clk)
if (i_rst)
r_ihalt_phase <= 1'b0;
else if ((~alu_gie)&&(alu_pc_valid)&&(~clear_pipeline))
else if ((!alu_gie)&&(alu_pc_valid)&&(!clear_pipeline))
r_ihalt_phase <= alu_phase;
 
assign ihalt_phase = r_ihalt_phase;
1805,7 → 1755,7
r_uhalt_phase <= 1'b0;
else if ((alu_gie)&&(alu_pc_valid))
r_uhalt_phase <= alu_phase;
else if ((~alu_gie)&&(wr_reg_ce)&&(wr_write_ucc))
else if ((!alu_gie)&&(wr_reg_ce)&&(wr_write_ucc))
r_uhalt_phase <= wr_spreg_vl[`CPU_PHASE_BIT];
 
assign uhalt_phase = r_uhalt_phase;
1822,7 → 1772,7
// the instruction writes the PC, we write whichever PC is appropriate.
//
// Do we need to all our partial results from the pipeline?
// What happens when the pipeline has gie and ~gie instructions within
// What happens when the pipeline has gie and !gie instructions within
// it? Do we clear both? What if a gie instruction tries to clear
// a non-gie instruction?
`ifdef OPT_NO_USERMODE
1834,7 → 1784,7
if ((wr_reg_ce)&&(wr_reg_id[4])&&(wr_write_pc))
r_upc <= { wr_spreg_vl[(AW+1):2], 2'b00 };
else if ((alu_gie)&&
(((alu_pc_valid)&&(~clear_pipeline)&&(!alu_illegal))
(((alu_pc_valid)&&(!clear_pipeline)&&(!alu_illegal))
||(mem_pc_valid)))
r_upc <= { alu_pc, 2'b00 };
assign upc = r_upc;
1843,10 → 1793,10
always @(posedge i_clk)
if (i_rst)
ipc <= { RESET_BUS_ADDRESS, 2'b00 };
else if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_pc))
else if ((wr_reg_ce)&&(!wr_reg_id[4])&&(wr_write_pc))
ipc <= { wr_spreg_vl[(AW+1):2], 2'b00 };
else if ((!alu_gie)&&(!alu_phase)&&
(((alu_pc_valid)&&(~clear_pipeline)&&(!alu_illegal))
(((alu_pc_valid)&&(!clear_pipeline)&&(!alu_illegal))
||(mem_pc_valid)))
ipc <= { alu_pc, 2'b00 };
 
1853,25 → 1803,20
always @(posedge i_clk)
if (i_rst)
pf_pc <= { RESET_BUS_ADDRESS, 2'b00 };
else if ((w_switch_to_interrupt)||((~gie)&&(w_clear_icache)))
else if ((w_switch_to_interrupt)||((!gie)&&(w_clear_icache)))
pf_pc <= { ipc[(AW+1):2], 2'b00 };
else if ((w_release_from_interrupt)||((gie)&&(w_clear_icache)))
pf_pc <= { upc[(AW+1):2], 2'b00 };
else if ((wr_reg_ce)&&(wr_reg_id[4] == gie)&&(wr_write_pc))
pf_pc <= { wr_spreg_vl[(AW+1):2], 2'b00 };
`ifdef OPT_PIPELINED
else if ((dcd_early_branch)&&(~clear_pipeline))
else if ((dcd_early_branch)&&(!clear_pipeline))
pf_pc <= { dcd_branch_pc + 1'b1, 2'b00 };
else if ((new_pc)||((!pf_stalled)&&(pf_valid)))
pf_pc <= { pf_pc[(AW+1):2] + {{(AW-1){1'b0}},1'b1}, 2'b00 };
`else
else if ((alu_gie==gie)&&(
((alu_pc_valid)&&(~clear_pipeline))
||(mem_pc_valid)))
pf_pc <= { alu_pc[(AW-1):0], 2'b00 };
`endif
 
`ifdef OPT_PIPELINED
// If we aren't pipelined, or equivalently if we have no cache, these
// instructions will get quietly (or not so quietly) ignored by the
// optimizer.
reg r_clear_icache;
initial r_clear_icache = 1'b1;
always @(posedge i_clk)
1882,9 → 1827,6
else
r_clear_icache <= 1'b0;
assign w_clear_icache = r_clear_icache;
`else
assign w_clear_icache = i_clear_pf_cache;
`endif
 
initial new_pc = 1'b1;
always @(posedge i_clk)
1949,8 → 1891,8
r_halted <= (i_halt)&&(
// To be halted, any long lasting instruction must
// be completed.
(~pf_cyc)&&(~mem_busy)&&(~alu_busy)
&&(~div_busy)&&(~fpu_busy)
(!pf_cyc)&&(!mem_busy)&&(!alu_busy)
&&(!div_busy)&&(!fpu_busy)
// Operations must either be valid, or illegal
&&((op_valid)||(i_rst)||(dcd_illegal))
// Decode stage must be either valid, in reset, or ill
1959,7 → 1901,7
always @(posedge i_clk)
r_halted <= (i_halt)&&((op_valid)||(i_rst));
`endif
assign o_dbg_stall = ~r_halted;
assign o_dbg_stall = !r_halted;
 
//
//
1968,55 → 1910,19
//
//
assign o_op_stall = (master_ce)&&(op_stall);
assign o_pf_stall = (master_ce)&&(~pf_valid);
assign o_i_count = (alu_pc_valid)&&(~clear_pipeline);
assign o_pf_stall = (master_ce)&&(!pf_valid);
assign o_i_count = (alu_pc_valid)&&(!clear_pipeline);
 
`ifdef DEBUG_SCOPE
always @(posedge i_clk)
o_debug <= {
/*
o_break, i_wb_err, pf_pc[1:0],
flags,
pf_valid, dcd_valid, op_valid, alu_valid, mem_valid,
op_ce, alu_ce, mem_ce,
//
master_ce, op_valid_alu, op_valid_mem,
//
alu_stall, mem_busy, op_pipe, mem_pipe_stalled,
mem_we,
// ((op_valid_alu)&&(alu_stall))
// ||((op_valid_mem)&&(~op_pipe)&&(mem_busy))
// ||((op_valid_mem)&&( op_pipe)&&(mem_pipe_stalled)));
// op_Av[23:20], op_Av[3:0],
gie, sleep, wr_reg_ce, wr_gpreg_vl[4:0]
*/
/*
i_rst, master_ce, (new_pc),
((dcd_early_branch)&&(dcd_valid)),
pf_valid, pf_illegal,
op_ce, dcd_ce, dcd_valid, dcd_stalled,
pf_cyc, pf_stb, pf_we, pf_ack, pf_stall, pf_err,
pf_pc[7:0], pf_addr[7:0]
*/
 
i_wb_err, gie, alu_illegal,
(new_pc)||((dcd_early_branch)&&(~clear_pipeline)),
mem_busy,
(mem_busy)?{ (o_wb_gbl_stb|o_wb_lcl_stb), o_wb_we,
o_wb_addr[8:0] }
: { pf_instruction[31:21] },
pf_valid, (pf_valid) ? alu_pc[14:0]
:{ pf_cyc, pf_stb, pf_pc[14:2] }
 
/*
i_wb_err, gie, new_pc, dcd_early_branch, // 4
pf_valid, pf_cyc, pf_stb, pf_instruction_pc[0], // 4
pf_instruction[30:27], // 4
dcd_gie, mem_busy, o_wb_gbl_cyc, o_wb_gbl_stb, // 4
dcd_valid,
((dcd_early_branch)&&(~clear_pipeline)) // 15
? dcd_branch_pc[14:0]:pf_pc[14:0]
*/
wr_reg_ce, pf_valid, new_pc,
(wr_reg_ce)?
{ wr_reg_id, wr_gpreg_vl[23:0] }
:{ op_stall,
o_wb_gbl_cyc, o_wb_gbl_stb, o_wb_we,
mem_busy,
dcd_valid, op_ce, pf_pc[21:0] }
};
`endif
 
/rtl/qflashxpress.v
0,0 → 1,251
////////////////////////////////////////////////////////////////////////////////
//
// Filename: qflashxpress.v
//
// Project: CMod S6 System on a Chip, ZipCPU demonstration project
//
// Purpose: To provide wishbone controlled read access (and read access
// *only*) to the QSPI flash, using a flash clock of 80MHz, and
// nothing more. Indeed, this is designed to be a *very* stripped down
// version of a flash driver, with the goal of providing 1) very fast
// access for 2) very low logic count.
//
// Two modes/states of operation:
//
// STARTUP
// 1. Waits for the flash to come on line
// Start out idle for 300 uS
// 2. Sends a signal to remove the flash from any QSPI read mode. In our
// case, we'll send several clocks of an empty command. In SPI
// mode, it'll get ignored. In QSPI mode, it'll remove us from
// QSPI mode.
// 3. Explicitly places and leaves the flash into QSPI mode
// 0xEB 3(0xa0) 0xa0 0xa0 0xa0 4(0x00)
// 4. All done
//
// NORMAL-OPS
// ODATA <- ?, 3xADDR, 0xa0, 0x00, 0x00 | 0x00, 0x00, 0x00, 0x00 ? (22nibs)
// STALL <- TRUE until closed at the end
// MODE <- 2'b10 for 4 clks, then 2'b11
// CLK <- 2'b10 before starting, then 2'b01 until the end
// CSN <- 0 any time CLK != 2'b11
//
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory. Run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`define OPT_FLASH_PIPELINE
module qflashxpress(i_clk,
i_wb_cyc, i_wb_stb, i_wb_addr,
o_wb_ack, o_wb_stall, o_wb_data,
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat);
localparam AW=24-2;
input i_clk;
//
input i_wb_cyc, i_wb_stb;
input [(AW-1):0] i_wb_addr;
//
output reg o_wb_ack, o_wb_stall;
output reg [31:0] o_wb_data;
//
output wire [1:0] o_qspi_sck;
output wire o_qspi_cs_n;
output wire [1:0] o_qspi_mod;
output wire [3:0] o_qspi_dat;
input wire [3:0] i_qspi_dat;
 
//
//
// Maintenance / startup portion
//
//
reg maintenance;
reg [14:0] m_counter;
reg [1:0] m_state;
reg [1:0] m_mod;
reg m_cs_n;
reg [1:0] m_clk;
reg [31:0] m_data;
wire [3:0] m_dat;
 
initial maintenance = 1'b1;
initial m_counter = 0;
initial m_state = 2'b00;
always @(posedge i_clk)
begin
if (maintenance)
m_counter <= m_counter + 1'b1;
m_mod <= 2'b00; // SPI mode always for maintenance
case(m_state)
2'b00: begin
// Step one: wait for the flash device to initialize.
// Perhaps this is more for form than anything else,
// especially if we just loaded our configuration from
// the flash, but in case we did not--we do this anyway.
maintenance <= 1'b1;
if (m_counter[14:0]==15'h7fff) // 24000 is the limit
m_state <= 2'b01;
m_cs_n <= 1'b1;
m_clk <= 2'b11;
end
2'b01: begin
// Now that the flash has had a chance to start up, feed
// it with chip selects with no clocks. This is
// guaranteed to remove us from any XIP mode we might
// be in upon startup. We do this so that we might be
// placed into a known mode--albeit the wrong one, but
// a known one.
maintenance <= 1'b1;
//
// 1111 0000 1111 0000 1111 0000 1111 0000
// 1111 0000 1111 0000 1111 0000 1111 0000
// 1111 ==> 17 * 4 clocks, or 68 clocks in total
//
if (m_counter[14:0] == 15'd138)
m_state <= 2'b10;
m_cs_n <= 1'b0;
m_clk <= {(2){!m_counter[2]}};
m_data <= { 32'hfff0f0ff }; // EB command
m_data[31:28] <= 0; // just ... not yet
end
2'b10: begin
// Rest, before issuing our initial read command
maintenance <= 1'b1;
if (m_counter[14:0] == 15'd138 + 15'd48)
m_state <= 2'b11;
m_cs_n <= 1'b1; // Rest the interface
m_clk <= 2'b11;
m_data <= { 32'hfff0f0ff }; // EB command
end
2'b11: begin
if (m_counter[14:0] == 15'd138+15'd48+15'd10)
maintenance <= 1'b0;
m_cs_n <= 1'b0;
m_clk <= (m_clk == 2'b11)? 2'b10 : 2'b01;
if (m_clk == 2'b01) // EB QuadIO Read Cmd
m_data <= {m_data[27:0], 4'h0};
// We depend upon the non-maintenance code to provide
// our first (bogus) address, mode, dummy cycles, and
// data bits.
end
endcase
end
assign m_dat = m_data[31:28];
 
//
//
// Data / access portion
//
//
reg [21:0] busy_pipe;
reg [31:0] data_pipe;
reg pre_ack;
initial data_pipe = 0;
always @(posedge i_clk)
if (((i_wb_stb)&&(!o_wb_stall))||(maintenance))
data_pipe <= { i_wb_addr, 2'b00, 8'ha0 };
else if (o_qspi_sck == 2'b01)
data_pipe <= { data_pipe[27:0], 4'h0 };
assign o_qspi_dat = (maintenance)? m_dat : data_pipe[31:28];
 
`ifdef OPT_FLASH_PIPELINE
reg pipe_req;
 
reg [(AW-1):0] last_addr;
always @(posedge i_clk)
if ((i_wb_stb)&&(!o_wb_stall))
last_addr <= i_wb_addr;
 
initial pipe_req = 1'b0;
always @(posedge i_clk)
pipe_req <= (pre_ack)&&(i_wb_stb)
&&(last_addr + 1'b1 == i_wb_addr);
`else
wire pipe_req;
assign pipe_req = 1'b0;
`endif
 
 
initial pre_ack = 0;
always @(posedge i_clk)
if ((maintenance)||(!i_wb_cyc))
pre_ack <= 1'b0;
else if ((i_wb_stb)&&(!o_wb_stall))
pre_ack <= 1'b1;
else if ((o_wb_ack)&&(!pipe_req))
pre_ack <= 1'b0;
 
reg [43:0] clk_pipe;
initial clk_pipe = -1;
always @(posedge i_clk)
if (((i_wb_stb)&&(!o_wb_stall)&&(!pipe_req))||(maintenance))
clk_pipe <= { 2'b00, {(21){2'b01}}};
else if (((i_wb_stb)&&(!o_wb_stall))||(maintenance))
clk_pipe <= { {(8){2'b01}}, {(14){2'b11}} };
else
clk_pipe <= { clk_pipe[41:0], 2'b11 };
assign o_qspi_sck = (maintenance)? m_clk : clk_pipe[43:42];
assign o_qspi_cs_n= (maintenance)?m_cs_n : (clk_pipe[43:42] == 2'b11);
 
reg [9:0] mod_pipe;
always @(posedge i_clk)
if(((i_wb_stb)&&(!o_wb_stall)&&(!pipe_req))||(maintenance))
mod_pipe <= { 10'h0 }; // Always quad, but in/out
else
mod_pipe <= { mod_pipe[8:0], 1'b1 }; // Add input at end
assign o_qspi_mod = (maintenance) ? m_mod :(mod_pipe[9]? 2'b11:2'b10);
 
initial busy_pipe = 22'h3fffff;
always @(posedge i_clk)
if (((i_wb_stb)&&(!o_wb_stall)&&(!pipe_req))||(maintenance))
busy_pipe <= { 22'h3fffff };
else if ((i_wb_stb)&&(!o_wb_stall))
busy_pipe <= { 22'h3fc000 };
else
busy_pipe <= { busy_pipe[20:0], 1'b0 };
 
initial o_wb_stall = 1'b1;
always @(posedge i_clk)
o_wb_stall <= ((i_wb_stb)&&(!o_wb_stall))
||(busy_pipe[19])||((busy_pipe[20])&&(!pipe_req));
 
reg ack_pipe;
initial ack_pipe = 1'b0;
always @(posedge i_clk)
ack_pipe <= (pre_ack)&&(busy_pipe[20:19] == 2'b10);
initial o_wb_ack = 1'b0;
always @(posedge i_clk)
o_wb_ack <= (pre_ack)&&(ack_pipe);
 
always @(posedge i_clk)
o_wb_data <= { o_wb_data[27:0], i_qspi_dat };
 
endmodule
 
/rtl/rxuartlite.v
0,0 → 1,197
////////////////////////////////////////////////////////////////////////////////
//
// Filename: rxuartlite.v
//
// Project: wbuart32, a full featured UART with simulator
//
// Purpose: Receive and decode inputs from a single UART line.
//
//
// To interface with this module, connect it to your system clock,
// and a UART input. Set the parameter to the number of clocks per
// baud. When data becomes available, the o_wr line will be asserted
// for one clock cycle.
//
// This interface only handles 8N1 serial port communications. It does
// not handle the break, parity, or frame error conditions.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory. Run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`define 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 // Unused in RXUARTLITE
`define RXU_STOP 4'h8
// `define RXU_SECOND_STOP 4'ha // Unused in RXUARTLITE
// Unused 4'hb
// Unused 4'hc
// `define RXU_BREAK 4'hd // Unused in RXUARTLITE
// `define RXU_RESET_IDLE 4'he // Unused in RXUARTLITE
`define RXU_IDLE 4'hf
 
module rxuartlite(i_clk, i_uart_rx, o_wr, o_data);
parameter [23:0] CLOCKS_PER_BAUD = 24'd868;
input i_clk;
input i_uart_rx;
output reg o_wr;
output reg [7:0] o_data;
 
 
wire [23:0] clocks_per_baud, half_baud;
reg [3:0] state;
 
assign half_baud = { 1'b0, CLOCKS_PER_BAUD[23:1] } - 24'h1;
reg [23:0] baud_counter;
reg zero_baud_counter;
 
 
// Since this is an asynchronous receiver, we need to register our
// input a couple of clocks over to avoid any problems with
// metastability. We do that here, and then ignore all but the
// ck_uart wire.
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_rx;
qq_uart <= q_uart;
ck_uart <= qq_uart;
end
 
// Keep track of the number of clocks since the last change.
//
// This is used to determine if we are in either a break or an idle
// condition, as discussed further below.
reg [23:0] chg_counter;
initial chg_counter = 24'h00;
always @(posedge i_clk)
if (qq_uart != ck_uart)
chg_counter <= 24'h00;
else
chg_counter <= chg_counter + 1;
 
// Are we in the middle of a baud iterval? Specifically, are we
// in the middle of a start bit? Set this to high if so. We'll use
// this within our state machine to transition out of the IDLE
// state.
reg half_baud_time;
initial half_baud_time = 0;
always @(posedge i_clk)
half_baud_time <= (~ck_uart)&&(chg_counter >= half_baud);
 
 
initial state = `RXU_IDLE;
always @(posedge i_clk)
begin
if (state == `RXU_IDLE)
begin // Idle state, independent of baud counter
// By default, just stay in the IDLE state
state <= `RXU_IDLE;
if ((~ck_uart)&&(half_baud_time))
// UNLESS: We are in the center of a valid
// start bit
state <= `RXU_BIT_ZERO;
end else if (zero_baud_counter)
begin
if (state < `RXU_STOP)
// Data arrives least significant bit first.
// By the time this is clocked in, it's what
// you'll have.
state <= state + 1;
else // Wait for the next character
state <= `RXU_IDLE;
end
end
 
// Data bit capture logic.
//
// This is drastically simplified from the state machine above, based
// upon: 1) it doesn't matter what it is until the end of a captured
// byte, and 2) the data register will flush itself of any invalid
// data in all other cases. Hence, let's keep it real simple.
reg [7:0] data_reg;
always @(posedge i_clk)
if (zero_baud_counter)
data_reg <= { ck_uart, data_reg[7:1] };
 
// Our data bit logic doesn't need nearly the complexity of all that
// work above. Indeed, we only need to know if we are at the end of
// a stop bit, in which case we copy the data_reg into our output
// data register, o_data, and tell others (for one clock) that data is
// available.
//
initial o_data = 8'h00;
reg pre_wr;
initial pre_wr = 1'b0;
always @(posedge i_clk)
if ((zero_baud_counter)&&(state == `RXU_STOP))
begin
o_wr <= 1'b1;
o_data <= data_reg;
end else
o_wr <= 1'b0;
 
// The baud counter
//
// This is used as a "clock divider" if you will, but the clock needs
// to be reset before any byte can be decoded. In all other respects,
// we set ourselves up for clocks_per_baud counts between baud
// intervals.
always @(posedge i_clk)
if ((zero_baud_counter)|||(state == `RXU_IDLE))
baud_counter <= CLOCKS_PER_BAUD-1'b1;
else
baud_counter <= baud_counter-1'b1;
 
// zero_baud_counter
//
// Rather than testing whether or not (baud_counter == 0) within our
// (already too complicated) state transition tables, we use
// zero_baud_counter to pre-charge that test on the clock
// before--cleaning up some otherwise difficult timing dependencies.
initial zero_baud_counter = 1'b0;
always @(posedge i_clk)
if (state == `RXU_IDLE)
zero_baud_counter <= 1'b0;
else
zero_baud_counter <= (baud_counter == 24'h01);
 
 
endmodule
 
 
/rtl/spio.v
4,7 → 4,12
//
// Project: CMod S6 System on a Chip, ZipCPU demonstration project
//
// Purpose:
// Purpose: To provide a bare minimum level of access to the two on-board
// buttons, the 4 LED's, and the external 4x4 keypad. This
// routine does *nothing* to debounce either buttons or keypad. Any such
// debouncing *must* be done in software. As with the rest of the S6
// project, the goal is to keep the logic small and simple, and this
// module is no different.
//
// With the USB cord on top, the board facing you, LED[0] is on the left.
//
72,6 → 77,12
reg [3:0] x_kp_row, r_kp_row;
reg [1:0] x_btn, r_btn;
 
initial x_kp_row = 4'h0;
initial r_kp_row = 4'b0;
initial x_btn = 2'b0;
initial r_btn = 2'b0;
initial o_kp_int = 1'b0;
initial o_btn_int = 1'b0;
always @(posedge i_clk)
begin
x_kp_row <= i_kp_row;
/rtl/toplevel.v
50,6 → 50,7
////////////////////////////////////////////////////////////////////////////////
//
//
`define LOWLOGIC_FLASH
module toplevel(i_clk_8mhz,
o_qspi_cs_n, o_qspi_sck, io_qspi_dat,
i_btn, o_led, o_pwm, o_pwm_shutdown_n, o_pwm_gain,
90,7 → 91,7
//
// Generate a usable clock for the rest of the board to run at.
//
wire ck_zero_0, clk_s;
wire ck_zero_0, clk_s, clk_sn;
 
// Clock frequency = (20 / 2) * 8Mhz = 80 MHz
// Clock period = 12.5 ns
111,6 → 112,7
.CLK0(ck_zero_0),
.CLKFB(ck_zero_0),
.CLKFX(clk_s),
.CLKFX180(clk_sn),
.PSEN(1'b0),
.RST(1'b0));
 
129,6 → 131,12
// the busmaster module (i.e. the interconnect) is all that needs
// to be changed: either to add more devices, or to remove them.
//
`ifdef LOWLOGIC_FLASH
wire [1:0] qspi_sck;
`else
wire qspi_sck;
`endif
wire qspi_cs_n;
wire [3:0] qspi_dat;
wire [1:0] qspi_bmod;
wire [15:0] w_gpio;
139,7 → 147,7
// Serial port wires
i_uart, o_uart_rts_n, o_uart, i_uart_cts_n,
// SPI/SD-card flash
o_qspi_cs_n, o_qspi_sck, qspi_dat, io_qspi_dat, qspi_bmod,
qspi_cs_n, qspi_sck, qspi_dat, io_qspi_dat, qspi_bmod,
// Board lights and switches
i_btn, o_led, o_pwm, { o_pwm_shutdown_n, o_pwm_gain },
// Keypad connections
157,9 → 165,41
// port with one wire in and one wire out. This utilizes our
// control wires (qspi_bmod) to set the output lines appropriately.
//
assign io_qspi_dat = (~qspi_bmod[1])?({2'b11,1'bz,qspi_dat[0]})
//
// 2'b0? -- Normal SPI
// 2'b10 -- Quad Output
// 2'b11 -- Quad Input
`ifdef LOWLOGIC_FLASH
reg r_qspi_cs_n;
reg [1:0] r_qspi_bmod;
reg [3:0] r_qspi_dat, r_qspi_z;
reg [1:0] r_qspi_sck;
always @(posedge clk_s)
r_qspi_sck <= qspi_sck;
xoddr xqspi_sck({clk_s, clk_sn}, r_qspi_sck, o_qspi_sck);
initial r_qspi_cs_n = 1'b1;
initial r_qspi_z = 4'b1101;
always @(posedge clk_s)
begin
r_qspi_dat <= (qspi_bmod[1]) ? qspi_dat:{ 3'b111, qspi_dat[0]};
r_qspi_z <= (!qspi_bmod[1])? 4'b1101
: ((qspi_bmod[0]) ? 4'h0 : 4'hf);
r_qspi_cs_n <= qspi_cs_n;
end
 
assign o_qspi_cs_n = r_qspi_cs_n;
assign io_qspi_dat[0] = (r_qspi_z[0]) ? r_qspi_dat[0] : 1'bz;
assign io_qspi_dat[1] = (r_qspi_z[1]) ? r_qspi_dat[1] : 1'bz;
assign io_qspi_dat[2] = (r_qspi_z[2]) ? r_qspi_dat[2] : 1'bz;
assign io_qspi_dat[3] = (r_qspi_z[3]) ? r_qspi_dat[3] : 1'bz;
`else
assign io_qspi_dat = (!qspi_bmod[1])?({2'b11,1'bz,qspi_dat[0]})
:((qspi_bmod[0])?(4'bzzzz):(qspi_dat[3:0]));
 
assign o_qspi_cs_n = qspi_cs_n;
assign o_qspi_sck = qspi_sck;
`endif // LOWLOGIC_FLASH
 
//
// I2C support
//
/rtl/txuartlite.v
0,0 → 1,206
////////////////////////////////////////////////////////////////////////////////
//
// Filename: txuartlite.v
//
// Project: wbuart32, a full featured UART with simulator
//
// Purpose: Transmit outputs over a single UART line. This particular UART
// implementation has been extremely simplified: it does not handle
// generating break conditions, nor does it handle anything other than the
// 8N1 (8 data bits, no parity, 1 stop bit) UART sub-protocol.
//
// To interface with this module, connect it to your system clock, and
// pass it the byte of data you wish to transmit. Strobe the i_wr line
// high for one 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
// get ignored. The output will be placed on the o_txuart output line.
//
// (I often set both data and strobe on the same clock, and then just leave
// them set until the busy line is low. Then I move on to the next piece
// of data.)
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory. Run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`define TXU_BIT_ZERO 4'h0
`define TXU_BIT_ONE 4'h1
`define TXU_BIT_TWO 4'h2
`define TXU_BIT_THREE 4'h3
`define TXU_BIT_FOUR 4'h4
`define TXU_BIT_FIVE 4'h5
`define TXU_BIT_SIX 4'h6
`define TXU_BIT_SEVEN 4'h7
`define TXU_STOP 4'h8
`define TXU_IDLE 4'hf
//
//
module txuartlite(i_clk, i_wr, i_data, o_uart_tx, o_busy);
parameter [23:0] CLOCKS_PER_BAUD = 24'd868;
input i_clk;
input i_wr;
input [7:0] i_data;
// And the UART input line itself
output reg o_uart_tx;
// A line to tell others when we are ready to accept data. If
// (i_wr)&&(!o_busy) is ever true, then the core has accepted a byte
// for transmission.
output wire o_busy;
 
reg [23:0] baud_counter;
reg [3:0] state;
reg [7:0] lcl_data;
reg r_busy, zero_baud_counter;
 
initial r_busy = 1'b1;
initial state = `TXU_IDLE;
initial lcl_data= 8'h0;
always @(posedge i_clk)
begin
if (!zero_baud_counter)
// r_busy needs to be set coming into here
r_busy <= 1'b1;
else if (state == `TXU_IDLE) // STATE_IDLE
begin
r_busy <= 1'b0;
if ((i_wr)&&(!r_busy))
begin // Immediately start us off with a start bit
r_busy <= 1'b1;
state <= `TXU_BIT_ZERO;
end
end else begin
// One clock tick in each of these states ...
r_busy <= 1'b1;
if (state <=`TXU_STOP) // start bit, 8-d bits, stop-b
state <= state + 1;
else
state <= `TXU_IDLE;
end
end
 
// o_busy
//
// This is a wire, designed to be true is we are ever busy above.
// originally, this was going to be true if we were ever not in the
// idle state. The logic has since become more complex, hence we have
// a register dedicated to this and just copy out that registers value.
assign o_busy = (r_busy);
 
 
// lcl_data
//
// This is our working copy of the i_data register which we use
// when transmitting. It is only of interest during transmit, and is
// allowed to be whatever at any other time. Hence, if r_busy isn't
// true, we can always set it. On the one clock where r_busy isn't
// true and i_wr is, we set it and r_busy is true thereafter.
// Then, on any zero_baud_counter (i.e. change between baud intervals)
// we simple logically shift the register right to grab the next bit.
initial lcl_data = 8'hff;
always @(posedge i_clk)
if ((i_wr)&&(!r_busy))
lcl_data <= i_data;
else if (zero_baud_counter)
lcl_data <= { 1'b1, lcl_data[7:1] };
 
// o_uart_tx
//
// This is the final result/output desired of this core. It's all
// centered about o_uart_tx. This is what finally needs to follow
// the UART protocol.
//
initial o_uart_tx = 1'b1;
always @(posedge i_clk)
if ((i_wr)&&(!r_busy))
o_uart_tx <= 1'b0; // Set the start bit on writes
else if (zero_baud_counter) // Set the data bit.
o_uart_tx <= lcl_data[0];
 
 
// All of the above logic is driven by the baud counter. Bits must last
// CLOCKS_PER_BAUD in length, and this baud counter is what we use to
// make certain of that.
//
// The basic logic is this: at the beginning of a bit interval, start
// the baud counter and set it to count CLOCKS_PER_BAUD. When it gets
// to zero, restart it.
//
// However, comparing a 28'bit number to zero can be rather complex--
// especially if we wish to do anything else on that same clock. For
// that reason, we create "zero_baud_counter". zero_baud_counter is
// nothing more than a flag that is true anytime baud_counter is zero.
// It's true when the logic (above) needs to step to the next bit.
// Simple enough?
//
// I wish we could stop there, but there are some other (ugly)
// conditions to deal with that offer exceptions to this basic logic.
//
// 1. When the user has commanded a BREAK across the line, we need to
// wait several baud intervals following the break before we start
// transmitting, to give any receiver a chance to recognize that we are
// out of the break condition, and to know that the next bit will be
// a stop bit.
//
// 2. A reset is similar to a break condition--on both we wait several
// baud intervals before allowing a start bit.
//
// 3. In the idle state, we stop our counter--so that upon a request
// to transmit when idle we can start transmitting immediately, rather
// than waiting for the end of the next (fictitious and arbitrary) baud
// interval.
//
// When (i_wr)&&(!r_busy)&&(state == `TXU_IDLE) then we're not only in
// the idle state, but we also just accepted a command to start writing
// the next word. At this point, the baud counter needs to be reset
// to the number of CLOCKS_PER_BAUD, and zero_baud_counter set to zero.
//
// The logic is a bit twisted here, in that it will only check for the
// above condition when zero_baud_counter is false--so as to make
// certain the STOP bit is complete.
initial zero_baud_counter = 1'b0;
initial baud_counter = 24'h05;
always @(posedge i_clk)
begin
zero_baud_counter <= (baud_counter == 24'h01);
if (state == `TXU_IDLE)
begin
baud_counter <= 24'h0;
zero_baud_counter <= 1'b1;
if ((i_wr)&&(!r_busy))
begin
baud_counter <= CLOCKS_PER_BAUD - 24'h01;
zero_baud_counter <= 1'b0;
end
end else if (!zero_baud_counter)
baud_counter <= baud_counter - 24'h01;
else
baud_counter <= CLOCKS_PER_BAUD - 24'h01;
end
endmodule
 
/rtl/wbqspiflashp.v
8,7 → 8,7
// provides a writable interface to the flash whereas the other
// is configured to be read only.
//
// Creator: Dan Gisselquist
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
/rtl/wbscope.v
11,7 → 11,7
// reset, the scope records a copy of the input data every time the clock
// ticks with the circuit enabled. That is, it records these values up
// until the trigger. Once the trigger goes high, the scope will record
// for bw_holdoff more counts before stopping. Values may then be read
// for br_holdoff more counts before stopping. Values may then be read
// from the buffer, oldest to most recent. After reading, the scope may
// then be reset for another run.
//
87,9 → 87,11
i_wb_clk, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
o_wb_ack, o_wb_stall, o_wb_data,
o_interrupt);
parameter LGMEM = 5'd10, BUSW = 32, SYNCHRONOUS=1,
DEFAULT_HOLDOFF = ((1<<(LGMEM-1))-4),
HOLDOFFBITS = 20;
parameter [4:0] LGMEM = 5'd10;
parameter BUSW = 32;
parameter [0:0] SYNCHRONOUS=1;
parameter HOLDOFFBITS = 20;
parameter [(HOLDOFFBITS-1):0] DEFAULT_HOLDOFF = ((1<<(LGMEM-1))-4);
// The input signals that we wish to record
input i_clk, i_ce, i_trigger;
input [(BUSW-1):0] i_data;
110,23 → 112,25
// Our status/config register
wire bw_reset_request, bw_manual_trigger,
bw_disable_trigger, bw_reset_complete;
reg [22:0] br_config;
wire [(HOLDOFFBITS-1):0] bw_holdoff;
initial br_config = DEFAULT_HOLDOFF;
reg [2:0] br_config;
reg [(HOLDOFFBITS-1):0] br_holdoff;
initial br_config = 3'b0;
initial br_holdoff = DEFAULT_HOLDOFF;
always @(posedge i_wb_clk)
if ((i_wb_stb)&&(~i_wb_addr))
if ((i_wb_stb)&&(!i_wb_addr))
begin
if (i_wb_we)
begin
br_config <= { i_wb_data[31],
(i_wb_data[27]),
i_wb_data[26],
i_wb_data[19:0] };
i_wb_data[27],
i_wb_data[26] };
br_holdoff = i_wb_data[(HOLDOFFBITS-1):0];
end
end else if (bw_reset_complete)
br_config[22] <= 1'b1;
assign bw_reset_request = (~br_config[22]);
assign bw_manual_trigger = (br_config[21]);
assign bw_disable_trigger = (br_config[20]);
assign bw_holdoff = br_config[(HOLDOFFBITS-1):0];
br_config[2] <= 1'b1;
assign bw_reset_request = (!br_config[2]);
assign bw_manual_trigger = (br_config[1]);
assign bw_disable_trigger = (br_config[0]);
 
wire dw_reset, dw_manual_trigger, dw_disable_trigger;
generate
180,8 → 184,7
reg dr_triggered, dr_primed;
wire dw_trigger;
assign dw_trigger = (dr_primed)&&(
((i_trigger)&&(~dw_disable_trigger))
||(dr_triggered)
((i_trigger)&&(!dw_disable_trigger))
||(dw_manual_trigger));
initial dr_triggered = 1'b0;
always @(posedge i_clk)
196,12 → 199,6
// Writes take place on the data clock
// The counter is unsigned
(* ASYNC_REG="TRUE" *) reg [(HOLDOFFBITS-1):0] counter;
reg less_than_holdoff;
always @(posedge i_clk)
if (dw_reset)
less_than_holdoff <= 1'b1;
else if (i_ce)
less_than_holdoff <= (counter < bw_holdoff);
 
reg dr_stopped;
initial dr_stopped = 1'b0;
209,7 → 206,7
always @(posedge i_clk)
if (dw_reset)
counter <= 0;
else if ((i_ce)&&(dr_triggered)&&(~dr_stopped))
else if ((i_ce)&&(dr_triggered)&&(!dr_stopped))
begin // MUST BE a < and not <=, so that we can keep this w/in
// 20 bits. Else we'd need to add a bit to comparison
// here.
216,12 → 213,10
counter <= counter + 1'b1;
end
always @(posedge i_clk)
if ((~dr_triggered)||(dw_reset))
if ((!dr_triggered)||(dw_reset))
dr_stopped <= 1'b0;
else if (i_ce)
dr_stopped <= (counter+1'b1 >= bw_holdoff);
else
dr_stopped <= (counter >= bw_holdoff);
dr_stopped <= (counter >= br_holdoff);
 
//
// Actually do our writes to memory. Record, via 'primed' when
296,10 → 291,10
if ((bw_reset_request)
||((bw_cyc_stb)&&(i_wb_addr)&&(i_wb_we)))
raddr <= 0;
else if ((bw_cyc_stb)&&(i_wb_addr)&&(~i_wb_we)&&(bw_stopped))
else if ((bw_cyc_stb)&&(i_wb_addr)&&(!i_wb_we)&&(bw_stopped))
raddr <= raddr + 1'b1; // Data read, when stopped
 
if ((bw_cyc_stb)&&(~i_wb_we))
if ((bw_cyc_stb)&&(!i_wb_we))
begin // Read from the bus
br_wb_ack <= 1'b1;
end else if ((bw_cyc_stb)&&(i_wb_we))
312,11 → 307,11
reg [31:0] nxt_mem;
always @(posedge i_wb_clk)
nxt_mem <= mem[raddr+waddr+
(((bw_cyc_stb)&&(i_wb_addr)&&(~i_wb_we)) ?
(((bw_cyc_stb)&&(i_wb_addr)&&(!i_wb_we)) ?
{{(LGMEM-1){1'b0}},1'b1} : { (LGMEM){1'b0}} )];
 
wire [19:0] full_holdoff;
assign full_holdoff[(HOLDOFFBITS-1):0] = bw_holdoff;
assign full_holdoff[(HOLDOFFBITS-1):0] = br_holdoff;
generate if (HOLDOFFBITS < 20)
assign full_holdoff[19:(HOLDOFFBITS)] = 0;
endgenerate
324,7 → 319,7
wire [4:0] bw_lgmem;
assign bw_lgmem = LGMEM;
always @(posedge i_wb_clk)
if (~i_wb_addr) // Control register read
if (!i_wb_addr) // Control register read
o_wb_data <= { bw_reset_request,
bw_stopped,
bw_triggered,
334,7 → 329,7
(raddr == {(LGMEM){1'b0}}),
bw_lgmem,
full_holdoff };
else if (~bw_stopped) // read, prior to stopping
else if (!bw_stopped) // read, prior to stopping
o_wb_data <= i_data;
else // if (i_wb_addr) // Read from FIFO memory
o_wb_data <= nxt_mem; // mem[raddr+waddr];
344,12 → 339,12
 
reg br_level_interrupt;
initial br_level_interrupt = 1'b0;
assign o_interrupt = (bw_stopped)&&(~bw_disable_trigger)
&&(~br_level_interrupt);
assign o_interrupt = (bw_stopped)&&(!bw_disable_trigger)
&&(!br_level_interrupt);
always @(posedge i_wb_clk)
if ((bw_reset_complete)||(bw_reset_request))
br_level_interrupt<= 1'b0;
else
br_level_interrupt<= (bw_stopped)&&(~bw_disable_trigger);
br_level_interrupt<= (bw_stopped)&&(!bw_disable_trigger);
 
endmodule
/rtl/xoddr.v
0,0 → 1,66
////////////////////////////////////////////////////////////////////////////////
//
// Filename: xoddr.v
//
// Project: CMod S6 System on a Chip, ZipCPU demonstration project
//
// Purpose: When outputting a clock, Xilinx recommends using the ODDR
// primitive to insure the clock's stability. This is a simple
// wrapper around that primitive, although it does cost one delay.
// For the QSPI, this helps to make certain that as much of the logic
// delay as possible has been removed from the path--to get the full
// 80MHz speed of our clock. (The QSPI device on the S6 can run at 108MHz,
// here, we will run it at 80MHz.)
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2017, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory. Run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
module xoddr(i_clk, i_v, o_pin);
input [1:0] i_clk;
input [1:0] i_v;
output o_pin;
 
wire w_internal;
reg last;
 
ODDR2 #(
.DDR_ALIGNMENT("C0"),
.INIT(1'b1),
.SRTYPE("ASYNC")
) ODDRi(
.Q(o_pin),
.CE(1'b1),
.C0(i_clk[0]),
.D0(i_v[0]), // Negative clock edge (goes first)
.C1(i_clk[1]),
.D1(i_v[1]), // Positive clock edge
.R(1'b0),
.S(1'b0));
 
endmodule

powered by: WebSVN 2.1.0

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