Subversion Repositories s6soc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    from Rev 15 to Rev 16
    Reverse comparison

Rev 15 → Rev 16

120,7 → 120,9
// Set the interrupt on our last tick.
initial o_int = 1'b0;
always @(posedge i_clk)
if (i_ce)
if (i_rst)
o_int <= 1'b0;
else if (i_ce)
o_int <= (r_running)&&(r_value == { {(VW-1){1'b0}}, 1'b1 });
o_int <= 1'b0;
266,6 → 266,6
// `define DEBUG_SCOPE
`endif // CPUDEFS_H
240,8 → 240,8
// +(al*bl)
// - 2^31 (2^16 bh+bl + 2^16 ah+al + 2^31)
reg [31:0] pp_f, pp_l; // pp_o, pp_i, pp_l;
reg [32:0] pp_oi;
reg [31:0] pp_f, pp_l; // F and L from FOIL
reg [32:0] pp_oi; // The O and I from FOIL
reg [32:0] pp_s;
always @(posedge i_clk)
304,7 → 304,8
reg [(AW-1):0] alu_pc;
reg alu_pc_valid, mem_pc_valid;
reg r_alu_pc_valid, mem_pc_valid;
wire alu_pc_valid;
wire alu_phase;
wire alu_ce, alu_stall;
wire [31:0] alu_result;
375,11 → 376,8
// PIPELINE STAGE #2 :: Instruction Decode
// Calculate stall conditions
assign dcd_ce = ((~dcdvalid)||(~dcd_stalled))&&(~clear_pipeline);
assign dcd_ce = 1'b1;
assign dcd_stalled = (dcdvalid)&&(op_stall);
428,7 → 426,7
assign op_ce = ((dcdvalid)||(dcd_illegal))&&(~op_stall)&&(~clear_pipeline);
assign op_stall = (opvalid)&&(~master_ce);
assign op_ce = ((dcdvalid)||(dcd_illegal));
assign op_ce = ((dcdvalid)||(dcd_illegal))&&(~clear_pipeline);
458,7 → 456,7
assign alu_stall = ((~master_ce)&&(opvalid_alu))
assign alu_ce = (master_ce)&&((opvalid_alu)||(op_illegal))&&(~alu_stall);
assign alu_ce = (master_ce)&&((opvalid_alu)||(op_illegal))&&(~alu_stall)&&(~clear_pipeline);
473,7 → 471,7
// 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.
assign mem_ce = (master_ce)&&(opvalid_mem)&&(~mem_stalled);
assign mem_ce = (master_ce)&&(opvalid_mem)&&(~mem_stalled)&&(~clear_pipeline);
assign mem_stalled = (~master_ce)||(alu_busy)||((opvalid_mem)&&(
512,7 → 510,7
assign pf_ce = (~pf_valid)&&(~dcdvalid)&&(~opvalid)&&(~alu_valid);
prefetch #(ADDRESS_WIDTH)
pf(i_clk, i_rst, (pf_ce), (~dcd_stalled), pf_pc, gie,
pf(i_clk, (i_rst), (pf_ce), (~dcd_stalled), pf_pc, gie,
instruction, instruction_pc, instruction_gie,
pf_valid, pf_illegal,
pf_cyc, pf_stb, pf_we, pf_addr, pf_data,
520,7 → 518,7
initial r_dcdvalid = 1'b0;
always @(posedge i_clk)
if (i_rst)
if ((i_rst)||(clear_pipeline))
r_dcdvalid <= 1'b0;
else if (dcd_ce)
r_dcdvalid <= (pf_valid);
565,7 → 563,7
if ((i_rst)||(clear_pipeline))
r_dcdvalid <= 1'b0;
else if (dcd_ce)
r_dcdvalid <= (pf_valid)&&(~clear_pipeline)&&(~dcd_ljmp)&&((~r_dcdvalid)||(~dcd_early_branch));
r_dcdvalid <= (pf_valid)&&(~dcd_ljmp)&&((~r_dcdvalid)||(~dcd_early_branch));
else if (op_ce)
r_dcdvalid <= 1'b0;
assign dcdvalid = r_dcdvalid;
1160,13 → 1158,16
assign alu_illegal = (alu_illegal_op)||(r_alu_illegal);
initial alu_pc_valid = 1'b0;
initial r_alu_pc_valid = 1'b0;
initial mem_pc_valid = 1'b0;
always @(posedge i_clk)
if (i_rst)
alu_pc_valid <= 1'b0;
alu_pc_valid <= (alu_ce);
r_alu_pc_valid <= 1'b0;
else if (alu_ce) // Includes && (~alu_clear_pipeline)
r_alu_pc_valid <= 1'b1;
else if ((~alu_busy)||(clear_pipeline))
r_alu_pc_valid <= 1'b0;
assign alu_pc_valid = (r_alu_pc_valid)&&(~alu_busy);
always @(posedge i_clk)
if (i_rst)
mem_pc_valid <= 1'b0;
1638,7 → 1639,9
else if ((new_pc)||((~dcd_stalled)&&(pf_valid)))
pf_pc <= pf_pc + {{(AW-1){1'b0}},1'b1};
else if (((alu_pc_valid)&&(~clear_pipeline))||(mem_pc_valid))
else if ((alu_gie==gie)&&(
pf_pc <= alu_pc;
1707,20 → 1710,45
always @(posedge i_clk)
o_debug <= {
o_break, i_wb_err, pf_pc[1:0],
pf_valid, dcdvalid, opvalid, alu_valid, mem_valid,
pf_valid, dcdvalid, opvalid, alu_valid,
op_ce, alu_ce, mem_ce,
master_ce, opvalid_alu, opvalid_mem,
opvalid_alu, opvalid_mem, alu_stall,
alu_stall, mem_busy, op_pipe, mem_pipe_stalled,
mem_busy, op_pipe,
// ((opvalid_alu)&&(alu_stall))
// ||((opvalid_mem)&&(~op_pipe)&&(mem_busy))
// ||((opvalid_mem)&&( op_pipe)&&(mem_pipe_stalled)));
// opA[23:20], opA[3:0],
gie, sleep, wr_reg_ce, wr_reg_vl[4:0]
o_break, i_wb_err, o_wb_gbl_cyc, o_wb_gbl_stb,
pf_valid, dcdvalid, opvalid, alu_valid,
mem_valid, dcd_ce, op_ce, alu_ce,
dcd_illegal, gie, sleep,
{ ((o_wb_gbl_cyc)&&(o_wb_gbl_stb)&&(o_wb_we))
? o_wb_data[15:0]
: ((o_wb_gbl_cyc)&&(o_wb_gbl_stb)&&(~o_wb_we)&&(i_wb_ack))
? i_wb_data[15:0]
: o_wb_addr[15:0]
i_rst, master_ce, (new_pc),
1,20 → 1710,45
`define DATESTAMP 32'h20160430
`define DATESTAMP 32'h20160505
0,0 → 1,220
// Filename: wbscopc.v
// Project: FPGA Library of Routines
// Purpose: This scope is identical in function to the wishbone scope
// found in wbscope, save that the output is compressed and that (as a
// result) it can only handle recording 31 bits at a time. This allows
// the top bit to indicate an 'address difference'. Okay, there's
// another difference as well: this version only works in a synchronous
// fashion with the clock from the WB bus. You cannot have a separate
// bus and data clock.
// Reading/decompressing the output of this scope works in this fashion:
// Once the scope has stopped, read from the port. Any time the high
// order bit is set, the other 31 bits tell you how many times to repeat
// the last value. If the high order bit is not set, then the value
// is a new data value.
// I've provided this version of a compressed scope to OpenCores for
// discussion purposes. While wbscope.v works and works well by itself,
// this compressed scope has a couple of fundamental flaw that I have
// yet to fix. One of them is that it is impossible to know when the
// trigger took place. The second problem is that it may be impossible
// to know the state of the scope at the beginning of the buffer--should
// the buffer begin with an address difference value instead of a data
// value.
// Ideally, the first item read out of the scope should be a data value,
// even if the scope was skipping values to a new address at the time.
// If it was in the middle of a skip, the next item out of the scope
// should be the skip length. This, though, violates the rule that there
// are (1<<LGMEMLEN) items in the memory, and that the trigger took place
// on the last item of memory ... so that portion of this compressed
// scope is still to be defined.
// Like I said, this version is placed here for discussion purposes,
// not because it runs well nor because I have recognized that it has any
// particular value (yet).
// Well, I take that back. When dealing with an interface such as the
// PS/2 interface, or even the 16x2 LCD interface, it is often true
// that things change _very_ slowly. They could change so slowly that
// the other approach to the scope doesn't work. This then gives you
// a working scope, by only capturing the changes. You'll still need
// to figure out (after the fact) when the trigge took place. Perhaps
// you'll wish to add the trigger as another data line, so you can find
// when it took place in your own data?
// Okay, I take that back twice: I'm finding this compressed scope very
// valuable for evaluating the timing associated with a GPS PPS and
// associated NMEA stream. I need to collect over a seconds worth of
// data, and I don't have enough memory to handle one memory value per
// clock, yet I still want to know exactly when the GPS PPS goes high,
// when it goes low, when I'm adjusting my clock, and when the clock's
// PPS output goes high. Did I synchronize them well? Oh, and when does
// the NMEA time string show up when compared with the PPS? All of those
// are valuable, but could never be done if the scope wasn't compressed.
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
// Copyright (C) 2015, Gisselquist Technology, LLC
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <> for a copy.
// License: GPL, v3, as defined and found on,
module wbscopc(i_clk, i_ce, i_trigger, i_data,
i_wb_clk, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
o_wb_ack, o_wb_stall, o_wb_data,
parameter LGMEM = 5'd10, NELM=31, BUSW = 32, SYNCHRONOUS=1;
// The input signals that we wish to record
input i_clk, i_ce, i_trigger;
input [(NELM-1):0] i_data;
// The WISHBONE bus for reading and configuring this scope
input i_wb_clk, i_wb_cyc, i_wb_stb, i_wb_we;
input i_wb_addr; // One address line only
input [(BUSW-1):0] i_wb_data;
output wire o_wb_ack, o_wb_stall;
output wire [(BUSW-1):0] o_wb_data;
// And, finally, for a final flair --- offer to interrupt the CPU after
// our trigger has gone off. This line is equivalent to the scope
// being stopped. It is not maskable here.
output wire o_interrupt;
// Let's first see how far we can get by cheating. We'll use the
// wbscope program, and suffer a lack of several features
// When is the full scope reset? Capture that reset bit from any
// write.
wire lcl_reset;
assign lcl_reset = (i_wb_cyc)&&(i_wb_stb)&&(~i_wb_addr)&&(i_wb_we)
// A big part of this scope is the 'address' of any particular
// data value. As of this current version, the 'address' changed
// in definition from an absolute time (which had all kinds of
// problems) to a difference in time. Hence, when the address line
// is high on decompression, the 'address' field will record an
// address difference.
// To implement this, we set our 'address' to zero any time the
// data changes, but increment it on all other clocks. Should the
// address difference get to our maximum value, we let it saturate
// rather than overflow.
reg [(BUSW-2):0] ck_addr;
reg [(NELM-1):0] lst_dat;
initial ck_addr = 0;
always @(posedge i_clk)
if ((lcl_reset)||((i_ce)&&(i_data != lst_dat)))
ck_addr <= 0;
else if (&ck_addr)
; // Saturated (non-overflowing) address diff
ck_addr <= ck_addr + 1;
wire [(BUSW-2):0] w_data;
if (NELM == BUSW-1)
assign w_data = i_data;
assign w_data = { {(BUSW-NELM-1){1'b0}}, i_data };
// To do our compression, we keep track of two registers: the most
// recent data to the device (imm_ prefix) and the data from one
// clock ago. This allows us to suppress writes to the scope which
// would otherwise be two address writes in a row.
reg imm_adr, lst_adr; // Is this an address (1'b1) or data value?
reg [(BUSW-2):0] lst_val, // Data for the scope, delayed by one
imm_val; // Data to write to the scope
initial lst_dat = 0;
initial lst_adr = 1'b1;
initial imm_adr = 1'b1;
always @(posedge i_clk)
if (lcl_reset)
imm_val <= 31'h0;
imm_adr <= 1'b1;
lst_val <= 31'h0;
lst_adr <= 1'b1;
lst_dat <= 0;
end else if ((i_ce)&&(i_data != lst_dat))
imm_val <= w_data;
imm_adr <= 1'b0;
lst_val <= imm_val;
lst_adr <= imm_adr;
lst_dat <= i_data;
end else begin
imm_val <= ck_addr; // Minimum value here is '1'
imm_adr <= 1'b1;
lst_val <= imm_val;
lst_adr <= imm_adr;
// Here's where we suppress writing pairs of address words to the
// scope at once.
reg r_ce;
reg [(BUSW-1):0] r_data;
initial r_ce = 1'b0;
always @(posedge i_clk)
r_ce <= (~lst_adr)||(~imm_adr);
always @(posedge i_clk)
r_data <= ((~lst_adr)||(~imm_adr))
? { lst_adr, lst_val }
: { {(32 - NELM){1'b0}}, i_data };
// The trigger needs some extra attention, in order to keep triggers
// that happen between events from being ignored.
wire w_trigger;
assign w_trigger = (r_trigger)||(i_trigger);
reg r_trigger;
initial r_trigger = 1'b0;
always @(posedge i_clk)
if (lcl_reset)
r_trigger <= 1'b0;
r_trigger <= w_trigger;
// Call the regular wishbone scope to do all of our real work, now
// that we've compressed the input.
.BUSW(BUSW)) cheatersscope(i_clk, r_ce, w_trigger, r_data,
i_wb_clk, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
o_wb_ack, o_wb_stall, o_wb_data, o_interrupt);
39,12 → 39,15
`include "builddate.v"
`define IMPLEMENT_ONCHIP_RAM // 2804 w/o after synthesis
`define DBG_SCOPE // About 204 LUTs, at 2^6 addresses
// `define INCLUDE_RTC // About 90 LUTs
module busmaster(i_clk, i_rst,
i_rx_stb, i_rx_data, o_tx_stb, o_tx_data, i_tx_busy,
122,7 → 125,7
wire zip_cyc, zip_stb, zip_we, zip_cpu_int;
wire [(ZA-1):0] w_zip_addr;
wire [(BAW-1):0] zip_addr;
wire [31:0] zip_data;
wire [31:0] zip_data, zip_scope_data;
// and then coming from devices
wire zip_ack, zip_stall, zip_err;
wire dwb_we, dwb_stb, dwb_cyc, dwb_ack, dwb_stall, dwb_err;
144,15 → 147,33
// in the flash without needing to change our FPGA load and vice versa.
// 23'h404000
wire cpu_reset;
reg btn_reset, x_button, r_button;
initial btn_reset = 1'b0;
initial x_button = 1'b0;
initial r_button = 1'b0;
always @(posedge i_clk)
x_button <= i_btn[1];
r_button <= x_button;
btn_reset <= ((r_button)&&(zip_cpu_int))||(tmrb_int);
assign cpu_reset = btn_reset;
assign cpu_reset = 1'b0;
thecpu(i_clk, 1'b0,
thecpu(i_clk, btn_reset, // 1'b0,
// Zippys wishbone interface
wb_cyc, wb_stb, wb_we, w_zip_addr, wb_data,
wb_ack, wb_stall, wb_idata, wb_err,
w_interrupt, zip_cpu_int,
// Debug wishbone interface
// Debug wishbone interface -- not really used
1'b0, 1'b0,1'b0, 1'b0, 32'h00,
zip_dbg_ack, zip_dbg_stall, zip_dbg_data);
zip_dbg_ack, zip_dbg_stall, zip_dbg_data,
if (ZA < BAW)
assign wb_addr = { {(BAW-ZA){1'b0}}, w_zip_addr };
219,6 → 240,12
assign none_sel =((wb_cyc)&&(wb_stb)&&(io_addr==6'h0));
assign none_sel =((wb_cyc)&&(wb_stb)&&
assign many_sel =((wb_cyc)&&(wb_stb)&&(
{3'h0, io_sel}
+{3'h0, flctl_sel}
270,14 → 297,24
wire zta_ack, zta_stall, ztb_ack, ztb_stall;
ziptimer #(32,31)
zipt_a(i_clk, 1'b0, 1'b1, wb_cyc,
wb_we, wb_data, zta_ack, zta_stall, timer_a,
ziptimer #(32,31)
zipt_b(i_clk, 1'b0, 1'b1, wb_cyc,
zipt_b(i_clk, cpu_reset, 1'b1, wb_cyc,
wb_we, wb_data, ztb_ack, ztb_stall, timer_b,
// assign timer_b = 32'h000;
assign timer_b = timer_a;
assign tmrb_int = 1'b0;
wire [31:0] rtc_data;
331,9 → 368,11
// Special Purpose I/O: Keypad, button, LED status and control
wire [3:0] w_led;
spio thespio(i_clk, wb_cyc,(wb_stb)&&(io_sel)&&(wb_addr[3:0]==4'h5),wb_we,
wb_data, spio_data, o_kp_col, i_kp_row, i_btn, o_led,
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] };
// General purpose (sort of) I/O: (Bottom two bits robbed in each
447,7 → 486,16
`ifdef DBG_SCOPE
wire scop_cfg_trigger;
assign scop_cfg_trigger = (wb_cyc)&&(wb_stb)&&(cfg_sel);
wbscope #(5'ha) wbcfgscope(i_clk, 1'b1, scop_cfg_trigger, cfg_scope,
// wire scop_trigger = scop_cfg_trigger;
wire scop_trigger = (zip_cpu_int) || (cpu_reset);
wbscopc #(5'ha)
wbscope #(5'ha)
wbcfgscope(i_clk, 1'b1, scop_trigger,
// cfg_scope,
// Wishbone interface
i_clk, wb_cyc, (wb_stb)&&(scop_sel),
wb_we, wb_addr[0], wb_data,

powered by: WebSVN 2.1.0

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