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 3 to Rev 2
- ↔ Reverse comparison
Rev 3 → Rev 2
/core/memops.v
1,39 → 1,3
/////////////////////////////////////////////////////////////////////////// |
// |
// Filename: memops.v |
// |
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core |
// |
// Purpose: A memory unit to support a CPU. |
// |
// In the interests of code simplicity, this memory operator is |
// susceptible to unknown results should a new command be sent to it |
// before it completes the last one. Unpredictable results might then |
// occurr. |
// |
// 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 memops(i_clk, i_rst, i_stb, |
i_op, i_addr, i_data, i_oreg, |
o_busy, o_valid, o_wreg, o_result, |
62,18 → 26,14
if (i_rst) |
o_wb_cyc <= 1'b0; |
else if (o_wb_cyc) |
begin |
o_wb_stb <= (o_wb_stb)&&(i_wb_stall); |
o_wb_cyc <= (~i_wb_ack); |
else if (i_stb) // New memory operation |
end else if (i_stb) // New memory operation |
begin |
// Grab the wishbone |
o_wb_cyc <= 1'b1; |
always @(posedge i_clk) |
if (o_wb_cyc) |
o_wb_stb <= (o_wb_stb)&&(i_wb_stall); |
else |
o_wb_stb <= i_stb; // Grab wishbone on new operation |
always @(posedge i_clk) |
if (i_stb) |
begin |
o_wb_stb <= 1'b1; |
o_wb_we <= i_op; |
o_wb_data <= i_data; |
o_wb_addr <= i_addr; |
81,13 → 41,13
|
initial o_valid = 1'b0; |
always @(posedge i_clk) |
o_valid <= (o_wb_cyc)&&(i_wb_ack)&&(~o_wb_we); |
o_valid <= (o_wb_cyc)&&(i_wb_ack)&&(~o_wb_we)&&(~i_rst); |
assign o_busy = o_wb_cyc; |
|
always @(posedge i_clk) |
if (i_stb) |
if ((i_stb)&&(~o_wb_cyc)) |
o_wreg <= i_oreg; |
always @(posedge i_clk) |
if (i_wb_ack) |
if ((o_wb_cyc)&&(i_wb_ack)) |
o_result <= i_wb_data; |
endmodule |
/core/pipefetch.v
1,18 → 1,10
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: pipefetch.v |
// Filename: regset.v |
// |
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core |
// |
// Purpose: Keeping our CPU fed with instructions, at one per clock and |
// with no stalls, can be quite a chore. Worse, the Wishbone |
// takes a couple of cycles just to read one instruction from |
// the bus. However, if we use pipeline accesses to the Wishbone |
// bus, then we can read more and faster. Further, if we cache |
// these results so that we have them before we need them, then |
// we have a chance of keeping our CPU from stalling. Those are |
// the purposes of this instruction fetch module: 1) Pipeline |
// wishbone accesses, and 2) an instruction cache. |
// Purpose: |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Tecnology, LLC |
40,10 → 32,8
module pipefetch(i_clk, i_rst, i_new_pc, 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); |
parameter RESET_ADDRESS=32'h0010_0000, |
LGCACHELEN = 6, CACHELEN=(1<<LGCACHELEN), |
BUSW=32; |
i_wb_ack, i_wb_stall, i_wb_data); |
parameter LGCACHELEN = 6, CACHELEN=(1<<LGCACHELEN), BUSW=32; |
input i_clk, i_rst, i_new_pc, i_stall_n; |
input [(BUSW-1):0] i_pc; |
output reg [(BUSW-1):0] o_i; |
57,9 → 47,6
// |
input i_wb_ack, i_wb_stall; |
input [(BUSW-1):0] i_wb_data; |
// |
// Is the (data) memory unit also requesting access to the bus? |
input i_wb_request; |
|
// Fixed bus outputs: we read from the bus only, never write. |
// Thus the output data is ... irrelevant and don't care. We set it |
67,11 → 54,12
assign o_wb_we = 1'b0; |
assign o_wb_data = 0; |
|
reg [(BUSW-1):0] r_cache_base; |
reg [(BUSW-1):0] r_cache_base, r_cache_offset; |
reg [(LGCACHELEN):0] r_nvalid, r_acks_waiting; |
reg [(BUSW-1):0] cache[0:(CACHELEN-1)]; |
|
reg [(LGCACHELEN-1):0] r_cache_offset; |
wire [(LGCACHELEN-1):0] c_cache_offset; |
assign c_cache_offset = r_cache_offset[(LGCACHELEN-1):0]; |
|
reg r_addr_set; |
reg [(BUSW-1):0] r_addr; |
79,34 → 67,21
wire [(BUSW-1):0] bus_nvalid; |
assign bus_nvalid = { {(BUSW-LGCACHELEN-1){1'b0}}, r_nvalid }; |
|
// What are some of the conditions for which we need to restart the |
// cache? |
wire w_pc_out_of_bounds; |
assign w_pc_out_of_bounds = ((i_new_pc)&&((r_nvalid == 0) |
||(i_pc < r_cache_base) |
||(i_pc >= r_cache_base + CACHELEN))); |
wire w_ran_off_end_of_cache; |
assign w_ran_off_end_of_cache =((r_addr_set)&&((r_addr < r_cache_base) |
||(r_addr >= r_cache_base + CACHELEN))); |
wire w_running_out_of_cache; |
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; |
initial r_cache_base = 0; |
always @(posedge i_clk) |
begin |
if (i_rst) |
o_wb_cyc <= 1'b0; |
else if ((~o_wb_cyc)&&(i_new_pc)&&(r_nvalid != 0) |
&&(i_pc > r_cache_base) |
&&(i_pc < r_cache_base + bus_nvalid)) |
begin |
o_wb_cyc <= 1'b0; |
// r_cache_base <= RESET_ADDRESS; |
// end else if ((~o_wb_cyc)&&(i_new_pc)&&(r_nvalid != 0) |
// &&(i_pc >= r_cache_base) |
// &&(i_pc < r_cache_base + bus_nvalid)) |
// begin |
// The new instruction is in our cache, do nothing |
// with the bus here. |
end else if ((o_wb_cyc)&&(w_pc_out_of_bounds)) |
end else if ((o_wb_cyc)&&(i_new_pc)&&(r_nvalid != 0) |
&&((i_pc < r_cache_base) |
||(i_pc >= r_cache_base + CACHELEN))) |
begin |
// We need to abandon our bus action to start over in |
// a new region, setting up a new cache. This may |
115,33 → 90,36
// interested in that result--whatever it might be. |
o_wb_cyc <= 1'b0; |
o_wb_stb <= 1'b0; |
end else if ((~o_wb_cyc)&&(~r_nvalid[LGCACHELEN])&&(~i_wb_request)&&(r_addr_set)) |
begin |
// Restart a bus cycle that was interrupted when the |
// data section wanted access to our bus. |
o_wb_cyc <= 1'b1; |
o_wb_stb <= 1'b1; |
// o_wb_addr <= r_cache_base + bus_nvalid; |
end else if ((~o_wb_cyc)&&( |
(w_pc_out_of_bounds)||(w_ran_off_end_of_cache))) |
((i_new_pc)&&((r_nvalid == 0) |
||(i_pc < r_cache_base) |
||(i_pc >= r_cache_base + CACHELEN))) |
||((r_addr_set)&&((r_addr < r_cache_base) |
||(r_addr >= r_cache_base + CACHELEN))) |
)) |
begin |
// Start a bus transaction |
o_wb_cyc <= 1'b1; |
o_wb_stb <= 1'b1; |
// o_wb_addr <= (i_new_pc) ? i_pc : r_addr; |
// r_nvalid <= 0; |
// r_cache_base <= (i_new_pc) ? i_pc : r_addr; |
// r_cache_offset <= 0; |
end else if ((~o_wb_cyc)&&(w_running_out_of_cache)) |
o_wb_addr <= (i_new_pc) ? i_pc : r_addr; |
r_acks_waiting <= 0; |
r_nvalid <= 0; |
r_cache_base <= (i_new_pc) ? i_pc : r_addr; |
r_cache_offset <= 0; |
end else if ((~o_wb_cyc)&&(r_addr_set) |
&&(r_addr >= r_cache_base |
+ (1<<(LGCACHELEN-2)) |
+ (1<<(LGCACHELEN-1)))) |
begin |
// If we're using the last quarter of the cache, then |
// let's start a bus transaction to extend the cache. |
o_wb_cyc <= 1'b1; |
o_wb_stb <= 1'b1; |
// o_wb_addr <= r_cache_base + (1<<(LGCACHELEN)); |
// r_nvalid <= r_nvalid - (1<<(LGCACHELEN-2)); |
// r_cache_base <= r_cache_base + (1<<(LGCACHELEN-2)); |
// r_cache_offset <= r_cache_offset + (1<<(LGCACHELEN-2)); |
o_wb_addr <= r_cache_base + (1<<(LGCACHELEN)); |
r_acks_waiting <= 0; |
r_nvalid <= r_nvalid - (1<<(LGCACHELEN-2)); |
r_cache_base <= r_cache_base + (1<<(LGCACHELEN-2)); |
r_cache_offset <= r_cache_offset + (1<<(LGCACHELEN-2)); |
end else if (o_wb_cyc) |
begin |
// This handles everything ... but the case where |
148,15 → 126,21
// while reading we need to extend our cache. |
if ((o_wb_stb)&&(~i_wb_stall)) |
begin |
// o_wb_addr <= o_wb_addr + 1; |
if ((o_wb_addr - r_cache_base >= CACHELEN-1) |
||(i_wb_request)) |
o_wb_addr <= o_wb_addr + 1; |
if (o_wb_addr - r_cache_base >= CACHELEN-1) |
o_wb_stb <= 1'b0; |
end |
|
if ((o_wb_stb)&&(~i_wb_stall)&&(~i_wb_ack)) |
r_acks_waiting <= r_acks_waiting |
+ ((i_wb_ack)? 0:1); |
else if ((i_wb_ack)&&((~o_wb_stb)||(i_wb_stall))) |
r_acks_waiting <= r_acks_waiting - 1; |
|
if (i_wb_ack) |
begin |
// r_nvalid <= r_nvalid + 1; |
cache[r_nvalid[(LGCACHELEN-1):0]+c_cache_offset] <= i_wb_data; |
r_nvalid <= r_nvalid + 1; |
if ((r_acks_waiting == 1)&&(~o_wb_stb)) |
o_wb_cyc <= 1'b0; |
end |
163,50 → 147,6
end |
end |
|
always @(posedge i_clk) |
if ((~o_wb_cyc)&&( |
(w_pc_out_of_bounds)||(w_ran_off_end_of_cache))) |
r_nvalid <= 0; |
else if ((~o_wb_cyc)&&(w_running_out_of_cache)) |
r_nvalid <= r_nvalid - (1<<(LGCACHELEN-2)); |
else if ((o_wb_cyc)&&(i_wb_ack)) |
r_nvalid <= r_nvalid+1; |
|
always @(posedge i_clk) |
if ((~o_wb_cyc)&&( |
(w_pc_out_of_bounds)||(w_ran_off_end_of_cache))) |
r_cache_base <= (i_new_pc) ? i_pc : r_addr; |
else if ((~o_wb_cyc)&&(w_running_out_of_cache)) |
r_cache_base <= r_cache_base + (1<<(LGCACHELEN-2)); |
|
always @(posedge i_clk) |
if ((~o_wb_cyc)&&( |
(w_pc_out_of_bounds)||(w_ran_off_end_of_cache))) |
r_cache_offset <= 0; |
else if ((~o_wb_cyc)&&(w_running_out_of_cache)) |
r_cache_offset <= r_cache_offset + (1<<(LGCACHELEN-2)); |
|
always @(posedge i_clk) |
if ((~o_wb_cyc)&&((w_pc_out_of_bounds) |
||(w_ran_off_end_of_cache))) |
o_wb_addr <= (i_new_pc) ? i_pc : r_addr; |
else if ((o_wb_cyc)&&(o_wb_stb)&&(~i_wb_stall)) |
o_wb_addr <= o_wb_addr + 1; |
|
initial r_acks_waiting = 0; |
always @(posedge i_clk) |
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); |
else if ((i_wb_ack)&&((~o_wb_stb)||(i_wb_stall))) |
r_acks_waiting <= r_acks_waiting - 1; |
|
always @(posedge i_clk) |
if ((o_wb_cyc)&&(i_wb_ack)) |
cache[r_nvalid[(LGCACHELEN-1):0]+r_cache_offset] |
<= i_wb_data; |
|
initial r_addr_set = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
231,7 → 171,7
|
wire [(LGCACHELEN-1):0] c_rdaddr, c_cache_base; |
assign c_cache_base = r_cache_base[(LGCACHELEN-1):0]; |
assign c_rdaddr = r_addr[(LGCACHELEN-1):0]-c_cache_base+r_cache_offset; |
assign c_rdaddr = r_addr[(LGCACHELEN-1):0]-c_cache_base+c_cache_offset; |
always @(posedge i_clk) |
if (i_stall_n) |
o_i <= cache[c_rdaddr]; |
/core/cpuops.v
57,13 → 57,17
begin |
pre_sign <= (i_a[31]); |
c <= 1'b0; |
casez(i_op) |
4'b?000:{c,o_c } <= {(i_b>i_a),i_a - i_b};// CMP/SUB |
4'b?001: o_c <= i_a & i_b; // BTST/And |
case(i_op) |
4'h0: { c, o_c } <= {(i_b>i_a),i_a - i_b};// CMP (SUB) |
4'h1: o_c <= i_a & i_b; // BTST (And) |
4'h2: o_c <= i_b; // MOV |
// 4'h3: o_c <= { i_b[15:0],i_a[15:6],6'h20};//TRAP |
// 4'h4: o_c <= i_a[15:0] * i_b[15:0]; |
4'h5: o_c <= w_rol_result; // ROL |
4'h6: o_c <= { i_a[31:16], i_b[15:0] }; // LODILO |
4'h7: o_c <= { i_b[15:0], i_a[15:0] }; // LODIHI |
4'h8: { c, o_c } <= {(i_b>i_a), i_a - i_b }; // Sub |
4'h9: o_c <= i_a & i_b; // And |
4'ha: { c, o_c } <= i_a + i_b; // Add |
4'hb: o_c <= i_a | i_b; // Or |
4'hc: o_c <= i_a ^ i_b; // Xor |
/core/zipcpu.v
204,8 → 204,8
wire [31:0] opA_nowait, opB_nowait, opA, opB; |
reg opR_wr, opM, opF_wr, op_gie, |
opA_rd, opB_rd; |
wire [7:0] opFl; |
reg [6:0] r_opF; |
reg [7:0] opFl; |
// reg [6:0] r_opF; |
wire [8:0] opF; |
wire op_ce; |
|
307,12 → 307,10
pf_data, |
pf_ack, pf_stall, i_wb_data); |
`else // Pipe fetch |
pipefetch #(RESET_ADDRESS) |
pf(i_clk, i_rst, new_pc, ~dcd_stalled, pf_pc, |
pipefetch pf(i_clk, i_rst, new_pc, ~dcd_stalled, pf_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, i_wb_data); |
assign instruction_gie = gie; |
`endif |
|
459,7 → 457,6
// these two bits are redundant. Hence the convoluted expression |
// below, arriving at what we finally want in the (now wire net) |
// opF. |
`define NEWCODE |
`ifdef NEWCODE |
always @(posedge i_clk) |
if (op_ce) |
582,7 → 579,7
assign opA = { r_opA[31:8], ((opA_cc[0]) ? |
((opA_cc[1])?w_uflags:w_iflags) : r_opA[7:0]) }; |
assign opB = { r_opB[31:8], ((opB_cc[0]) ? |
((opB_cc[1])?w_uflags:w_iflags) : r_opB[7:0]) }; |
((opA_cc[1])?w_uflags:w_iflags) : r_opB[7:0]) }; |
|
// |
// |
/zipsystem.v
82,13 → 82,6
// |
/////////////////////////////////////////////////////////////////////////// |
// |
// While I hate adding delays to any bus access, these two are required |
// to make timing close in my Basys-3 design. |
`define DELAY_EXT_BUS |
`define DELAY_DBG_BUS |
// |
// |
// 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 |
155,22 → 148,11
wire dbg_cyc, dbg_stb, dbg_we, dbg_addr, dbg_stall; |
wire [31:0] dbg_idata, dbg_odata; |
reg dbg_ack; |
`ifdef DELAY_DBG_BUS |
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, |
dbg_cyc, dbg_stb, dbg_we, dbg_addr, dbg_idata, |
dbg_ack, dbg_stall, dbg_odata); |
`else |
assign dbg_cyc = i_dbg_cyc; |
assign dbg_stb = i_dbg_stb; |
assign dbg_we = i_dbg_we; |
assign dbg_addr = i_dbg_addr; |
assign dbg_idata = i_dbg_data; |
assign o_dbg_ack = dbg_ack; |
assign o_dbg_stall = dbg_stall; |
assign o_dbg_data = dbg_odata; |
`endif |
|
// |
// |
496,22 → 478,11
ext_addr, ext_odata, ext_we, ext_stb, |
ext_cyc, ext_ack, ext_stall); |
|
`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, |
o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data, |
i_wb_ack, i_wb_stall, i_wb_data); |
`else |
assign o_wb_cyc = ext_cyc; |
assign o_wb_stb = ext_stb; |
assign o_wb_we = ext_we; |
assign o_wb_addr = ext_addr; |
assign o_wb_data = ext_odata; |
assign ext_ack = i_wb_ack; |
assign ext_stall = i_wb_stall; |
assign ext_idata = i_wb_data; |
`endif |
|
wire tmr_ack; |
assign tmr_ack = (tma_ack|tmb_ack|tmc_ack|jif_ack); |