URL
https://opencores.org/ocsvn/zipcpu/zipcpu/trunk
Subversion Repositories zipcpu
Compare Revisions
- This comparison shows the changes necessary to convert path
/zipcpu/trunk/rtl
- from Rev 34 to Rev 36
- ↔ Reverse comparison
Rev 34 → Rev 36
/core/memops.v
11,6 → 11,9
// before it completes the last one. Unpredictable results might then |
// occurr. |
// |
// 20150919 -- Added support for handling BUS ERR's (i.e., the WB |
// error signal). |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Tecnology, LLC |
// |
36,9 → 39,11
// |
module memops(i_clk, i_rst, i_stb, |
i_op, i_addr, i_data, i_oreg, |
o_busy, o_valid, o_wreg, o_result, |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, |
i_wb_ack, i_wb_stall, i_wb_data); |
o_busy, o_valid, o_err, o_wreg, o_result, |
o_wb_cyc_gbl, o_wb_cyc_lcl, |
o_wb_stb_gbl, o_wb_stb_lcl, |
o_wb_we, o_wb_addr, o_wb_data, |
i_wb_ack, i_wb_stall, i_wb_err, i_wb_data); |
input i_clk, i_rst; |
input i_stb; |
// CPU interface |
49,29 → 54,49
// CPU outputs |
output wire o_busy; |
output reg o_valid; |
output reg o_err; |
output reg [4:0] o_wreg; |
output reg [31:0] o_result; |
// Wishbone outputs |
output reg o_wb_cyc, o_wb_stb, o_wb_we; |
output reg o_wb_cyc_gbl, o_wb_stb_gbl; |
output reg o_wb_cyc_lcl, o_wb_stb_lcl, o_wb_we; |
output reg [31:0] o_wb_addr, o_wb_data; |
// Wishbone inputs |
input i_wb_ack, i_wb_stall; |
input i_wb_ack, i_wb_stall, i_wb_err; |
input [31:0] i_wb_data; |
|
wire gbl_stb, lcl_stb; |
assign lcl_stb = (i_stb)&&(i_addr[31:8]==24'hc00000)&&(i_addr[7:5]==3'h0); |
assign gbl_stb = (i_stb)&&((i_addr[31:8]!=24'hc00000)||(i_addr[7:5]!=3'h0)); |
|
always @(posedge i_clk) |
if (i_rst) |
o_wb_cyc <= 1'b0; |
else if (o_wb_cyc) |
o_wb_cyc <= (~i_wb_ack); |
else if (i_stb) // New memory operation |
// Grab the wishbone |
o_wb_cyc <= 1'b1; |
begin |
o_wb_cyc_gbl <= 1'b0; |
o_wb_cyc_lcl <= 1'b0; |
end else if ((o_wb_cyc_gbl)||(o_wb_cyc_lcl)) |
begin |
if ((i_wb_ack)||(i_wb_err)) |
begin |
o_wb_cyc_gbl <= 1'b0; |
o_wb_cyc_lcl <= 1'b0; |
end |
end else if (i_stb) // New memory operation |
begin // Grab the wishbone |
o_wb_cyc_lcl <= lcl_stb; |
o_wb_cyc_gbl <= gbl_stb; |
end |
always @(posedge i_clk) |
if (o_wb_cyc) |
o_wb_stb <= (o_wb_stb)&&(i_wb_stall); |
if (o_wb_cyc_gbl) |
o_wb_stb_gbl <= (o_wb_stb_gbl)&&(i_wb_stall); |
else |
o_wb_stb <= i_stb; // Grab wishbone on new operation |
o_wb_stb_gbl <= gbl_stb; // Grab wishbone on new operation |
always @(posedge i_clk) |
if (o_wb_cyc_lcl) |
o_wb_stb_lcl <= (o_wb_stb_lcl)&&(i_wb_stall); |
else |
o_wb_stb_lcl <= lcl_stb; // Grab wishbone on new operation |
always @(posedge i_clk) |
if (i_stb) |
begin |
o_wb_we <= i_op; |
81,8 → 106,11
|
initial o_valid = 1'b0; |
always @(posedge i_clk) |
o_valid <= (o_wb_cyc)&&(i_wb_ack)&&(~o_wb_we); |
assign o_busy = o_wb_cyc; |
o_valid <= ((o_wb_cyc_gbl)||(o_wb_cyc_lcl))&&(i_wb_ack)&&(~o_wb_we); |
initial o_err = 1'b0; |
always @(posedge i_clk) |
o_err <= ((o_wb_cyc_gbl)||(o_wb_cyc_lcl))&&(i_wb_err); |
assign o_busy = (o_wb_cyc_gbl)||(o_wb_cyc_lcl); |
|
always @(posedge i_clk) |
if (i_stb) |
/core/prefetch.v
13,6 → 13,12
// a suggestion of what to load. Other wires may be loaded |
// instead. i_pc is what must be output, not necessarily input. |
// |
// 20150919 -- Added support for the WB error signal. When reading an |
// instruction results in this signal being raised, the pipefetch |
// module will set an illegal instruction flag to be returned to |
// the CPU together with the instruction. Hence, the ZipCPU |
// can trap on it if necessary. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Tecnology, LLC |
// |
42,9 → 48,9
// 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_pc, i_aux, |
o_i, o_pc, o_aux, o_valid, |
o_i, o_pc, o_aux, o_valid, o_illegal, |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, |
i_wb_ack, i_wb_stall, i_wb_data); |
i_wb_ack, i_wb_stall, i_wb_err, i_wb_data); |
parameter AW = 1; |
input i_clk, i_rst, i_ce; |
input [31:0] i_pc; |
52,7 → 58,7
output reg [31:0] o_i; |
output reg [31:0] o_pc; |
output reg [(AW-1):0] o_aux; |
output wire o_valid; |
output wire o_valid, o_illegal; |
// Wishbone outputs |
output reg o_wb_cyc, o_wb_stb; |
output wire o_wb_we; |
59,7 → 65,7
output reg [31:0] o_wb_addr; |
output wire [31:0] o_wb_data; |
// And return inputs |
input i_wb_ack, i_wb_stall; |
input i_wb_ack, i_wb_stall, i_wb_err; |
input [31:0] i_wb_data; |
|
assign o_wb_we = 1'b0; |
103,5 → 109,6
o_pc <= o_wb_addr; |
|
assign o_valid = (i_pc == o_pc)&&(i_aux == o_aux)&&(~o_wb_cyc); |
assign o_illegal = (o_wb_cyc)&&(i_wb_err); |
|
endmodule |
/core/pipefetch.v
14,6 → 14,17
// the purposes of this instruction fetch module: 1) Pipeline |
// wishbone accesses, and 2) an instruction cache. |
// |
// 20150919 -- Fixed a nasty race condition whereby the pipefetch routine |
// would produce either the same instruction twice, or skip |
// an instruction. This condition was dependent on the CPU stall |
// condition, and would only take place if the pipeline wasn't |
// completely full throughout the stall. |
// |
// Interface support was also added for trapping on illegal |
// instructions (i.e., instruction fetches that cause bus errors), |
// however the internal interface has not caught up to supporting |
// these exceptions yet. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Tecnology, LLC |
// |
40,7 → 51,8
module pipefetch(i_clk, i_rst, i_new_pc, i_clear_cache, i_stall_n, i_pc, |
o_i, o_pc, o_v, |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, |
i_wb_ack, i_wb_stall, i_wb_data, i_wb_request); |
i_wb_ack, i_wb_stall, i_wb_err, i_wb_data, i_wb_request, |
o_illegal); |
parameter RESET_ADDRESS=32'h0010_0000, |
LGCACHELEN = 6, CACHELEN=(1<<LGCACHELEN), |
BUSW=32; |
56,12 → 68,15
output reg [(BUSW-1):0] o_wb_addr; |
output wire [(BUSW-1):0] o_wb_data; |
// |
input i_wb_ack, i_wb_stall; |
input i_wb_ack, i_wb_stall, i_wb_err; |
input [(BUSW-1):0] i_wb_data; |
// |
// Is the (data) memory unit also requesting access to the bus? |
input i_wb_request; |
output wire o_illegal; |
|
assign o_illegal = 1'b0; |
|
// Fixed bus outputs: we read from the bus only, never write. |
// Thus the output data is ... irrelevant and don't care. We set it |
// to zero just to set it to something. |
93,7 → 108,6
assign w_running_out_of_cache = (r_addr_set) |
&&(r_addr >= r_cache_base + (1<<(LGCACHELEN-2)) |
+ (1<<(LGCACHELEN-1))); |
initial r_nvalid = 0; |
initial r_cache_base = RESET_ADDRESS; |
always @(posedge i_clk) |
begin |
161,10 → 175,12
// r_nvalid <= r_nvalid + 1; |
if ((r_acks_waiting == 1)&&(~o_wb_stb)) |
o_wb_cyc <= 1'b0; |
end |
end else if ((r_acks_waiting == 0)&&(~o_wb_stb)) |
o_wb_cyc <= 1'b0; |
end |
end |
|
initial r_nvalid = 0; |
always @(posedge i_clk) |
if ((i_rst)||(i_clear_cache)) // Required, so we can reload memoy and then reset |
r_nvalid <= 0; |
210,9 → 226,9
if (~o_wb_cyc) |
r_acks_waiting <= 0; |
else if ((o_wb_stb)&&(~i_wb_stall)&&(~i_wb_ack)) |
r_acks_waiting <= r_acks_waiting + ((i_wb_ack)? 0:1); |
r_acks_waiting <= r_acks_waiting + 1; |
else if ((i_wb_ack)&&((~o_wb_stb)||(i_wb_stall))) |
r_acks_waiting <= r_acks_waiting - 1; |
r_acks_waiting <= r_acks_waiting - 1; |
|
always @(posedge i_clk) |
if ((o_wb_cyc)&&(i_wb_ack)) |
232,13 → 248,13
assign w_cv = ((r_nvalid != 0)&&(r_addr>=r_cache_base) |
&&(r_addr-r_cache_base < bus_nvalid)); |
always @(posedge i_clk) |
r_cv <= (~i_new_pc)&&(w_cv); |
r_cv <= (~i_new_pc)&&((w_cv)||((~i_stall_n)&&(r_cv))); |
assign o_v = (r_cv)&&(~i_new_pc); |
|
always @(posedge i_clk) |
if (i_new_pc) |
r_addr <= i_pc; |
else if ((i_stall_n)&&(w_cv)) |
else if ( ((i_stall_n)&&(w_cv)) || ((~i_stall_n)&&(w_cv)&&(r_addr == o_pc)) ) |
r_addr <= r_addr + 1; |
|
wire [(LGCACHELEN-1):0] c_rdaddr, c_cache_base; |
245,10 → 261,10
assign c_cache_base = r_cache_base[(LGCACHELEN-1):0]; |
assign c_rdaddr = r_addr[(LGCACHELEN-1):0]-c_cache_base+r_cache_offset; |
always @(posedge i_clk) |
if (i_stall_n) |
if ((~o_v)||((i_stall_n)&&(o_v))) |
o_i <= cache[c_rdaddr]; |
always @(posedge i_clk) |
if (i_stall_n) |
if ((~o_v)||((i_stall_n)&&(o_v))) |
o_pc <= r_addr; |
|
endmodule |
/core/zipcpu.v
106,6 → 106,20
// |
/////////////////////////////////////////////////////////////////////////////// |
// |
// We can either pipeline our fetches, or issue one fetch at a time. Pipelined |
// fetches are more complicated and therefore use more FPGA resources, while |
// single fetches will cause the CPU to stall for about 5 stalls each |
// instruction cycle, effectively reducing the instruction count per clock to |
// about 0.2. However, the area cost may be worth it. Consider: |
// |
// Slice LUTs ZipSystem ZipCPU |
// Single Fetching 2521 1734 |
// Pipelined fetching 2796 2046 |
// |
// `define SINGLE_FETCH |
// |
// |
// |
`define CPU_CC_REG 4'he |
`define CPU_PC_REG 4'hf |
`define CPU_TRAP_BIT 9 |
113,6 → 127,13
`define CPU_STEP_BIT 6 |
`define CPU_GIE_BIT 5 |
`define CPU_SLEEP_BIT 4 |
// Compile time defines |
// `define SINGLE_FETCH |
`define NG_CONDITIONAL_FLAGS |
`define NG_PRECLEAR_BUS // 0.61 w/ or w/o |
// `define NG_BRANCH_DELAY_SLOT |
`define NG_ILLEGAL_INSTRUCTION |
`define NG_EARLY_BRANCHING // 0.60 w/, 0.61 w/o ???? |
module zipcpu(i_clk, i_rst, i_interrupt, |
// Debug interface |
i_halt, i_clear_pf_cache, i_dbg_reg, i_dbg_we, i_dbg_data, |
119,8 → 140,11
o_dbg_stall, o_dbg_reg, o_dbg_cc, |
o_break, |
// CPU interface to the wishbone bus |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, |
o_wb_gbl_cyc, o_wb_gbl_stb, |
o_wb_lcl_cyc, o_wb_lcl_stb, |
o_wb_we, o_wb_addr, o_wb_data, |
i_wb_ack, i_wb_stall, i_wb_data, |
i_wb_err, |
// Accounting/CPU usage interface |
o_op_stall, o_pf_stall, o_i_count); |
parameter RESET_ADDRESS=32'h0100000; |
136,11 → 160,13
output reg [1:0] o_dbg_cc; |
output wire o_break; |
// Wishbone interface -- outputs |
output wire o_wb_cyc, o_wb_stb, o_wb_we; |
output wire o_wb_gbl_cyc, o_wb_gbl_stb; |
output wire o_wb_lcl_cyc, o_wb_lcl_stb, o_wb_we; |
output wire [31:0] o_wb_addr, o_wb_data; |
// Wishbone interface -- inputs |
input i_wb_ack, i_wb_stall; |
input [31:0] i_wb_data; |
input i_wb_err; |
// Accounting outputs ... to help us count stalls and usage |
output wire o_op_stall; |
output wire o_pf_stall; |
152,8 → 178,12
|
// Condition codes |
reg [3:0] flags, iflags; // (TRAP,FPEN,BREAKEN,STEP,GIE,SLEEP ), V, N, C, Z |
wire [9:0] w_uflags, w_iflags; |
wire [10:0] w_uflags, w_iflags; |
reg trap, break_en, step, gie, sleep; |
`ifdef NG_ILLEGAL_INSTRUCTION |
reg ill_err; |
`endif |
reg bus_err_flag; |
|
// The master chip enable |
wire master_ce; |
166,13 → 196,13
reg [31:0] pf_pc; |
reg new_pc, op_break; |
wire clear_pipeline; |
assign clear_pipeline = new_pc || i_clear_pf_cache || op_break; |
assign clear_pipeline = new_pc || i_clear_pf_cache; // || op_break; |
|
wire dcd_stalled; |
wire pf_cyc, pf_stb, pf_we, pf_busy, pf_ack, pf_stall; |
wire pf_cyc, pf_stb, pf_we, pf_busy, pf_ack, pf_stall, pf_err; |
wire [31:0] pf_addr, pf_data; |
wire [31:0] instruction, instruction_pc; |
wire pf_valid, instruction_gie; |
wire pf_valid, instruction_gie, pf_illegal; |
|
// |
// |
192,6 → 222,19
reg [23:0] r_dcdI; |
wire dcdA_stall, dcdB_stall, dcdF_stall; |
|
`ifdef NG_PRECLEAR_BUS |
reg dcd_clear_bus; |
`endif |
`ifdef NG_ILLEGAL_INSTRUCTION |
reg dcd_illegal; |
`endif |
`ifdef NG_EARLY_BRANCHING |
reg dcd_early_branch_stb, dcd_early_branch; |
reg [31:0] dcd_branch_pc; |
`else |
wire dcd_early_branch_stb, dcd_early_branch; |
wire [31:0] dcd_branch_pc; |
`endif |
|
|
// |
210,13 → 253,18
wire [31:0] opA_nowait, opB_nowait, opA, opB; |
reg opR_wr, opR_cc, opF_wr, op_gie, |
opA_rd, opB_rd; |
wire [9:0] opFl; |
wire [10:0] opFl; |
reg [6:0] r_opF; |
wire [8:0] opF; |
wire op_ce; |
`ifdef NG_PRECLEAR_BUS |
reg op_clear_bus; |
`endif |
`ifdef NG_ILLEGAL_INSTRUCTION |
reg op_illegal; |
`endif |
|
|
|
// |
// |
// PIPELINE STAGE #4 :: ALU / Memory |
231,12 → 279,15
wire alu_valid; |
wire set_cond; |
reg alu_wr, alF_wr, alu_gie; |
`ifdef NG_ILLEGAL_INSTRUCTION |
reg alu_illegal; |
`endif |
|
|
|
wire mem_ce, mem_stalled; |
wire mem_valid, mem_ack, mem_stall, |
mem_cyc, mem_stb, mem_we; |
wire mem_valid, mem_ack, mem_stall, mem_err, bus_err, |
mem_cyc_gbl, mem_cyc_lcl, mem_stb_gbl, mem_stb_lcl, mem_we; |
wire [4:0] mem_wreg; |
|
wire mem_busy, mem_rdbusy; |
274,7 → 325,10
assign dcd_stalled = (dcdvalid)&&( |
(op_stall) |
||((dcdA_stall)||(dcdB_stall)||(dcdF_stall)) |
||((opvalid)&&((op_wr_pc)||(opR_cc)))); |
`ifndef NG_BRANCH_DELAY_SLOT |
||((opvalid_mem)&&(op_wr_pc)) |
`endif |
||((opvalid_mem)&&(opR_cc))); |
// |
// PIPELINE STAGE #3 :: Read Operands |
// Calculate stall conditions |
285,9 → 339,25
// |
// PIPELINE STAGE #4 :: ALU / Memory |
// Calculate stall conditions |
assign alu_stall = (((~master_ce)||(mem_rdbusy))&&(opvalid_alu)) |
// |
// 1. Basic stall is if the previous stage is valid and the next is |
// busy. |
// 2. Also stall if the prior stage is valid and the master clock enable |
// is de-selected |
// 3. Next case: Stall if we want to start a memory operation and the |
// prior operation will write either the PC or CC registers. |
// 4. Last case: Stall if we would otherwise move a break instruction |
// through the ALU. Break instructions are not allowed through |
// the ALU. |
assign alu_stall = (((~master_ce)||(mem_rdbusy))&&(opvalid_alu)) //Case 1&2 |
`ifdef BEFORE |
||((opvalid)&&(wr_reg_ce)&&(wr_reg_id[4] == op_gie) |
&&(wr_write_pc)||(wr_write_cc)); |
&&((wr_write_pc)||(wr_write_cc)) // Case 3 |
`else |
||((opvalid_mem)&&(wr_reg_ce)&&(wr_reg_id[4] == op_gie) |
&&((wr_write_pc)||(wr_write_cc))) // Case 3 |
`endif |
||((opvalid)&&(op_break)); // Case 4 |
assign alu_ce = (master_ce)&&(opvalid_alu)&&(~alu_stall)&&(~clear_pipeline); |
// |
assign mem_ce = (master_ce)&&(opvalid_mem)&&(~mem_stalled)&&(~clear_pipeline)&&(set_cond); |
311,31 → 381,90
assign pf_ce = (~dcd_stalled); |
prefetch pf(i_clk, i_rst, (pf_ce), pf_pc, gie, |
instruction, instruction_pc, instruction_gie, |
pf_valid, |
pf_cyc, pf_stb, pf_we, pf_addr, |
pf_data, |
pf_ack, pf_stall, i_wb_data); |
pf_valid, pf_illegal, |
pf_cyc, pf_stb, pf_we, pf_addr, pf_data, |
pf_ack, pf_stall, pf_err, i_wb_data); |
`else // Pipe fetch |
pipefetch #(RESET_ADDRESS) |
pf(i_clk, i_rst, new_pc, i_clear_pf_cache, ~dcd_stalled, pf_pc, |
pf(i_clk, i_rst, (new_pc)|(dcd_early_branch_stb), |
i_clear_pf_cache, ~dcd_stalled, |
(new_pc)?pf_pc:dcd_branch_pc, |
instruction, instruction_pc, pf_valid, |
pf_cyc, pf_stb, pf_we, pf_addr, pf_data, |
pf_ack, pf_stall, i_wb_data, |
mem_cyc); |
pf_ack, pf_stall, pf_err, i_wb_data, |
`ifdef NG_PRECLEAR_BUS |
((dcd_clear_bus)&&(dcdvalid)) |
||((op_clear_bus)&&(opvalid)) |
|| |
`endif |
(mem_cyc_lcl)||(mem_cyc_gbl), |
pf_illegal); |
assign instruction_gie = gie; |
`endif |
|
initial dcdvalid = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
dcdvalid <= 1'b0; |
else if (dcd_ce) |
dcdvalid <= (~clear_pipeline); |
else if ((~dcd_stalled)||(clear_pipeline)) |
dcdvalid <= (~clear_pipeline)&&(~dcd_early_branch_stb); |
else if ((~dcd_stalled)||(clear_pipeline)||(dcd_early_branch)) |
dcdvalid <= 1'b0; |
|
`ifdef NG_EARLY_BRANCHING |
always @(posedge i_clk) |
if ((dcd_ce)&&(instruction[27:24]==`CPU_PC_REG)) |
begin |
dcd_early_branch <= 1'b0; |
// First case, a move to PC instruction |
if ((instruction[31:28] == 4'h2) |
&&((instruction_gie) |
||((~instruction[20])&&(~instruction[15]))) |
&&(instruction[23:21]==3'h0)) |
begin |
dcd_early_branch_stb <= 1'b1; |
dcd_early_branch <= 1'b1; |
// r_dcdI <= { {(17){instruction[14]}}, instruction[14:0] }; |
|
end else // Next case, an Add Imm -> PC instruction |
if ((instruction[31:28] == 4'ha) // Add |
&&(~instruction[20]) // Immediate |
&&(instruction[23:21]==3'h0)) // Always |
begin |
dcd_early_branch_stb <= 1'b1; |
dcd_early_branch <= 1'b1; |
// r_dcdI <= { {(4){instruction[19]}}, instruction[19:0] }; |
end else // Next case: load Immediate to PC |
if (instruction[31:28] == 4'h3) |
begin |
dcd_early_branch_stb <= 1'b1; |
dcd_early_branch <= 1'b1; |
// r_dcdI <= { instruction[23:0] }; |
end |
end else |
begin |
if (dcd_ce) dcd_early_branch <= 1'b0; |
dcd_early_branch_stb <= 1'b0; |
end |
always @(posedge i_clk) |
if (dcd_ce) |
begin |
if (instruction[31]) // Add |
dcd_branch_pc <= instruction_pc+32'h01+{ {(12){instruction[19]}}, instruction[19:0] }; |
else if (~instruction[28]) // 4'h2 = MOV |
dcd_branch_pc <= instruction_pc+32'h01+{ {(17){instruction[14]}}, instruction[14:0] }; |
else // if (instruction[28]) // 4'h3 = LDI |
dcd_branch_pc <= instruction_pc+32'h01+{ {(8){instruction[23]}}, instruction[23:0] }; |
end |
`else // NG_EARLY_BRANCHING |
assign dcd_early_branch_stb = 1'b0; |
assign dcd_early_branch = 1'b0; |
assign dcd_branch_pc = 32'h00; |
`endif // NG_EARLY_BRANCHING |
|
always @(posedge i_clk) |
if (dcd_ce) |
begin |
dcd_pc <= instruction_pc+1; |
|
// Record what operation we are doing |
349,7 → 478,17
dcdA_pc <= (instruction[27:24] == `CPU_PC_REG); |
dcdB_pc <= (instruction[19:16] == `CPU_PC_REG); |
dcdM <= 1'b0; |
`ifdef NG_CONDITIONAL_FLAGS |
dcdF_wr <= (instruction[23:21]==3'h0); |
`else |
dcdF_wr <= 1'b1; |
`endif |
`ifdef NG_PRECLEAR_BUS |
dcd_clear_bus <= 1'b0; |
`endif |
`ifdef NG_ILLEGAL_INSTRUCTION |
dcd_illegal <= pf_illegal; |
`endif |
|
// Set the condition under which we do this operation |
// The top four bits are a mask, the bottom four the |
378,8 → 517,15
dcdOp <= 4'h2; |
end |
4'h4: begin // Multiply, LDI[HI|LO], or NOOP/BREAK |
`ifdef NG_CONDITIONAL_FLAGS |
// Don't write flags except for multiplies |
// and then only if they are unconditional |
dcdF_wr <= ((instruction[27:25] != 3'h7) |
&&(instruction[23:21]==3'h0)); |
`else |
// Don't write flags except for multiplies |
dcdF_wr <= (instruction[27:25] != 3'h7); |
`endif |
r_dcdI <= { 8'h00, instruction[15:0] }; |
if (instruction[27:24] == 4'he) |
begin |
388,6 → 534,11
dcdA_rd <= 1'b0; |
dcdB_rd <= 1'b0; |
dcdOp <= 4'h2; |
// Might also be a break. Big |
// instruction set hole here. |
`ifdef NG_ILLEGAL_INSTRUCTION |
dcd_illegal <= (pf_illegal)||(instruction[23:1] != 0); |
`endif |
end else if (instruction[27:24] == 4'hf) |
begin // Load partial immediate(s) |
dcdA_wr <= 1'b1; |
414,6 → 565,9
else |
r_dcdI <= { {(4){instruction[19]}}, instruction[19:0] }; |
dcdM <= 1'b1; // Memory operation |
`ifdef NG_PRECLEAR_BUS |
dcd_clear_bus <= (instruction[23:21]==3'h0); |
`endif |
end |
default: begin |
dcdA_wr <= (instruction[31])||(instruction[31:28]==4'h5); |
432,7 → 586,7
always @(posedge i_clk) |
if (dcd_ce) |
dcd_break <= (instruction[31:0] == 32'h4e000001); |
else |
else if ((clear_pipeline)||(~dcdvalid)) |
dcd_break <= 1'b0; |
|
|
453,28 → 607,21
else if (dcdA_pc) |
r_opA <= upc; |
else if (dcdA_cc) |
r_opA <= { w_opA[31:10], (dcd_gie)?w_uflags:w_iflags }; |
r_opA <= { w_opA[31:11], (dcd_gie)?w_uflags:w_iflags }; |
else |
r_opA <= w_opA; |
end |
wire [31:0] dcdI; |
wire [31:0] dcdI, w_opBnI; |
assign dcdI = { {(8){r_dcdI[23]}}, r_dcdI }; |
assign w_opBnI = (~dcdB_rd) ? 32'h00 |
: (((wr_reg_ce)&&(wr_reg_id == dcdB)) ? wr_reg_vl |
: (((dcdB_pc)&&(dcdB[4] == dcd_gie)) ? dcd_pc |
: ((dcdB_pc) ? upc |
: ((dcdB_cc) ? { w_opB[31:11], (dcd_gie)?w_uflags:w_iflags} |
: regset[dcdB])))); |
always @(posedge i_clk) |
if (op_ce) // &&(dcdvalid)) |
begin |
if (~dcdB_rd) |
r_opB <= dcdI; |
else if ((wr_reg_ce)&&(wr_reg_id == dcdB)) |
r_opB <= wr_reg_vl + dcdI; |
else if ((dcdB_pc)&&(dcdB[4] == dcd_gie)) |
r_opB <= dcd_pc + dcdI; |
else if (dcdB_pc) // & dcdB[4] != dcd_gie thus is user |
r_opB <= upc + dcdI; |
else if (dcdB_cc) |
r_opB <= { w_opB[31:10], (dcd_gie)?w_uflags:w_iflags} + dcdI; |
else |
r_opB <= regset[dcdB] + dcdI; |
end |
r_opB <= w_opBnI + dcdI; |
|
// The logic here has become more complex than it should be, no thanks |
// to Xilinx's Vivado trying to help. The conditions are supposed to |
487,7 → 634,7
// opF. |
always @(posedge i_clk) |
if (op_ce) |
begin // Set the flag condition codes |
begin // Set the flag condition codes, bit order is [3:0]=VNCZ |
case(dcdF[2:0]) |
3'h0: r_opF <= 7'h80; // Always |
3'h1: r_opF <= 7'h11; // Z |
498,9 → 645,12
3'h6: r_opF <= 7'h02; // C |
3'h7: r_opF <= 7'h08; // V |
endcase |
end |
end // Bit order is { (flags_not_used), VNCZ mask, VNCZ value } |
assign opF = { r_opF[6], r_opF[3], r_opF[5], r_opF[1], r_opF[4:0] }; |
|
initial opvalid = 1'b0; |
initial opvalid_alu = 1'b0; |
initial opvalid_mem = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
begin |
518,8 → 668,13
// wait until our operands are valid, then we aren't |
// valid yet until then. |
opvalid<= (~clear_pipeline)&&(dcdvalid)&&(~dcd_stalled); |
`ifdef NG_ILLEGAL_INSTRUCTION |
opvalid_mem <= (dcdM)&&(~dcd_illegal)&&(~clear_pipeline)&&(dcdvalid)&&(~dcd_stalled); |
opvalid_alu <= ((~dcdM)||(dcd_illegal))&&(~clear_pipeline)&&(dcdvalid)&&(~dcd_stalled); |
`else |
opvalid_alu <= (~dcdM)&&(~clear_pipeline)&&(dcdvalid)&&(~dcd_stalled); |
opvalid_mem <= (dcdM)&&(~clear_pipeline)&&(dcdvalid)&&(~dcd_stalled); |
`endif |
end else if ((~op_stall)||(clear_pipeline)) |
begin |
opvalid <= 1'b0; |
543,15 → 698,26
else if ((clear_pipeline)||(~opvalid)) |
op_break <= 1'b0; |
|
`ifdef NG_ILLEGAL_INSTRUCTION |
always @(posedge i_clk) |
if(op_ce) |
op_illegal <= dcd_illegal; |
`endif |
|
always @(posedge i_clk) |
if (op_ce) |
begin |
opn <= dcdOp; // Which ALU operation? |
// opM <= dcdM; // Is this a memory operation? |
`ifdef NG_EARLY_BRANCH |
opF_wr <= (dcdF_wr)&&((~dcdA_cc)||(~dcdA_wr))&&(~dcd_early_branch); |
opR_wr <= (dcdA_wr)&&(~dcd_early_branch); |
`else |
// Will we write the flags/CC Register with our result? |
opF_wr <= (dcdF_wr)&&((~dcdA_cc)||(~dcdA_wr)); |
// Will we be writing our results into a register? |
opR_wr <= dcdA_wr; |
`endif |
// What register will these results be written into? |
opR <= dcdA; |
opR_cc <= (dcdA_wr)&&(dcdA_cc); |
567,7 → 733,15
opB_rd <= dcdB_rd; |
op_pc <= dcd_pc; |
// |
`ifdef NG_EARLY_BRANCHING |
op_wr_pc <= ((dcdA_wr)&&(dcdA_pc)&&(dcdA[4] == dcd_gie))&&(~dcd_early_branch); |
`else |
op_wr_pc <= ((dcdA_wr)&&(dcdA_pc)&&(dcdA[4] == dcd_gie)); |
`endif |
|
`ifdef NG_PRECLEAR_BUS |
op_clear_bus <= dcd_clear_bus; |
`endif |
end |
assign opFl = (op_gie)?(w_uflags):(w_iflags); |
|
583,45 → 757,29
// We'll create a flag here to start our coordination. Once we |
// define this flag to something other than just plain zero, then |
// the stalls will already be in place. |
`define DONT_STALL_ON_OPA |
`ifdef DONT_STALL_ON_OPA |
reg opA_alu; |
always @(posedge i_clk) |
if (op_ce) |
opA_alu <= (opvalid_alu)&&(opR == dcdA)&&(dcdA_rd); |
assign opA = (opA_alu) ? alu_result : r_opA; |
`else |
assign opA = r_opA; |
`endif |
|
assign dcdA_stall = (dcdvalid)&&(dcdA_rd)&&( |
`define DONT_STALL_ON_OPA |
`ifdef DONT_STALL_ON_OPA |
// Skip the requirement on writing back opA |
// Stall on memory, since we'll always need to stall for a |
// memory access anyway |
((opvalid_mem)&&(opR_wr)&&(opR == dcdA))|| |
((opvalid_alu)&&(opF_wr)&&(dcdA_cc))|| |
`else |
((opvalid)&&(opR_wr)&&(opR == dcdA))|| |
`endif |
((mem_busy)&&(~mem_we)&&(mem_wreg == dcdA))); |
`define DONT_STALL_ON_OPB |
`ifdef DONT_STALL_ON_OPB |
|
reg opB_alu; |
always @(posedge i_clk) |
if (op_ce) |
opB_alu <= (opvalid_alu)&&(opR == dcdB)&&(dcdB_rd)&&(dcdI == 0); |
assign opB = (opB_alu) ? alu_result : r_opB; |
`else |
assign opB = r_opB; |
`endif |
assign dcdB_stall = (dcdvalid)&&(dcdB_rd)&&( |
((opvalid)&&(opR_wr)&&(opR == dcdB) |
&&((opvalid_mem)||(dcdI != 0))) |
||((opvalid_alu)&&(opF_wr)&&(dcdB_cc)) |
`ifdef DONT_STALL_ON_OPB |
`endif |
||((mem_busy)&&(~mem_we)&&(mem_wreg == dcdB))); |
assign dcdF_stall = (dcdvalid)&&((~dcdF[3])||(dcdA_cc)||(dcdB_cc)) |
&&(opvalid)&&(opR_cc); |
666,21 → 824,26
|
memops domem(i_clk, i_rst, mem_ce, |
(opn[0]), opB, opA, opR, |
mem_busy, mem_valid, mem_wreg, mem_result, |
mem_cyc, mem_stb, mem_we, mem_addr, mem_data, |
mem_ack, mem_stall, i_wb_data); |
assign mem_rdbusy = ((mem_cyc)&&(~mem_we)); |
mem_busy, mem_valid, bus_err, mem_wreg, mem_result, |
mem_cyc_gbl, mem_cyc_lcl, |
mem_stb_gbl, mem_stb_lcl, |
mem_we, mem_addr, mem_data, |
mem_ack, mem_stall, mem_err, i_wb_data); |
assign mem_rdbusy = (((mem_cyc_gbl)||(mem_cyc_lcl))&&(~mem_we)); |
|
// Either the prefetch or the instruction gets the memory bus, but |
// never both. |
wbarbiter #(32,32) pformem(i_clk, i_rst, |
wbdblpriarb #(32,32) pformem(i_clk, i_rst, |
// Memory access to the arbiter, priority position |
mem_cyc_gbl, mem_cyc_lcl, mem_stb_gbl, mem_stb_lcl, |
mem_we, mem_addr, mem_data, mem_ack, mem_stall, mem_err, |
// Prefetch access to the arbiter |
pf_addr, pf_data, pf_we, pf_stb, pf_cyc, pf_ack, pf_stall, |
// Memory access to the arbiter |
mem_addr, mem_data, mem_we, mem_stb, mem_cyc, mem_ack, mem_stall, |
pf_cyc, 1'b0, pf_stb, 1'b0, pf_we, pf_addr, pf_data, |
pf_ack, pf_stall, pf_err, |
// Common wires, in and out, of the arbiter |
o_wb_addr, o_wb_data, o_wb_we, o_wb_stb, o_wb_cyc, i_wb_ack, |
i_wb_stall); |
o_wb_gbl_cyc, o_wb_lcl_cyc, o_wb_gbl_stb, o_wb_lcl_stb, |
o_wb_we, o_wb_addr, o_wb_data, |
i_wb_ack, i_wb_stall, i_wb_err); |
|
// |
// |
700,7 → 863,11
// bus instruction, so they don't need to be checked here. |
// Further, alu_wr includes (set_cond), so we don't need to |
// check for that here either. |
assign wr_reg_ce = ((alu_wr)&&(alu_valid))||(mem_valid); |
`ifdef NG_ILLEGAL_INSTRUCTION |
assign wr_reg_ce = (~alu_illegal)&&((alu_wr)&&(alu_valid)&&(~clear_pipeline))||(mem_valid); |
`else |
assign wr_reg_ce = ((alu_wr)&&(alu_valid)&&(~clear_pipeline))||(mem_valid); |
`endif |
// Which register shall be written? |
assign wr_reg_id = (alu_wr)?alu_reg:mem_wreg; |
// Are we writing to the CC register? |
719,9 → 886,14
// Write back to the condition codes/flags register ... |
// When shall we write to our flags register? alF_wr already |
// includes the set condition ... |
assign wr_flags_ce = (alF_wr)&&(alu_valid); |
assign w_uflags = { trap, 1'b0, 1'b0, step, 1'b1, sleep, ((wr_flags_ce)&&(alu_gie))?alu_flags:flags }; |
assign w_iflags = { trap, 1'b0, break_en, 1'b0, 1'b0, sleep, ((wr_flags_ce)&&(~alu_gie))?alu_flags:iflags }; |
assign wr_flags_ce = (alF_wr)&&(alu_valid)&&(~clear_pipeline)&&(~alu_illegal); |
`ifdef NG_ILLEGAL_INSTRUCTION |
assign w_uflags = { bus_err_flag, trap, ill_err, 1'b0, step, 1'b1, sleep, ((wr_flags_ce)&&(alu_gie))?alu_flags:flags }; |
assign w_iflags = { bus_err_flag, trap, ill_err, break_en, 1'b0, 1'b0, sleep, ((wr_flags_ce)&&(~alu_gie))?alu_flags:iflags }; |
`else |
assign w_uflags = { bus_err_flag, trap, ill_err, 1'b0, step, 1'b1, sleep, ((wr_flags_ce)&&(alu_gie))?alu_flags:flags }; |
assign w_iflags = { bus_err_flag, trap, ill_err, break_en, 1'b0, 1'b0, sleep, ((wr_flags_ce)&&(~alu_gie))?alu_flags:iflags }; |
`endif |
// What value to write? |
always @(posedge i_clk) |
// If explicitly writing the register itself |
767,7 → 939,18
else if ((i_halt)&&(i_dbg_we) |
&&(i_dbg_reg == { 1'b0, `CPU_CC_REG })) |
break_en <= i_dbg_data[`CPU_BREAK_BIT]; |
assign o_break = ((break_en)||(~op_gie))&&(op_break)&&(~alu_valid)&&(~mem_valid)&&(~mem_busy); |
`ifdef NG_ILLEGAL_INSTRUCTION |
assign o_break = ((break_en)||(~op_gie))&&(op_break) |
&&(~alu_valid)&&(~mem_valid)&&(~mem_busy) |
&&(~clear_pipeline) |
||((~alu_gie)&&(bus_err)) |
||((~alu_gie)&&(alu_valid)&&(alu_illegal)); |
`else |
assign o_break = (((break_en)||(~op_gie))&&(op_break) |
&&(~alu_valid)&&(~mem_valid)&&(~mem_busy) |
&&(~clear_pipeline)) |
||((~alu_gie)&&(bus_err)) |
`endif |
|
|
// The sleep register. Setting the sleep register causes the CPU to |
811,8 → 994,12
// If we are stepping the CPU |
||((master_ce)&&(alu_pc_valid)&&(step)) |
// If we encounter a break instruction, if the break |
// enable isn't not set. |
// enable isn't set. |
||((master_ce)&&(op_break)&&(~break_en)) |
`ifdef NG_ILLEGAL_INSTRUCTION |
// On an illegal instruction |
||((alu_valid)&&(alu_illegal)) |
`endif |
// If we write to the CC register |
||((wr_reg_ce)&&(~wr_reg_vl[`CPU_GIE_BIT]) |
&&(wr_reg_id[4])&&(wr_write_cc)) |
849,6 → 1036,25
else if (w_release_from_interrupt) |
trap <= 1'b0; |
|
`ifdef NG_ILLEGAL_INSTRUCTION |
initial ill_err = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
ill_err <= 1'b0; |
else if (w_release_from_interrupt) |
ill_err <= 1'b0; |
else if ((alu_valid)&&(alu_illegal)&&(gie)) |
ill_err <= 1'b1; |
`endif |
initial bus_err_flag = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
bus_err_flag <= 1'b0; |
else if (w_release_from_interrupt) |
bus_err_flag <= 1'b0; |
else if ((bus_err)&&(alu_gie)) |
bus_err_flag <= 1'b1; |
|
// |
// Write backs to the PC register, and general increments of it |
// We support two: upc and ipc. If the instruction is normal, |
862,7 → 1068,7
always @(posedge i_clk) |
if ((wr_reg_ce)&&(wr_reg_id[4])&&(wr_write_pc)) |
upc <= wr_reg_vl; |
else if ((alu_gie)&&(alu_pc_valid)) |
else if ((alu_gie)&&(alu_pc_valid)&&(~clear_pipeline)) |
upc <= alu_pc; |
else if ((i_halt)&&(i_dbg_we) |
&&(i_dbg_reg == { 1'b1, `CPU_PC_REG })) |
873,7 → 1079,7
ipc <= RESET_ADDRESS; |
else if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_pc)) |
ipc <= wr_reg_vl; |
else if ((~alu_gie)&&(alu_pc_valid)) |
else if ((~alu_gie)&&(alu_pc_valid)&&(~clear_pipeline)) |
ipc <= alu_pc; |
else if ((i_halt)&&(i_dbg_we) |
&&(i_dbg_reg == { 1'b0, `CPU_PC_REG })) |
918,7 → 1124,7
if (i_dbg_reg[3:0] == `CPU_PC_REG) |
o_dbg_reg <= (i_dbg_reg[4])?upc:ipc; |
else if (i_dbg_reg[3:0] == `CPU_CC_REG) |
o_dbg_reg[9:0] <= (i_dbg_reg[4])?w_uflags:w_iflags; |
o_dbg_reg[10:0] <= (i_dbg_reg[4])?w_uflags:w_iflags; |
end |
always @(posedge i_clk) |
o_dbg_cc <= { gie, sleep }; |
925,7 → 1131,7
|
always @(posedge i_clk) |
o_dbg_stall <= (i_halt)&&( |
(pf_cyc)||(mem_cyc)||(mem_busy) |
(pf_cyc)||(mem_cyc_gbl)||(mem_cyc_lcl)||(mem_busy) |
||((~opvalid)&&(~i_rst)) |
||((~dcdvalid)&&(~i_rst))); |
|
/zipsystem.v
82,33 → 82,61
// |
/////////////////////////////////////////////////////////////////////////// |
// |
// While I hate adding delays to any bus access, these two are required |
// While I hate adding delays to any bus access, this next delay is required |
// to make timing close in my Basys-3 design. |
`define DELAY_EXT_BUS |
`define DELAY_DBG_BUS |
// On my previous version, I needed to add a delay to access the external |
// bus. Activate the define below and that delay will be put back into place. |
// This particular version no longer needs the delay in order to run at |
// 100 MHz. Timing indicates I may even run this at 250 MHz without the |
// delay too, so we're doing better. To get rid of this, I placed the logic |
// determining whether or not I was accessing the local system bus one clock |
// earlier, or into the memops.v file. This also required my wishbone bus |
// arbiter to maintain the bus selection as well, so that got updated ... |
// you get the picture. But, the bottom line is that I no longer need this |
// delay. |
// |
// `define DELAY_EXT_BUS // Required no longer!k |
// |
// |
// If space is tight, you might not wish to have your performance and |
// accounting counters, so let's make those optional here |
// Without this flag, Slice LUT count is 3315 (ZipSystem),2432 (ZipCPU) |
// When including counters, |
// Slice LUTs ZipSystem ZipCPU |
// With Counters 3315 2432 |
// Without Counters 2796 2046 |
`define INCLUDE_ACCOUNTING_COUNTERS |
|
// |
// Now, where am I placing all of my peripherals? |
`define PERIPHBASE 32'hc0000000 |
`define INTCTRL 4'h0 // |
`define WATCHDOG 4'h1 // Interrupt generates reset signal |
`define CACHECTRL 4'h2 // Sets IVEC[0] |
`define CTRINT 4'h3 // Sets IVEC[5] |
`define TIMER_A 4'h4 // Sets IVEC[4] |
`define TIMER_B 4'h5 // Sets IVEC[3] |
`define TIMER_C 4'h6 // Sets IVEC[2] |
`define JIFFIES 4'h7 // Sets IVEC[1] |
`define INTCTRL 5'h0 // |
`define WATCHDOG 5'h1 // Interrupt generates reset signal |
// `define CACHECTRL 5'h2 // Sets IVEC[0] |
`define CTRINT 5'h3 // Sets IVEC[5] |
`define TIMER_A 5'h4 // Sets IVEC[4] |
`define TIMER_B 5'h5 // Sets IVEC[3] |
`define TIMER_C 5'h6 // Sets IVEC[2] |
`define JIFFIES 5'h7 // Sets IVEC[1] |
|
`define MSTR_TASK_CTR 4'h8 |
`define MSTR_MSTL_CTR 4'h9 |
`define MSTR_PSTL_CTR 4'ha |
`define MSTR_INST_CTR 4'hb |
`define USER_TASK_CTR 4'hc |
`define USER_MSTL_CTR 4'hd |
`define USER_PSTL_CTR 4'he |
`define USER_INST_CTR 4'hf |
|
`define CACHEBASE 16'hc010 // |
`ifdef INCLUDE_ACCOUNTING_COUNTERS |
`define MSTR_TASK_CTR 5'h08 |
`define MSTR_MSTL_CTR 5'h09 |
`define MSTR_PSTL_CTR 5'h0a |
`define MSTR_INST_CTR 5'h0b |
`define USER_TASK_CTR 5'h0c |
`define USER_MSTL_CTR 5'h0d |
`define USER_PSTL_CTR 5'h0e |
`define USER_INST_CTR 5'h0f |
`endif |
|
// Although I have a hole at 5'h2, the DMA controller requires four wishbone |
// addresses, therefore we place it by itself and expand our address bus |
// width here by another bit. |
`define DMAC 5'h10 |
|
// `define RTC_CLOCK 32'hc0000008 // A global something |
// `define BITREV 32'hc0000003 |
// |
126,7 → 154,7
module zipsystem(i_clk, i_rst, |
// Wishbone master interface from the CPU |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, |
i_wb_ack, i_wb_stall, i_wb_data, |
i_wb_ack, i_wb_stall, i_wb_data, i_wb_err, |
// Incoming interrupts |
i_ext_int, |
// Our one outgoing interrupt |
143,6 → 171,7
output wire [31:0] o_wb_data; |
input i_wb_ack, i_wb_stall; |
input [31:0] i_wb_data; |
input i_wb_err; |
// Incoming interrupts |
input [(EXTERNAL_INTERRUPTS-1):0] i_ext_int; |
// Outgoing interrupt |
161,11 → 190,13
wire [31:0] dbg_idata, dbg_odata; |
reg dbg_ack; |
`ifdef DELAY_DBG_BUS |
wire dbg_err, no_dbg_err; |
assign dbg_err = 1'b0; |
busdelay #(1,32) wbdelay(i_clk, |
i_dbg_cyc, i_dbg_stb, i_dbg_we, i_dbg_addr, i_dbg_data, |
o_dbg_ack, o_dbg_stall, o_dbg_data, |
o_dbg_ack, o_dbg_stall, o_dbg_data, no_dbg_err, |
dbg_cyc, dbg_stb, dbg_we, dbg_addr, dbg_idata, |
dbg_ack, dbg_stall, dbg_odata); |
dbg_ack, dbg_stall, dbg_odata, dbg_err); |
`else |
assign dbg_cyc = i_dbg_cyc; |
assign dbg_stb = i_dbg_stb; |
181,10 → 212,10
// |
// |
wire sys_cyc, sys_stb, sys_we; |
wire [3:0] sys_addr; |
wire [4:0] sys_addr; |
wire [31:0] cpu_addr; |
wire [31:0] sys_data; |
// wire sys_ack, sys_stall; |
wire sys_ack, sys_stall; |
|
// |
// The external debug interface |
214,7 → 245,7
if (i_rst) |
cmd_halt <= (START_HALTED == 1)? 1'b1 : 1'b0; |
else if (dbg_cmd_write) |
cmd_halt <= dbg_idata[10]; |
cmd_halt <= ((dbg_idata[10])||(dbg_idata[8])); |
else if ((cmd_step)||(cpu_break)) |
cmd_halt <= 1'b1; |
|
235,7 → 266,7
cmd_addr <= dbg_idata[5:0]; |
|
wire cpu_reset; |
assign cpu_reset = (cmd_reset)||(wdt_reset); |
assign cpu_reset = (cmd_reset)||(wdt_reset)||(i_rst); |
|
wire cpu_halt, cpu_dbg_stall; |
assign cpu_halt = (i_rst)||((cmd_halt)&&(~cmd_step)); |
280,26 → 311,13
wdt_ack, wdt_stall, wdt_data, wdt_reset); |
|
// |
// The Flash Cache, a pre-read cache to memory that can be used to |
// create a fast memory access area |
// Position two ... unclaimed / unused |
// |
wire cache_int; |
wire [31:0] cache_data; |
wire cache_stb, cache_ack, cache_stall; |
wire fc_cyc, fc_stb, fc_we, fc_ack, fc_stall; |
wire [31:0] fc_data, fc_addr; |
flashcache #(10) manualcache(i_clk, |
sys_cyc, cache_stb, |
((sys_stb)&&(sys_addr == `CACHECTRL)), |
sys_we, cpu_addr[9:0], sys_data, |
cache_ack, cache_stall, cache_data, |
// Need the outgoing CACHE wishbone bus |
fc_cyc, fc_stb, fc_we, fc_addr, fc_data, |
fc_ack, fc_stall, ext_idata, |
// Cache interrupt, for upon completion |
cache_int); |
|
|
wire cache_stall; |
assign cache_stall = 1'b0; |
reg cache_ack; |
always @(posedge i_clk) |
cache_ack <= (sys_cyc)&&(sys_stb)&&(sys_addr == 5'h02); |
// Counters -- for performance measurement and accounting |
// |
// Here's the stuff we'll be counting .... |
306,6 → 324,7
// |
wire cpu_op_stall, cpu_pf_stall, cpu_i_count; |
|
`ifdef INCLUDE_ACCOUNTING_COUNTERS |
// |
// The master counters will, in general, not be reset. They'll be used |
// for an overall counter. |
313,7 → 332,7
// Master task counter |
wire mtc_ack, mtc_stall, mtc_int; |
wire [31:0] mtc_data; |
zipcounter mtask_ctr(i_clk, (~cmd_halt), sys_cyc, |
zipcounter mtask_ctr(i_clk, (~cpu_halt), sys_cyc, |
(sys_stb)&&(sys_addr == `MSTR_TASK_CTR), |
sys_we, sys_data, |
mtc_ack, mtc_stall, mtc_data, mtc_int); |
349,7 → 368,7
// User task counter |
wire utc_ack, utc_stall, utc_int; |
wire [31:0] utc_data; |
zipcounter utask_ctr(i_clk,(~cmd_halt), sys_cyc, |
zipcounter utask_ctr(i_clk,(~cpu_halt), sys_cyc, |
(sys_stb)&&(sys_addr == `USER_TASK_CTR), |
sys_we, sys_data, |
utc_ack, utc_stall, utc_data, utc_int); |
393,9 → 412,54
: ((uoc_ack) ? uoc_data |
: ((upc_ack) ? upc_data |
: uic_data))))))); |
`else // INCLUDE_ACCOUNTING_COUNTERS |
reg actr_ack; |
wire actr_stall; |
wire [31:0] actr_data; |
assign actr_stall = 1'b0; |
assign actr_data = 32'h0000; |
|
wire utc_int, uoc_int, upc_int, uic_int; |
wire mtc_int, moc_int, mpc_int, mic_int; |
assign mtc_int = 1'b0; |
assign moc_int = 1'b0; |
assign mpc_int = 1'b0; |
assign mic_int = 1'b0; |
assign utc_int = 1'b0; |
assign uoc_int = 1'b0; |
assign upc_int = 1'b0; |
assign uic_int = 1'b0; |
|
always @(posedge i_clk) |
actr_ack <= (sys_stb)&&(sys_addr[4:3] == 2'b01); |
`endif // INCLUDE_ACCOUNTING_COUNTERS |
|
// |
// The DMA Controller |
// |
wire dmac_int, dmac_stb, dc_err; |
wire [31:0] dmac_data; |
wire dmac_ack, dmac_stall; |
wire dc_cyc, dc_stb, dc_we, dc_ack, dc_stall; |
wire [31:0] dc_data, dc_addr; |
wire cpu_gbl_cyc; |
assign dmac_stb = (sys_stb)&&(sys_addr[4]); |
wbdmac dma_controller(i_clk, |
sys_cyc, dmac_stb, sys_we, |
sys_addr[1:0], sys_data, |
dmac_ack, dmac_stall, dmac_data, |
// Need the outgoing DMAC wishbone bus |
dc_cyc, dc_stb, dc_we, dc_addr, dc_data, |
dc_ack, dc_stall, ext_idata, dc_err, |
// External device interrupts |
{ {(32-EXTERNAL_INTERRUPTS){1'b0}}, i_ext_int }, |
// DMAC interrupt, for upon completion |
dmac_int, |
// Whether or not the CPU wants the bus |
cpu_gbl_cyc); |
|
|
`ifdef INCLUDE_ACCOUNTING_COUNTERS |
// |
// Counter Interrupt controller |
// |
410,8 → 474,20
sys_data, ctri_data, ctri_vector, ctri_int); |
always @(posedge i_clk) |
ctri_ack <= ctri_sel; |
assign ctri_stall = 1'b0; |
`else // INCLUDE_ACCOUNTING_COUNTERS |
reg ctri_ack; |
wire ctri_stall, ctri_int; |
wire [31:0] ctri_data; |
assign ctri_stall = 1'b0; |
assign ctri_data = 32'h0000; |
assign ctri_int = 1'b0; |
|
always @(posedge i_clk) |
ctri_ack <= (sys_cyc)&&(sys_stb)&&(sys_addr == `CTRINT); |
`endif // INCLUDE_ACCOUNTING_COUNTERS |
|
|
// |
// Timer A |
// |
458,12 → 534,14
wire pic_interrupt; |
wire [(5+EXTERNAL_INTERRUPTS):0] int_vector; |
assign int_vector = { i_ext_int, ctri_int, tma_int, tmb_int, tmc_int, |
jif_int, cache_int }; |
jif_int, dmac_int }; |
icontrol #(6+EXTERNAL_INTERRUPTS) pic(i_clk, cpu_reset, |
(sys_cyc)&&(sys_stb)&&(sys_we) |
&&(sys_addr==`INTCTRL), |
sys_data, pic_data, |
int_vector, pic_interrupt); |
wire pic_stall; |
assign pic_stall = 1'b0; |
reg pic_ack; |
always @(posedge i_clk) |
pic_ack <= (sys_cyc)&&(sys_stb)&&(sys_addr == `INTCTRL); |
471,9 → 549,10
// |
// The CPU itself |
// |
wire cpu_cyc, cpu_stb, cpu_we, cpu_dbg_we; |
wire cpu_gbl_stb, cpu_lcl_cyc, cpu_lcl_stb, |
cpu_we, cpu_dbg_we; |
wire [31:0] cpu_data, wb_data; |
wire cpu_ack, cpu_stall; |
wire cpu_ack, cpu_stall, cpu_err; |
wire [31:0] cpu_dbg_data; |
assign cpu_dbg_we = ((dbg_cyc)&&(dbg_stb)&&(~cmd_addr[5]) |
&&(dbg_we)&&(dbg_addr)); |
481,20 → 560,39
cpu_halt, cmd_clear_pf_cache, cmd_addr[4:0], cpu_dbg_we, |
dbg_idata, cpu_dbg_stall, cpu_dbg_data, |
cpu_dbg_cc, cpu_break, |
cpu_cyc, cpu_stb, cpu_we, cpu_addr, cpu_data, |
cpu_gbl_cyc, cpu_gbl_stb, |
cpu_lcl_cyc, cpu_lcl_stb, |
cpu_we, cpu_addr, cpu_data, |
cpu_ack, cpu_stall, wb_data, |
cpu_err, |
cpu_op_stall, cpu_pf_stall, cpu_i_count); |
|
// Now, arbitrate the bus ... first for the local peripherals |
assign sys_cyc = (cpu_cyc)||((cpu_halt)&&(~cpu_dbg_stall)&&(dbg_cyc)); |
assign sys_stb = (cpu_cyc) |
? ((cpu_stb)&&(cpu_addr[31:4] == 28'hc000000)) |
// For the debugger to have access to the local system bus, the |
// following must be true: |
// (dbg_cyc) The debugger must request the bus |
// (~cpu_lcl_cyc) The CPU cannot be using it (CPU gets priority) |
// (dbg_addr) The debugger must be requesting its data |
// register, not just the control register |
// and one of two other things. Either |
// ((cpu_halt)&&(~cpu_dbg_stall)) the CPU is completely halted, |
// or |
// (~cmd_addr[5]) we are trying to read a CPU register |
// while in motion. Let the user beware that, |
// by not waiting for the CPU to fully halt, |
// his results may not be what he expects. |
// |
wire sys_dbg_cyc = ((dbg_cyc)&&(~cpu_lcl_cyc)&&(dbg_addr)) |
&&(((cpu_halt)&&(~cpu_dbg_stall)) |
||(~cmd_addr[5])); |
assign sys_cyc = (cpu_lcl_cyc)||(sys_dbg_cyc); |
assign sys_stb = (cpu_lcl_cyc) |
? (cpu_lcl_stb) |
: ((dbg_stb)&&(dbg_addr)&&(cmd_addr[5])); |
|
assign sys_we = (cpu_cyc) ? cpu_we : dbg_we; |
assign sys_addr= (cpu_cyc) ? cpu_addr[3:0] : cmd_addr[3:0]; |
assign sys_data= (cpu_cyc) ? cpu_data : dbg_idata; |
assign cache_stb=((cpu_cyc)&&(cpu_stb)&&(cpu_addr[31:16]==`CACHEBASE)); |
assign sys_we = (cpu_lcl_cyc) ? cpu_we : dbg_we; |
assign sys_addr= (cpu_lcl_cyc) ? cpu_addr[4:0] : cmd_addr[4:0]; |
assign sys_data= (cpu_lcl_cyc) ? cpu_data : dbg_idata; |
|
// Return debug response values |
assign dbg_odata = (~dbg_addr)?cmd_data |
501,11 → 599,8
:((~cmd_addr[5])?cpu_dbg_data : wb_data); |
initial dbg_ack = 1'b0; |
always @(posedge i_clk) |
dbg_ack <= (dbg_cyc)&&(dbg_stb)&& |
((~dbg_addr)||((cpu_halt)&&(~cpu_dbg_stall))); |
assign dbg_stall=(dbg_addr)&&(dbg_cyc) |
&&((cpu_cyc)||((cmd_halt)&&(~cpu_halt)) |
||(cpu_dbg_stall)); |
dbg_ack <= (dbg_cyc)&&(~dbg_stall); |
assign dbg_stall=(dbg_cyc)&&((~sys_dbg_cyc)||(sys_stall))&&(dbg_addr); |
|
// Now for the external wishbone bus |
// Need to arbitrate between the flash cache and the CPU |
512,24 → 607,24
// The way this works, though, the CPU will stall once the flash |
// cache gets access to the bus--the CPU will be stuck until the |
// flash cache is finished with the bus. |
wire ext_cyc, ext_stb, ext_we; |
wire cpu_ext_ack, cpu_ext_stall, ext_ack, ext_stall; |
wire ext_cyc, ext_stb, ext_we, ext_err; |
wire cpu_ext_ack, cpu_ext_stall, ext_ack, ext_stall, |
cpu_ext_err; |
wire [31:0] ext_addr, ext_odata; |
wbarbiter #(32,32) flashvcpu(i_clk, i_rst, |
fc_addr, fc_data, fc_we, fc_stb, fc_cyc, |
fc_ack, fc_stall, |
cpu_addr, cpu_data, cpu_we, |
((cpu_stb)&&(~sys_stb)&&(~cache_stb)), |
cpu_cyc, cpu_ext_ack, cpu_ext_stall, |
ext_addr, ext_odata, ext_we, ext_stb, |
ext_cyc, ext_ack, ext_stall); |
wbpriarbiter #(32,32) dmacvcpu(i_clk, i_rst, |
cpu_gbl_cyc, cpu_gbl_stb, cpu_we, cpu_addr, cpu_data, |
cpu_ext_ack, cpu_ext_stall, cpu_ext_err, |
dc_cyc, dc_stb, dc_we, dc_addr, dc_data, |
dc_ack, dc_stall, dc_err, |
ext_cyc, ext_stb, ext_we, ext_addr, ext_odata, |
ext_ack, ext_stall, ext_err); |
|
`ifdef DELAY_EXT_BUS |
busdelay #(32,32) extbus(i_clk, |
ext_cyc, ext_stb, ext_we, ext_addr, ext_odata, |
ext_ack, ext_stall, ext_idata, |
ext_ack, ext_stall, ext_idata, ext_err, |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, |
i_wb_ack, i_wb_stall, i_wb_data); |
i_wb_ack, i_wb_stall, i_wb_data, i_wb_err); |
`else |
assign o_wb_cyc = ext_cyc; |
assign o_wb_stb = ext_stb; |
539,6 → 634,7
assign ext_ack = i_wb_ack; |
assign ext_stall = i_wb_stall; |
assign ext_idata = i_wb_data; |
assign ext_err = i_wb_err; |
`endif |
|
wire tmr_ack; |
549,14 → 645,17
:(tmc_ack ? tmc_data |
:jif_data)); |
assign wb_data = (tmr_ack|wdt_ack)?((tmr_ack)?tmr_data:wdt_data) |
:((actr_ack|cache_ack)?((actr_ack)?actr_data:cache_data) |
:((actr_ack|dmac_ack)?((actr_ack)?actr_data:dmac_data) |
:((pic_ack|ctri_ack)?((pic_ack)?pic_data:ctri_data) |
:(ext_idata))); |
|
assign cpu_stall = (tma_stall | tmb_stall | tmc_stall | jif_stall |
| wdt_stall | cache_stall |
| cpu_ext_stall); |
assign cpu_ack = (tmr_ack|wdt_ack|cache_ack|cpu_ext_ack|ctri_ack|actr_ack|pic_ack); |
assign sys_stall = (tma_stall | tmb_stall | tmc_stall | jif_stall |
| wdt_stall | ctri_stall | actr_stall |
| pic_stall | dmac_stall | cache_stall); |
assign cpu_stall = (sys_stall)|(cpu_ext_stall); |
assign sys_ack = (tmr_ack|wdt_ack|ctri_ack|actr_ack|pic_ack|dmac_ack|cache_ack); |
assign cpu_ack = (sys_ack)||(cpu_ext_ack); |
assign cpu_err = (cpu_ext_err)&&(cpu_gbl_cyc); |
|
assign o_ext_int = (cmd_halt) && (~cpu_stall); |
|
/Makefile
38,13 → 38,14
PRPHD:= peripherals |
AUXD := aux |
VSRC := zipsystem.v \ |
$(PRPHD)/flashcache.v $(PRPHD)/icontrol.v \ |
$(PRPHD)/wbdmac.v $(PRPHD)/icontrol.v \ |
$(PRPHD)/zipcounter.v $(PRPHD)/zipjiffies.v \ |
$(PRPHD)/ziptimer.v $(PRPHD)/ziptrap.v \ |
$(CORED)/zipcpu.v $(CORED)/cpuops.v \ |
$(CORED)/pipefetch.v $(CORED)/prefetch.v \ |
$(CORED)/memops.v \ |
$(AUXD)/busdelay.v $(AUXD)/wbarbiter.v |
$(AUXD)/busdelay.v $(AUXD)/wbarbiter.v \ |
$(AUXD)/wbdblpriarb.v $(AUXD)/wbpriarbiter.v |
|
VOBJ := obj_dir |
|
/aux/wbpriarbiter.v
0,0 → 1,118
/////////////////////////////////////////////////////////////////////////// |
// |
// Filename: wbpriarbiter.v |
// |
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core |
// |
// Purpose: This is a priority bus arbiter. It allows two separate wishbone |
// masters to connect to the same bus, while also guaranteeing |
// that one master can have the bus with no delay any time the |
// other master is not using the bus. The goal is to eliminate |
// the combinatorial logic required in the other wishbone |
// arbiter, while still guarateeing access time for the priority |
// channel. |
// |
// The core logic works like this: |
// |
// 1. When no one requests the bus, 'A' is granted the bus and |
// guaranteed that any access will go right through. |
// 2. If 'B' requests the bus (asserts cyc), and the bus is idle, |
// then 'B' will be granted the bus. |
// 3. Bus grants last as long as the 'cyc' line is high. |
// 4. Once 'cyc' is dropped, the bus returns to 'A' as the owner. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Tecnology, LLC |
// |
/////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
/////////////////////////////////////////////////////////////////////////// |
// |
module wbpriarbiter(i_clk, i_rst, |
// Bus A |
i_a_cyc, i_a_stb, i_a_we, i_a_adr, i_a_dat, o_a_ack, o_a_stall, o_a_err, |
// Bus B |
i_b_cyc, i_b_stb, i_b_we, i_b_adr, i_b_dat, o_b_ack, o_b_stall, o_b_err, |
// Both buses |
o_cyc, o_stb, o_we, o_adr, o_dat, i_ack, i_stall, i_err); |
parameter DW=32, AW=32; |
// Wishbone doesn't use an i_ce signal. While it could, they dislike |
// what it would (might) do to the synchronous reset signal, i_rst. |
input i_clk, i_rst; |
// Bus A |
input i_a_cyc, i_a_stb, i_a_we; |
input [(AW-1):0] i_a_adr; |
input [(DW-1):0] i_a_dat; |
output wire o_a_ack, o_a_stall, o_a_err; |
// Bus B |
input i_b_cyc, i_b_stb, i_b_we; |
input [(AW-1):0] i_b_adr; |
input [(DW-1):0] i_b_dat; |
output wire o_b_ack, o_b_stall, o_b_err; |
// |
output wire o_cyc, o_stb, o_we; |
output wire [(AW-1):0] o_adr; |
output wire [(DW-1):0] o_dat; |
input i_ack, i_stall, i_err; |
|
// Go high immediately (new cycle) if ... |
// Previous cycle was low and *someone* is requesting a bus cycle |
// Go low immadiately if ... |
// We were just high and the owner no longer wants the bus |
// WISHBONE Spec recommends no logic between a FF and the o_cyc |
// This violates that spec. (Rec 3.15, p35) |
assign o_cyc = (r_a_owner) ? i_a_cyc : i_b_cyc; |
reg r_a_owner; |
initial r_a_owner = 1'b1; |
always @(posedge i_clk) |
if (~i_b_cyc) |
r_a_owner <= 1'b1; |
else if ((i_b_cyc)&&(~i_a_cyc)) |
r_a_owner <= 1'b0; |
|
|
// Realistically, if neither master owns the bus, the output is a |
// don't care. Thus we trigger off whether or not 'A' owns the bus. |
// If 'B' owns it all we care is that 'A' does not. Likewise, if |
// neither owns the bus than the values on the various lines are |
// irrelevant. |
assign o_stb = (r_a_owner) ? i_a_stb : i_b_stb; |
assign o_we = (r_a_owner) ? i_a_we : i_b_we; |
assign o_adr = (r_a_owner) ? i_a_adr : i_b_adr; |
assign o_dat = (r_a_owner) ? i_a_dat : i_b_dat; |
|
// We cannot allow the return acknowledgement to ever go high if |
// the master in question does not own the bus. Hence we force it |
// low if the particular master doesn't own the bus. |
assign o_a_ack = ( r_a_owner) ? i_ack : 1'b0; |
assign o_b_ack = (~r_a_owner) ? i_ack : 1'b0; |
|
// Stall must be asserted on the same cycle the input master asserts |
// the bus, if the bus isn't granted to him. |
assign o_a_stall = ( r_a_owner) ? i_stall : 1'b1; |
assign o_b_stall = (~r_a_owner) ? i_stall : 1'b1; |
|
// |
// |
assign o_a_err = ( r_a_owner) ? i_err : 1'b0; |
assign o_b_err = (~r_a_owner) ? i_err : 1'b0; |
|
endmodule |
|
/aux/wbarbiter.v
57,11 → 57,11
`define WBA_ALTERNATING |
module wbarbiter(i_clk, i_rst, |
// Bus A |
i_a_adr, i_a_dat, i_a_we, i_a_stb, i_a_cyc, o_a_ack, o_a_stall, |
i_a_adr, i_a_dat, i_a_we, i_a_stb, i_a_cyc, o_a_ack, o_a_stall, o_a_err, |
// Bus B |
i_b_adr, i_b_dat, i_b_we, i_b_stb, i_b_cyc, o_b_ack, o_b_stall, |
i_b_adr, i_b_dat, i_b_we, i_b_stb, i_b_cyc, o_b_ack, o_b_stall, o_b_err, |
// Both buses |
o_adr, o_dat, o_we, o_stb, o_cyc, i_ack, i_stall); |
o_adr, o_dat, o_we, o_stb, o_cyc, i_ack, i_stall, i_err); |
// 18 bits will address one GB, 4 bytes at a time. |
// 19 bits will allow the ability to address things other than just |
// the 1GB of memory we are expecting. |
73,11 → 73,12
input [(DW-1):0] i_a_dat, i_b_dat; |
input i_a_we, i_a_stb, i_a_cyc; |
input i_b_we, i_b_stb, i_b_cyc; |
output wire o_a_ack, o_b_ack, o_a_stall, o_b_stall; |
output wire o_a_ack, o_b_ack, o_a_stall, o_b_stall, |
o_a_err, o_b_err; |
output wire [(AW-1):0] o_adr; |
output wire [(DW-1):0] o_dat; |
output wire o_we, o_stb, o_cyc; |
input i_ack, i_stall; |
input i_ack, i_stall, i_err; |
|
// All the fancy stuff here is done with the three primary signals: |
// o_cyc |
113,6 → 114,11
wire w_a_owner, w_b_owner; |
`ifdef WBA_ALTERNATING |
reg r_a_last_owner; |
// Stall must be asserted on the same cycle the input master asserts |
// the bus, if the bus isn't granted to him. |
assign o_a_stall = (w_a_owner) ? i_stall : 1'b1; |
assign o_b_stall = (w_b_owner) ? i_stall : 1'b1; |
|
`endif |
always @(posedge i_clk) |
if (i_rst) |
169,10 → 175,10
assign o_a_ack = (w_a_owner) ? i_ack : 1'b0; |
assign o_b_ack = (w_b_owner) ? i_ack : 1'b0; |
|
// Stall must be asserted on the same cycle the input master asserts |
// the bus, if the bus isn't granted to him. |
assign o_a_stall = (w_a_owner) ? i_stall : 1'b1; |
assign o_b_stall = (w_b_owner) ? i_stall : 1'b1; |
// |
// |
assign o_a_err = (w_a_owner) ? i_err : 1'b0; |
assign o_b_err = (w_b_owner) ? i_err : 1'b0; |
|
endmodule |
|
/aux/busdelay.v
44,10 → 44,10
module busdelay(i_clk, |
// The input bus |
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, |
o_wb_ack, o_wb_stall, o_wb_data, |
o_wb_ack, o_wb_stall, o_wb_data, o_wb_err, |
// The delayed bus |
o_dly_cyc, o_dly_stb, o_dly_we, o_dly_addr, o_dly_data, |
i_dly_ack, i_dly_stall, i_dly_data); |
i_dly_ack, i_dly_stall, i_dly_data, i_dly_err); |
parameter AW=32, DW=32; |
input i_clk; |
// Input/master bus |
57,6 → 57,7
output reg o_wb_ack; |
output wire o_wb_stall; |
output reg [(DW-1):0] o_wb_data; |
output wire o_wb_err; |
// Delayed bus |
output reg o_dly_cyc, o_dly_stb, o_dly_we; |
output reg [(AW-1):0] o_dly_addr; |
64,6 → 65,7
input i_dly_ack; |
input i_dly_stall; |
input [(DW-1):0] i_dly_data; |
input i_dly_err; |
|
initial o_dly_cyc = 1'b0; |
initial o_dly_stb = 1'b0; |
91,5 → 93,6
// there's a way to register this? |
// o_wb_stall <= (i_wb_cyc)&&(i_wb_stb) ... or some such? |
assign o_wb_stall = ((i_wb_cyc)&&(o_dly_cyc)&&(i_dly_stall)&&(o_dly_stb)); |
assign o_wb_err = i_dly_err; |
|
endmodule |
/aux/wbdblpriarb.v
0,0 → 1,142
/////////////////////////////////////////////////////////////////////////// |
// |
// Filename: wbdblpriarb.v |
// |
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core |
// |
// Purpose: This should almost be identical to the priority arbiter, save |
// for a simple diffence: it allows the arbitration of two |
// separate wishbone buses. The purpose of this is to push the address |
// resolution back one cycle, so that by the first clock visible to this |
// core, it is known which of two parts of the bus the desired address |
// will be on, save that we still use the arbiter since the underlying |
// device doesn't know that there are two wishbone buses. |
// |
// So at this point we've deviated from the WB spec somewhat, by allowing |
// two CYC and two STB lines. Everything else is the same. This allows |
// (in this case the Zip CPU) to determine whether or not the access |
// will be to the local ZipSystem bus or the external WB bus on the clock |
// before the local bus access, otherwise peripherals were needing to do |
// multiple device selection comparisons/test within a clock: 1) is this |
// for the local or external bus, and 2) is this referencing me as a |
// peripheral. This then caused the ZipCPU to fail all timing specs. |
// By creating the two pairs of lines, CYC_A/STB_A and CYC_B/STB_B, the |
// determination of local vs external can be made one clock earlier |
// where there's still time for the logic, and the second comparison |
// now has time to complete. |
// |
// So let me try to explain this again. To use this arbiter, one of the |
// two masters sets CYC and STB before, only the master determines which |
// of two address spaces the CYC and STB apply to before the clock and |
// only sets the appropriate CYC and STB lines. Then, on the clock tick, |
// the arbiter determines who gets *both* busses, as they both share every |
// other WB line. Thus, only one of CYC_A and CYC_B going out will ever |
// be high at a given time. |
// |
// Hopefully this makes more sense than it sounds. If not, check out the |
// code below for a better explanation. |
// |
// 20150919 -- Added supported for the WB error signal. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Tecnology, LLC |
// |
/////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
/////////////////////////////////////////////////////////////////////////// |
// |
module wbdblpriarb(i_clk, i_rst, |
// Bus A |
i_a_cyc_a,i_a_cyc_b,i_a_stb_a,i_a_stb_b,i_a_we,i_a_adr, i_a_dat, o_a_ack, o_a_stall, o_a_err, |
// Bus B |
i_b_cyc_a,i_b_cyc_b,i_b_stb_a,i_b_stb_b,i_b_we,i_b_adr, i_b_dat, o_b_ack, o_b_stall, o_b_err, |
// Both buses |
o_cyc_a, o_cyc_b, o_stb_a, o_stb_b, o_we, o_adr, o_dat, |
i_ack, i_stall, i_err); |
parameter DW=32, AW=32; |
// Wishbone doesn't use an i_ce signal. While it could, they dislike |
// what it would (might) do to the synchronous reset signal, i_rst. |
input i_clk, i_rst; |
// Bus A |
input i_a_cyc_a, i_a_cyc_b, i_a_stb_a, i_a_stb_b, i_a_we; |
input [(AW-1):0] i_a_adr; |
input [(DW-1):0] i_a_dat; |
output wire o_a_ack, o_a_stall, o_a_err; |
// Bus B |
input i_b_cyc_a, i_b_cyc_b, i_b_stb_a, i_b_stb_b, i_b_we; |
input [(AW-1):0] i_b_adr; |
input [(DW-1):0] i_b_dat; |
output wire o_b_ack, o_b_stall, o_b_err; |
// |
output wire o_cyc_a,o_cyc_b, o_stb_a, o_stb_b, o_we; |
output wire [(AW-1):0] o_adr; |
output wire [(DW-1):0] o_dat; |
input i_ack, i_stall, i_err; |
|
// All of our logic is really captured in the 'r_a_owner' register. |
// This register determines who owns the bus. If no one is requesting |
// the bus, ownership goes to A on the next clock. Otherwise, if B is |
// requesting the bus and A is not, then ownership goes to not A on |
// the next clock. (Sounds simple ...) |
// |
// The CYC logic is here to make certain that, by the time we determine |
// who the bus owner is, we can do so based upon determined criteria. |
assign o_cyc_a = (~i_rst)&&((r_a_owner) ? i_a_cyc_a : i_b_cyc_a); |
assign o_cyc_b = (~i_rst)&&((r_a_owner) ? i_a_cyc_b : i_b_cyc_b); |
reg r_a_owner; |
initial r_a_owner = 1'b1; |
always @(posedge i_clk) |
if (i_rst) |
r_a_owner <= 1'b1; |
else if ((~o_cyc_a)&&(~o_cyc_b)) |
r_a_owner <= ((i_b_cyc_a)||(i_b_cyc_b))? 1'b0:1'b1; |
|
|
// Realistically, if neither master owns the bus, the output is a |
// don't care. Thus we trigger off whether or not 'A' owns the bus. |
// If 'B' owns it all we care is that 'A' does not. Likewise, if |
// neither owns the bus than the values on these various lines are |
// irrelevant. |
assign o_stb_a = (r_a_owner) ? i_a_stb_a : i_b_stb_a; |
assign o_stb_b = (r_a_owner) ? i_a_stb_b : i_b_stb_b; |
assign o_we = (r_a_owner) ? i_a_we : i_b_we; |
assign o_adr = (r_a_owner) ? i_a_adr : i_b_adr; |
assign o_dat = (r_a_owner) ? i_a_dat : i_b_dat; |
|
// We cannot allow the return acknowledgement to ever go high if |
// the master in question does not own the bus. Hence we force it |
// low if the particular master doesn't own the bus. |
assign o_a_ack = ( r_a_owner) ? i_ack : 1'b0; |
assign o_b_ack = (~r_a_owner) ? i_ack : 1'b0; |
|
// Stall must be asserted on the same cycle the input master asserts |
// the bus, if the bus isn't granted to him. |
assign o_a_stall = ( r_a_owner) ? i_stall : 1'b1; |
assign o_b_stall = (~r_a_owner) ? i_stall : 1'b1; |
|
// |
// These error lines will be implemented soon, as soon as the rest of |
// the Zip CPU is ready to support them. |
// |
assign o_a_err = ( r_a_owner) ? i_err : 1'b0; |
assign o_b_err = (~r_a_owner) ? i_err : 1'b0; |
|
endmodule |
|
/peripherals/wbdmac.v
0,0 → 1,329
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// Filename: wbdmac.v |
// |
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core |
// |
// Purpose: Wishbone DMA controller |
// |
// This module is controllable via the wishbone, and moves values from |
// one location in the wishbone address space to another. The amount of |
// memory moved at any given time can be up to 4kB, or equivalently 1kW. |
// Four registers control this DMA controller: a control/status register, |
// a length register, a source WB address and a destination WB address. |
// These register may be read at any time, but they may only be written |
// to when the controller is idle. |
// |
// The meanings of three of the setup registers should be self explanatory: |
// - The length register controls the total number of words to |
// transfer. |
// - The source address register controls where the DMA controller |
// reads from. This address may or may not be incremented |
// after each read, depending upon the setting in the |
// control/status register. |
// - The destination address register, which controls where the DMA |
// controller writes to. This address may or may not be |
// incremented after each write, also depending upon the |
// setting in the control/status register. |
// |
// It is the control/status register, at local address zero, that needs |
// more definition: |
// |
// Bits: |
// 31 R Write protect If this is set to one, it means the |
// write protect bit is set and the controller |
// is therefore idle. This bit will be set upon |
// completing any transfer. |
// 30 R Error. The controller stopped mid-transfer |
// after receiving a bus error. |
// 29 R/W inc_s_n If set to one, the source address |
// will not increment from one read to the next. |
// 28 R/W inc_d_n If set to one, the destination address |
// will not increment from one write to the next. |
// 27 R Always 0 |
// 26..16 R nread Indicates how many words have been read, |
// and not necessarily written (yet). This |
// combined with the cfg_len parameter should tell |
// exactly where the controller is at mid-transfer. |
// 27..16 W WriteProtect When a 12'h3db is written to these |
// bits, the write protect bit will be cleared. |
// |
// 15 R/W on_dev_trigger When set to '1', the controller will |
// wait for an external interrupt before starting. |
// 14..10 R/W device_id This determines which external interrupt |
// will trigger a transfer. |
// 9..0 R/W transfer_len How many bytes to transfer at one time. |
// The minimum transfer length is one, while zero |
// is mapped to a transfer length of 1kW. |
// |
// |
// To use this, follow this checklist: |
// 1. Wait for any prior DMA operation to complete |
// (Read address 0, wait 'till either top bit is set or cfg_len==0) |
// 2. Write values into length, source and destination address. |
// (writei(3, &vals) should be sufficient for this.) |
// 3. Enable the DMAC interrupt in whatever interrupt controller is present |
// on the system. |
// 4. Write the final start command to the setup/control/status register: |
// Set inc_s_n, inc_d_n, on_dev_trigger, dev_trigger, |
// appropriately for your task |
// Write 12'h3db to the upper word. |
// Set the lower word to either all zeros, or a smaller transfer |
// length if desired. |
// 5. wait() for the interrupt and the operation to complete. |
// Prior to completion, number of items successfully transferred |
// be read from the length register. If the internal buffer is |
// being used, then you can read how much has been read into that |
// buffer by reading from bits 25..16 of this control/status |
// register. |
// |
// Creator: Dan Gisselquist |
// Gisselquist Tecnology, LLC |
// |
// Copyright: 2015 |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
/////////////////////////////////////////////////////////////////////////// |
// |
// |
module wbdmac(i_clk, |
i_swb_cyc, i_swb_stb, i_swb_we, i_swb_addr, i_swb_data, |
o_swb_ack, o_swb_stall, o_swb_data, |
o_mwb_cyc, o_mwb_stb, o_mwb_we, o_mwb_addr, o_mwb_data, |
i_mwb_ack, i_mwb_stall, i_mwb_data, i_mwb_err, |
i_dev_ints, |
o_interrupt, |
i_other_busmaster_requests_bus); |
parameter LGMEMLEN = 10, DW=32, LGDV=5; |
input i_clk; |
// Slave/control wishbone inputs |
input i_swb_cyc, i_swb_stb, i_swb_we; |
input [1:0] i_swb_addr; |
input [(DW-1):0] i_swb_data; |
// Slave/control wishbone outputs |
output reg o_swb_ack; |
output wire o_swb_stall; |
output reg [(DW-1):0] o_swb_data; |
// Master/DMA wishbone control |
output reg o_mwb_cyc, o_mwb_stb, o_mwb_we; |
output reg [(DW-1):0] o_mwb_addr, o_mwb_data; |
// Master/DMA wishbone responses from the bus |
input i_mwb_ack, i_mwb_stall; |
input [(DW-1):0] i_mwb_data; |
input i_mwb_err; |
// The interrupt device interrupt lines |
input [(DW-1):0] i_dev_ints; |
// An interrupt to be set upon completion |
output reg o_interrupt; |
// Need to release the bus for a higher priority user |
input i_other_busmaster_requests_bus; |
|
|
reg cfg_wp; // Write protect |
reg cfg_err; |
reg [(DW-1):0] cfg_waddr, cfg_raddr, cfg_len; |
reg [(LGMEMLEN-1):0] cfg_blocklen_sub_one; |
reg cfg_incs, cfg_incd; |
reg [(LGDV-1):0] cfg_dev_trigger; |
reg cfg_on_dev_trigger; |
|
// Single block operations: We'll read, then write, up to a single |
// memory block here. |
|
reg [(DW-1):0] dma_mem [0:(((1<<LGMEMLEN))-1)]; |
reg [(LGMEMLEN):0] nread, nwritten, nacks; |
wire [(DW-1):0] bus_nacks; |
assign bus_nacks = { {(DW-LGMEMLEN-1){1'b0}}, nacks }; |
|
initial o_interrupt = 1'b0; |
initial o_mwb_cyc = 1'b0; |
initial cfg_err = 1'b0; |
initial cfg_wp = 1'b0; |
initial cfg_len = 32'h00; |
initial cfg_blocklen_sub_one = {(LGMEMLEN){1'b1}}; |
initial cfg_on_dev_trigger = 1'b0; |
always @(posedge i_clk) |
if ((o_mwb_cyc)&&(o_mwb_we)) // Write cycle |
begin |
if ((o_mwb_stb)&&(~i_mwb_stall)) |
begin |
nwritten <= nwritten+1; |
if ((nwritten == nread-1) |
||(i_other_busmaster_requests_bus)) |
// Wishbone interruptus |
o_mwb_stb <= 1'b0; |
else if (cfg_incd) begin |
o_mwb_addr <= o_mwb_addr + 1; |
cfg_waddr <= cfg_waddr + 1; |
end |
// o_mwb_data <= dma_mem[nwritten + 1]; |
end |
|
if (i_mwb_err) |
begin |
o_mwb_cyc <= 1'b0; |
cfg_err <= 1'b1; |
cfg_len <= 0; |
nread <= 0; |
end else if (i_mwb_ack) |
begin |
nacks <= nacks+1; |
cfg_len <= cfg_len - 1; |
if ((nacks+1 == nwritten)&&(~o_mwb_stb)) |
begin |
o_mwb_cyc <= 1'b0; |
nread <= 0; |
o_interrupt <= (cfg_len == 1); |
// Turn write protect back on |
cfg_wp <= 1'b1; |
end |
end |
end else if ((o_mwb_cyc)&&(~o_mwb_we)) // Read cycle |
begin |
if ((o_mwb_stb)&&(~i_mwb_stall)) |
begin |
nacks <= nacks+1; |
if ((nacks == {1'b0, cfg_blocklen_sub_one}) |
||(bus_nacks <= cfg_len-1) |
||(i_other_busmaster_requests_bus)) |
// Wishbone interruptus |
o_mwb_stb <= 1'b0; |
else if (cfg_incs) begin |
o_mwb_addr <= o_mwb_addr + 1; |
end |
end |
|
if (i_mwb_err) |
begin |
o_mwb_cyc <= 1'b0; |
cfg_err <= 1'b1; |
cfg_len <= 0; |
nread <= 0; |
end else if (i_mwb_ack) |
begin |
nread <= nread+1; |
if ((~o_mwb_stb)&&(nread+1 == nacks)) |
begin |
o_mwb_cyc <= 1'b0; |
nacks <= 0; |
end |
if (cfg_incs) |
cfg_raddr <= cfg_raddr + 1; |
// dma_mem[nread[(LGMEMLEN-1):0]] <= i_mwb_data; |
end |
end else if ((~o_mwb_cyc)&&(nread > 0)&&(~cfg_err)) |
begin // Initiate/continue a write cycle |
o_mwb_cyc <= 1'b1; |
o_mwb_stb <= 1'b1; |
o_mwb_we <= 1'b1; |
// o_mwb_data <= dma_mem[0]; |
o_mwb_addr <= cfg_waddr; |
// nwritten <= 0; // Can't set to zero, in case we're |
// nacks <= 0; // continuing a cycle |
end else if ((~o_mwb_cyc)&&(nread == 0)&&(cfg_len>0)&&(~cfg_wp) |
&&((~cfg_on_dev_trigger) |
||(i_dev_ints[cfg_dev_trigger]))) |
begin // Initiate a read cycle |
o_mwb_cyc <= 1'b1; |
o_mwb_stb <= 1'b1; |
o_mwb_we <= 1'b0; |
o_mwb_addr<= cfg_raddr; |
nwritten <= 0; |
nread <= 0; |
nacks <= 0; |
end else begin |
o_mwb_cyc <= 1'b0; |
o_mwb_stb <= 1'b0; |
o_mwb_we <= 1'b0; |
o_mwb_addr <= cfg_raddr; |
o_interrupt<= 1'b0; |
nwritten <= 0; |
if ((i_swb_cyc)&&(i_swb_stb)&&(i_swb_we)) |
begin |
cfg_wp <= 1'b1; |
case(i_swb_addr) |
2'b00: begin |
cfg_wp <= (i_swb_data[27:16]!=12'hfed); |
cfg_blocklen_sub_one |
<= i_swb_data[(LGMEMLEN-1):0]-1; |
cfg_dev_trigger <= i_swb_data[14:10]; |
cfg_on_dev_trigger <= i_swb_data[15]; |
cfg_incs <= ~i_swb_data[29]; |
cfg_incd <= ~i_swb_data[28]; |
cfg_err <= 1'b0; |
end |
2'b01: cfg_len <= i_swb_data; |
2'b10: cfg_raddr <= i_swb_data; |
2'b11: cfg_waddr <= i_swb_data; |
endcase |
end |
end |
|
// |
// This is tricky. In order for Vivado to consider dma_mem to be a |
// proper memory, it must have a simple address fed into it. Hence |
// the read_address (rdaddr) register. The problem is that this |
// register must always be one greater than the address we actually |
// want to read from, unless we are idling. So ... the math is touchy. |
// |
reg [(LGMEMLEN-1):0] rdaddr; |
always @(posedge i_clk) |
if ((o_mwb_cyc)&&(o_mwb_we)&&(o_mwb_stb)&&(~i_mwb_stall)) |
// This would be the normal advance, save that we are |
// already one ahead of nwritten |
rdaddr <= rdaddr + 1; // {{(LGMEMLEN-1){1'b0}},1}; |
else if ((~o_mwb_cyc)&&(nread > 0)&&(~cfg_err)) |
// Here's where we do our extra advance |
rdaddr <= nwritten[(LGMEMLEN-1):0]+1; |
else if ((~o_mwb_cyc)||(~o_mwb_we)) |
rdaddr <= nwritten[(LGMEMLEN-1):0]; |
always @(posedge i_clk) |
if ((~o_mwb_cyc)||((o_mwb_we)&&(o_mwb_stb)&&(~i_mwb_stall))) |
o_mwb_data <= dma_mem[rdaddr]; |
always @(posedge i_clk) |
if ((o_mwb_cyc)&&(~o_mwb_we)&&(i_mwb_ack)) |
dma_mem[nread[(LGMEMLEN-1):0]] <= i_mwb_data; |
|
always @(posedge i_clk) |
casez(i_swb_addr) |
2'b00: o_swb_data <= { ~cfg_wp, cfg_err, |
~cfg_incs, ~cfg_incd, |
1'b0, nread, |
cfg_on_dev_trigger, cfg_dev_trigger, |
cfg_blocklen_sub_one |
}; |
2'b01: o_swb_data <= cfg_len; |
2'b10: o_swb_data <= cfg_raddr; |
2'b11: o_swb_data <= cfg_waddr; |
endcase |
|
always @(posedge i_clk) |
if ((i_swb_cyc)&&(i_swb_stb)) // &&(~i_swb_we)) |
o_swb_ack <= 1'b1; |
// else if ((i_swb_cyc)&&(i_swb_stb)&&(i_swb_we)&&(~o_mwb_cyc)&&(nread == 0)) |
else |
o_swb_ack <= 1'b0; |
|
assign o_swb_stall = 1'b0; |
|
endmodule |
|
/peripherals/zipport.v
0,0 → 1,129
/////////////////////////////////////////////////////////////////////////// |
// |
// Filename: zipport.v |
// |
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core |
// |
// Purpose: A communications port for passing data between CPU's in a |
// multi-cpu system. |
// |
// Example: Imagine a signal processing system with many 'CPUs' working |
// together. Each communicates its outputs to the next CPU. |
// Writes to this port will send values to the next port over, |
// and reads from this port will read such values. |
// |
// These ports are ripe for adding FIFO's too, but the port |
// itself doesn't offer a FIFO. Worse, as written, the port |
// offers no flags to a FIFO to know when to read the next |
// value. |
// |
// Note: There are other means of message passing, this is just |
// one--perhaps not even the best one. |
// |
// Interface: |
// 2-bits of control: |
// top bit means valid data that hasn't been read. |
// next bit means data has not been read, but instead has been |
// lost |
// These statuses are cleared upon any read. |
// 30-bits of data. |
// |
// External CPU: |
// Can read/write to the port. |
// Writes to the port take place by setting i_port_v and strobing i_port_w. |
// Writes from this port to other ports take place the same way. |
// Reads/writes to/from this port by the CPU take place via the single |
// wishbone address. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Tecnology, LLC |
// |
/////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
/////////////////////////////////////////////////////////////////////////// |
// |
module zipport(i_clk, |
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_data, |
o_wb_ack, o_wb_stall, o_wb_data, |
i_port_w, i_port_v, |
o_port_w, o_port_v, |
o_int_full, o_int_ovflw); |
parameter BW = 32, DW = (BW-2); |
input i_clk; |
// Wishbone inputs |
input i_wb_cyc, i_wb_stb, i_wb_we; |
input [(BW-1):0] i_wb_data; |
// Wishbone outputs |
output reg o_wb_ack; |
output wire o_wb_stall; |
output wire [(BW-1):0] o_wb_data; |
// Port connections |
input i_port_w; // Write strobe |
input [(DW-1):0] i_port_v; // Value received |
output reg o_port_w; // Writing strobe |
output reg [(BW-1):0] o_port_v; // Value being sent |
// Interrupt line |
output wire o_int_full, o_int_ovflw; |
|
wire wb_write, wb_read, wb_cycle; |
assign wb_write = (i_wb_cyc)&&(i_wb_stb)&&(i_wb_we); |
assign wb_read = (i_wb_cyc)&&(i_wb_stb)&&(~i_wb_we); |
assign wb_cycle = (i_wb_cyc)&&(i_wb_stb); |
|
reg r_valid, r_ovflw; |
reg [(DW-1):0] r_data; |
|
initial r_valid = 1'b0; |
initial r_ovflw = 1'b0; |
always @(posedge i_clk) |
if (wb_write) |
begin |
o_port_w <= 1'b1; |
o_port_v <= i_wb_data; |
end else |
o_port_w <= 1'b0; |
|
always @(posedge i_clk) |
if (i_port_w) |
r_valid <= 1'b1; |
else if (wb_read) |
r_valid <= 1'b0; |
|
always @(posedge i_clk) |
if (i_port_w) |
r_ovflw <= (r_valid); |
else if (wb_read) |
r_ovflw <= 1'b0; |
|
always @(posedge i_clk) |
if (i_port_w) |
r_data <= i_port_v; |
|
assign o_int_full = r_valid; |
assign o_int_ovflw= r_ovflw; |
|
initial o_wb_ack = 1'b0; |
always @(posedge i_clk) |
o_wb_ack <= wb_cycle; |
assign o_wb_stall = 1'b0; |
|
assign o_wb_data = { r_valid, r_ovflw, {(BW-2-DW){1'b0}}, r_data }; |
|
endmodule |