URL
https://opencores.org/ocsvn/zipcpu/zipcpu/trunk
Subversion Repositories zipcpu
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 159 to Rev 160
- ↔ Reverse comparison
Rev 159 → Rev 160
/zipcpu/trunk/rtl/core/idecode.v
19,7 → 19,7
// |
/////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// Copyright (C) 2015-2016, 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 |
88,8 → 88,11
wire [(AW-1):0] o_dcd_branch_pc; |
reg o_dcdI, o_dcdIz; |
`ifdef OPT_PIPELINED |
reg r_lock, r_pipe; |
reg r_lock; |
`endif |
`ifdef OPT_PIPELINED_BUS_ACCESS |
reg r_pipe; |
`endif |
|
|
wire [4:0] w_op; |
443,7 → 446,7
// taking place, and it's only valid if the new word is not compressed. |
// |
reg r_valid; |
`ifdef OPT_PIPELINED |
`ifdef OPT_PIPELINED_BUS_ACCESS |
initial r_pipe = 1'b0; |
always @(posedge i_clk) |
if (i_ce) |
/zipcpu/trunk/rtl/core/pipemem.v
160,8 → 160,9
always @(posedge i_clk) |
o_wreg <= fifo_oreg[rdaddr]; |
always @(posedge i_clk) |
if (i_wb_ack) |
o_result <= i_wb_data; |
// if (i_wb_ack) isn't necessary, since o_valid won't be true |
// then either. |
o_result <= i_wb_data; |
|
assign o_pipe_stalled = (cyc) |
&&((i_wb_stall)||((~o_wb_stb_lcl)&&(~o_wb_stb_gbl))); |
/zipcpu/trunk/rtl/core/div.v
12,7 → 12,7
// |
/////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// Copyright (C) 2015-2016, 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 |
44,6 → 44,10
output reg [(BW-1):0] o_quotient; |
output wire [3:0] o_flags; |
|
// r_busy is an internal busy register. It will clear one clock |
// before we are valid, so it can't be o_busy ... |
// |
reg r_busy; |
reg [(2*BW-2):0] r_divisor; |
reg [(BW-1):0] r_dividend; |
wire [(BW):0] diff; // , xdiff[(BW-1):0]; |
50,26 → 54,35
assign diff = r_dividend - r_divisor[(BW-1):0]; |
// assign xdiff= r_dividend - { 1'b0, r_divisor[(BW-1):1] }; |
|
reg r_sign, pre_sign, r_z, r_c; |
reg [(LGBW):0] r_bit; |
reg r_sign, pre_sign, r_z, r_c, last_bit; |
reg [(LGBW-1):0] r_bit; |
|
initial r_busy = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
begin |
r_busy <= 1'b0; |
else if (i_wr) |
r_busy <= 1'b1; |
else if ((last_bit)||(o_err)) |
r_busy <= 1'b0; |
|
initial o_busy = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
o_busy <= 1'b0; |
end else if (i_wr) |
begin |
else if (i_wr) |
o_busy <= 1'b1; |
end else if ((o_busy)&&((r_bit == 6'h0)||(o_err))) |
else if (((last_bit)||(o_err))&&(~r_sign)) |
o_busy <= 1'b0; |
// else busy is zero and stays at zero |
else if (~r_busy) |
o_busy <= 1'b0; |
|
always @(posedge i_clk) |
if ((i_rst)||(i_wr)) |
o_valid <= 1'b0; |
else if (o_busy) |
else if (r_busy) |
begin |
if ((r_bit == 6'h0)||(o_err)) |
if ((last_bit)||(o_err)) |
o_valid <= (o_err)||(~r_sign); |
end else if (r_sign) |
begin |
85,12 → 98,26
else if (o_busy) |
o_err <= (r_divisor == 0); |
|
initial last_bit = 1'b0; |
always @(posedge i_clk) |
if ((i_wr)||(pre_sign)||(i_rst)) |
last_bit <= 1'b0; |
else if (r_busy) |
last_bit <= (r_bit == {{(LGBW-1){1'b0}},1'b1}); |
|
always @(posedge i_clk) |
// if (i_rst) r_busy <= 1'b0; |
// else |
if (i_wr) |
begin |
// |
// Set our values upon an initial command. Here's |
// where we come in and start. |
// |
// r_busy <= 1'b1; |
// |
o_quotient <= 0; |
// r_bit <= { 1'b1, {(LGBW){1'b0}} }; |
r_bit <= { 1'b0, {(LGBW){1'b1}} }; |
r_bit <= {(LGBW){1'b1}}; |
r_divisor <= { i_denominator, {(BW-1){1'b0}} }; |
r_dividend <= i_numerator; |
r_sign <= 1'b0; |
98,22 → 125,49
r_z <= 1'b1; |
end else if (pre_sign) |
begin |
// r_bit <= r_bit - 1; |
r_sign <= ((r_divisor[(2*BW-2)])^(r_dividend[(BW-1)]));; |
// |
// Note that we only come in here, for one clock, if |
// our initial value may have been signed. If we are |
// doing an unsigned divide, we then skip this step. |
// |
r_sign <= ((r_divisor[(2*BW-2)])^(r_dividend[(BW-1)])); |
// Negate our dividend if necessary so that it becomes |
// a magnitude only value |
if (r_dividend[BW-1]) |
r_dividend <= -r_dividend; |
// Do the same with the divisor--rendering it into |
// a magnitude only. |
if (r_divisor[(2*BW-2)]) |
r_divisor[(2*BW-2):(BW-1)] <= -r_divisor[(2*BW-2):(BW-1)]; |
// |
// We only do this stage for a single clock, so go on |
// with the rest of the divide otherwise. |
pre_sign <= 1'b0; |
end else if (o_busy) |
end else if (r_busy) |
begin |
r_bit <= r_bit + {(LGBW+1){1'b1}}; // r_bit = r_bit - 1; |
// While the divide is taking place, we examine each bit |
// in turn here. |
// |
r_bit <= r_bit + {(LGBW){1'b1}}; // r_bit = r_bit - 1; |
r_divisor <= { 1'b0, r_divisor[(2*BW-2):1] }; |
if (|r_divisor[(2*BW-2):(BW)]) |
begin |
end else if (diff[BW]) |
begin |
// |
// diff = r_dividend - r_divisor[(BW-1):0]; |
// |
// If this value was negative, there wasn't |
// enough value in the dividend to support |
// pulling off a bit. We'll move down a bit |
// therefore and try again. |
// |
end else begin |
// |
// Put a '1' into our output accumulator. |
// Subtract the divisor from the dividend, |
// and then move on to the next bit |
// |
r_dividend <= diff[(BW-1):0]; |
o_quotient[r_bit[(LGBW-1):0]] <= 1'b1; |
r_z <= 1'b0; |
127,7 → 181,7
// Set Carry on an exact divide |
wire w_n; |
always @(posedge i_clk) |
r_c <= (o_busy)&&((diff == 0)||(r_dividend == 0)); |
r_c <= (r_busy)&&((diff == 0)||(r_dividend == 0)); |
assign w_n = o_quotient[(BW-1)]; |
|
assign o_flags = { 1'b0, w_n, r_c, r_z }; |
/zipcpu/trunk/rtl/core/zipcpu.v
71,7 → 71,7
// |
/////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// Copyright (C) 2015-2016, 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 |
165,7 → 165,7
input i_dbg_we; |
input [31:0] i_dbg_data; |
// Debug interface -- outputs |
output reg o_dbg_stall; |
output wire o_dbg_stall; |
output reg [31:0] o_dbg_reg; |
output reg [3:0] o_dbg_cc; |
output wire o_break; |
204,7 → 204,7
// (BUS, TRAP,ILL,BREAKEN,STEP,GIE,SLEEP ), V, N, C, Z |
reg [3:0] flags, iflags; |
wire [13:0] w_uflags, w_iflags; |
reg trap, break_en, step, gie, sleep; |
reg trap, break_en, step, gie, sleep, r_halted; |
`ifdef OPT_ILLEGAL_INSTRUCTION |
reg ill_err_u, ill_err_i; |
`else |
284,7 → 284,7
wire [13:0] opFl; |
reg [5:0] r_opF; |
wire [7:0] opF; |
wire op_ce, op_phase, op_pipe; |
wire op_ce, op_phase, op_pipe, op_change_data_ce; |
// Some pipeline control wires |
`ifdef OPT_PIPELINED |
reg opA_alu, opA_mem; |
292,6 → 292,9
`endif |
`ifdef OPT_ILLEGAL_INSTRUCTION |
reg op_illegal; |
`else |
wire op_illegal; |
assign op_illegal = 1'b0; |
`endif |
reg op_break; |
wire op_lock; |
346,6 → 349,12
&&(~mem_rdbusy)&&(~div_busy)&&(~fpu_busy) |
&&(set_cond); |
|
// ALU, DIV, or FPU CE ... equivalent to the OR of all three of these |
wire adf_ce, adf_ce_unconditional; |
assign adf_ce_unconditional = (master_ce)&&(~clear_pipeline)&&(opvalid) |
&&(~opvalid_mem)&&(~mem_rdbusy)&&(~div_busy) |
&&(~fpu_busy); |
assign adf_ce = (adf_ce_unconditional)&&(set_cond); |
|
// |
// |
354,7 → 363,7
// |
wire wr_reg_ce, wr_flags_ce, wr_write_pc, wr_write_cc; |
wire [4:0] wr_reg_id; |
wire [31:0] wr_reg_vl; |
wire [31:0] wr_gpreg_vl, wr_spreg_vl; |
wire w_switch_to_interrupt, w_release_from_interrupt; |
reg [(AW-1):0] upc, ipc; |
|
424,9 → 433,16
||(dcdF_stall) |
); |
assign op_ce = ((dcdvalid)||(dcd_illegal))&&(~op_stall)&&(~clear_pipeline); |
// BUT ... op_ce is too complex for many of the data operations. So |
// let's make their circuit enable code simpler. In particular, if |
// op_ doesn't need to be preserved, we can change it all we want |
// ... right? The clear_pipeline code, for example, really only needs |
// to determine whether opvalid is true. |
assign op_change_data_ce = (~op_stall); |
`else |
assign op_stall = (opvalid)&&(~master_ce); |
assign op_ce = ((dcdvalid)||(dcd_illegal))&&(~clear_pipeline); |
assign op_change_data_ce = 1'b1; |
`endif |
|
// |
450,8 → 466,7
||((opvalid)&&(op_lock)&&(op_lock_stall)) |
||((opvalid)&&(op_break)) |
||(div_busy)||(fpu_busy); |
assign alu_ce = (master_ce)&&((opvalid_alu)||(op_illegal)) |
&&(~alu_stall) |
assign alu_ce = (master_ce)&&(opvalid_alu)&&(~alu_stall) |
&&(~clear_pipeline); |
`else |
assign alu_stall = ((~master_ce)&&(opvalid_alu)) |
713,10 → 728,10
`endif |
|
always @(posedge i_clk) |
if (op_ce) // &&(dcdvalid)) |
if (op_change_data_ce) |
begin |
if ((wr_reg_ce)&&(wr_reg_id == dcdA)) |
r_opA <= wr_reg_vl; |
r_opA <= wr_gpreg_vl; |
else if (dcdA_pc) |
r_opA <= w_pcA_v; |
else if (dcdA_cc) |
729,9 → 744,9
// but for some reason we're stuck here as they became |
// valid. Pick them up now anyway |
// if (((opA_alu)&&(alu_wr))||((opA_mem)&&(mem_valid))) |
// r_opA <= wr_reg_vl; |
// r_opA <= wr_gpreg_vl; |
if ((wr_reg_ce)&&(wr_reg_id == opA_id)&&(opA_rd)) |
r_opA <= wr_reg_vl; |
r_opA <= wr_gpreg_vl; |
`endif |
end |
|
744,7 → 759,7
endgenerate |
|
assign w_opBnI = (~dcdB_rd) ? 32'h00 |
: (((wr_reg_ce)&&(wr_reg_id == dcdB)) ? wr_reg_vl |
: (((wr_reg_ce)&&(wr_reg_id == dcdB)) ? wr_gpreg_vl |
: ((dcdB_pc) ? w_pcB_v |
: ((dcdB_cc) ? { w_cpu_info, w_opB[22:14], // w_opB[31:14], |
(dcdB[4])?w_uflags:w_iflags} |
751,11 → 766,11
: w_opB))); |
|
always @(posedge i_clk) |
if (op_ce) // &&(dcdvalid)) |
if (op_change_data_ce) |
r_opB <= w_opBnI + dcdI; |
`ifdef OPT_PIPELINED |
else if ((wr_reg_ce)&&(opB_id == wr_reg_id)&&(opB_rd)) |
r_opB <= wr_reg_vl; |
r_opB <= wr_gpreg_vl; |
`endif |
|
// The logic here has become more complex than it should be, no thanks |
768,7 → 783,9
// below, arriving at what we finally want in the (now wire net) |
// opF. |
always @(posedge i_clk) |
if (op_ce) |
if (op_ce) // Cannot do op_change_data_ce here since opF depends |
// upon being either correct for a valid op, or correct |
// for the last valid op |
begin // Set the flag condition codes, bit order is [3:0]=VNCZ |
case(dcdF[2:0]) |
3'h0: r_opF <= 6'h00; // Always |
830,7 → 847,7
opvalid_div <= (dcdDV)&&(w_opvalid); |
opvalid_fpu <= (dcdFP)&&(w_opvalid); |
`endif |
end else if ((clear_pipeline)||(alu_ce)||(mem_ce)||(div_ce)||(fpu_ce)) |
end else if ((clear_pipeline)||(adf_ce_unconditional)||(mem_ce)) |
begin |
opvalid <= 1'b0; |
opvalid_alu <= 1'b0; |
873,7 → 890,7
|
initial r_op_lock = 1'b0; |
always @(posedge i_clk) |
if (i_rst) |
if ((i_rst)||(clear_pipeline)) |
r_op_lock <= 1'b0; |
else if (op_ce) |
r_op_lock <= (dcd_lock)&&(~clear_pipeline); |
914,7 → 931,7
end |
|
always @(posedge i_clk) |
if (op_ce) |
if (op_change_data_ce) |
begin |
opn <= dcdOp; // Which ALU operation? |
// opM <= dcdM; // Is this a memory operation? |
936,7 → 953,7
always @(posedge i_clk) |
if ((i_rst)||(clear_pipeline)) |
r_op_phase <= 1'b0; |
else if (op_ce) |
else if (op_change_data_ce) |
r_op_phase <= dcd_phase; |
assign op_phase = r_op_phase; |
`else |
957,7 → 974,7
// the stalls will already be in place. |
`ifdef OPT_PIPELINED |
assign opA = ((wr_reg_ce)&&(wr_reg_id == opA_id)) // &&(opA_rd)) |
? wr_reg_vl : r_opA; |
? wr_gpreg_vl : r_opA; |
`else |
assign opA = r_opA; |
`endif |
980,7 → 997,7
|
`ifdef OPT_PIPELINED |
assign opB = ((wr_reg_ce)&&(wr_reg_id == opB_id)&&(opB_rd)) |
? wr_reg_vl: r_opB; |
? wr_gpreg_vl: r_opB; |
`else |
assign opB = r_opB; |
`endif |
1120,7 → 1137,7
always @(posedge i_clk) |
if (i_rst) |
r_alu_phase <= 1'b0; |
else if ((alu_ce)||(mem_ce)||(div_ce)||(fpu_ce)) |
else if ((adf_ce_unconditional)||(mem_ce)) |
r_alu_phase <= op_phase; |
assign alu_phase = r_alu_phase; |
`else |
1128,7 → 1145,7
`endif |
|
always @(posedge i_clk) |
if ((alu_ce)||(div_ce)||(fpu_ce)) |
if (adf_ce_unconditional) |
alu_reg <= opR; |
else if ((i_halt)&&(i_dbg_we)) |
alu_reg <= i_dbg_reg; |
1139,15 → 1156,16
reg dbgv; |
initial dbgv = 1'b0; |
always @(posedge i_clk) |
dbgv <= (~i_rst)&&(~alu_ce)&&((i_halt)&&(i_dbg_we)); |
dbgv <= (~i_rst)&&(i_halt)&&(i_dbg_we)&&(r_halted); |
reg [31:0] dbg_val; |
always @(posedge i_clk) |
dbg_val <= i_dbg_data; |
always @(posedge i_clk) |
if ((alu_ce)||(mem_ce)) |
if ((adf_ce_unconditional)||(mem_ce)) |
alu_gie <= op_gie; |
always @(posedge i_clk) |
if ((alu_ce)||((master_ce)&&(opvalid_mem)&&(~clear_pipeline) |
if ((adf_ce_unconditional) |
||((master_ce)&&(opvalid_mem)&&(~clear_pipeline) |
&&(~mem_stalled))) |
alu_pc <= op_pc; |
|
1167,11 → 1185,11
always @(posedge i_clk) |
if (i_rst) |
r_alu_pc_valid <= 1'b0; |
else if (alu_ce) // Includes && (~alu_clear_pipeline) |
else if (adf_ce_unconditional)//Includes&&(~alu_clear_pipeline) |
r_alu_pc_valid <= 1'b1; |
else if ((~alu_busy)||(clear_pipeline)) |
else if (((~alu_busy)&&(~div_busy)&&(~fpu_busy))||(clear_pipeline)) |
r_alu_pc_valid <= 1'b0; |
assign alu_pc_valid = (r_alu_pc_valid)&&(~alu_busy); |
assign alu_pc_valid = (r_alu_pc_valid)&&((~alu_busy)&&(~div_busy)&&(~fpu_busy)); |
always @(posedge i_clk) |
if (i_rst) |
mem_pc_valid <= 1'b0; |
1263,12 → 1281,15
// Further, alu_wr includes (set_cond), so we don't need to |
// check for that here either. |
`ifdef OPT_ILLEGAL_INSTRUCTION |
assign wr_reg_ce = (dbgv)||(~alu_illegal)&& |
(((alu_wr)&&(~clear_pipeline) |
&&((alu_valid)||(div_valid)||(fpu_valid))) |
||(mem_valid)); |
assign wr_reg_ce = (dbgv)||(mem_valid) |
||((~clear_pipeline)&&(~alu_illegal) |
&&(((alu_wr)&&(alu_valid)) |
||(div_valid)||(fpu_valid))); |
`else |
assign wr_reg_ce = (dbgv)||((alu_wr)&&(~clear_pipeline))||(mem_valid)||(div_valid)||(fpu_valid); |
assign wr_reg_ce = (dbgv)||(mem_valid) |
||((~clear_pipeline) |
&&(((alu_wr)&&(alu_valid)) |
||(div_valid)||(fpu_valid))); |
`endif |
// Which register shall be written? |
// COULD SIMPLIFY THIS: by adding three bits to these registers, |
1275,19 → 1296,21
// One or PC, one for CC, and one for GIE match |
// Note that the alu_reg is the register to write on a divide or |
// FPU operation. |
assign wr_reg_id = (alu_wr)?alu_reg:mem_wreg; |
assign wr_reg_id = (alu_wr|div_valid|fpu_valid)?alu_reg:mem_wreg; |
// Are we writing to the CC register? |
assign wr_write_cc = (wr_reg_id[3:0] == `CPU_CC_REG); |
// Are we writing to the PC? |
assign wr_write_pc = (wr_reg_id[3:0] == `CPU_PC_REG); |
// What value to write? |
assign wr_reg_vl = ((mem_valid) ? mem_result |
assign wr_gpreg_vl = ((mem_valid) ? mem_result |
:((div_valid|fpu_valid)) |
? ((div_valid) ? div_result:fpu_result) |
:((dbgv) ? dbg_val : alu_result)); |
assign wr_spreg_vl = ((mem_valid) ? mem_result |
:((dbgv) ? dbg_val : alu_result)); |
always @(posedge i_clk) |
if (wr_reg_ce) |
regset[wr_reg_id] <= wr_reg_vl; |
regset[wr_reg_id] <= wr_gpreg_vl; |
|
// |
// Write back to the condition codes/flags register ... |
1308,7 → 1331,7
always @(posedge i_clk) |
// If explicitly writing the register itself |
if ((wr_reg_ce)&&(wr_reg_id[4])&&(wr_write_cc)) |
flags <= wr_reg_vl[3:0]; |
flags <= wr_gpreg_vl[3:0]; |
// Otherwise if we're setting the flags from an ALU operation |
else if ((wr_flags_ce)&&(alu_gie)) |
flags <= (div_valid)?div_flags:((fpu_valid)?fpu_flags |
1316,7 → 1339,7
|
always @(posedge i_clk) |
if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_cc)) |
iflags <= wr_reg_vl[3:0]; |
iflags <= wr_gpreg_vl[3:0]; |
else if ((wr_flags_ce)&&(~alu_gie)) |
iflags <= (div_valid)?div_flags:((fpu_valid)?fpu_flags |
: alu_flags); |
1341,10 → 1364,11
if ((i_rst)||(i_halt)) |
break_en <= 1'b0; |
else if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_cc)) |
break_en <= wr_reg_vl[`CPU_BREAK_BIT]; |
break_en <= wr_spreg_vl[`CPU_BREAK_BIT]; |
`ifdef OPT_ILLEGAL_INSTRUCTION |
assign o_break = ((break_en)||(~op_gie))&&(op_break) |
&&(~alu_valid)&&(~mem_valid)&&(~mem_busy) |
&&(~alu_busy) |
&&(~div_busy)&&(~fpu_busy) |
&&(~clear_pipeline) |
||((~alu_gie)&&(bus_err)) |
1354,6 → 1378,7
`else |
assign o_break = (((break_en)||(~op_gie))&&(op_break) |
&&(~alu_valid)&&(~mem_valid)&&(~mem_busy) |
&&(~alu_busy)&&(~div_busy)&&(~fpu_busy) |
&&(~clear_pipeline)) |
||((~alu_gie)&&(bus_err)) |
||((~alu_gie)&&(div_valid)&&(div_error)) |
1376,23 → 1401,23
// Well ... not quite. Switching to user mode and |
// sleep mode shouold only be possible if the interrupt |
// flag isn't set. |
// Thus: if (i_interrupt)&&(wr_reg_vl[GIE]) |
// Thus: if (i_interrupt)&&(wr_spreg_vl[GIE]) |
// don't set the sleep bit |
// otherwise however it would o.w. be set |
sleep <= (wr_reg_vl[`CPU_SLEEP_BIT]) |
&&((~i_interrupt)||(~wr_reg_vl[`CPU_GIE_BIT])); |
else if ((wr_reg_ce)&&(wr_write_cc)&&(wr_reg_vl[`CPU_GIE_BIT])) |
sleep <= (wr_spreg_vl[`CPU_SLEEP_BIT]) |
&&((~i_interrupt)||(~wr_spreg_vl[`CPU_GIE_BIT])); |
else if ((wr_reg_ce)&&(wr_write_cc)&&(wr_spreg_vl[`CPU_GIE_BIT])) |
// In user mode, however, you can only set the sleep |
// mode while remaining in user mode. You can't switch |
// to sleep mode *and* supervisor mode at the same |
// time, lest you halt the CPU. |
sleep <= wr_reg_vl[`CPU_SLEEP_BIT]; |
sleep <= wr_spreg_vl[`CPU_SLEEP_BIT]; |
|
always @(posedge i_clk) |
if ((i_rst)||(w_switch_to_interrupt)) |
step <= 1'b0; |
else if ((wr_reg_ce)&&(~alu_gie)&&(wr_reg_id[4])&&(wr_write_cc)) |
step <= wr_reg_vl[`CPU_STEP_BIT]; |
step <= wr_spreg_vl[`CPU_STEP_BIT]; |
else if (((alu_pc_valid)||(mem_pc_valid))&&(step)&&(gie)) |
step <= 1'b0; |
|
1419,12 → 1444,12
// |
||(bus_err) |
// If we write to the CC register |
||((wr_reg_ce)&&(~wr_reg_vl[`CPU_GIE_BIT]) |
||((wr_reg_ce)&&(~wr_spreg_vl[`CPU_GIE_BIT]) |
&&(wr_reg_id[4])&&(wr_write_cc)) |
); |
assign w_release_from_interrupt = (~gie)&&(~i_interrupt) |
// Then if we write the CC register |
&&(((wr_reg_ce)&&(wr_reg_vl[`CPU_GIE_BIT]) |
&&(((wr_reg_ce)&&(wr_spreg_vl[`CPU_GIE_BIT]) |
&&(~wr_reg_id[4])&&(wr_write_cc)) |
); |
always @(posedge i_clk) |
1441,11 → 1466,11
trap <= 1'b0; |
else if (w_release_from_interrupt) |
trap <= 1'b0; |
else if ((alu_gie)&&(wr_reg_ce)&&(~wr_reg_vl[`CPU_GIE_BIT]) |
else if ((alu_gie)&&(wr_reg_ce)&&(~wr_spreg_vl[`CPU_GIE_BIT]) |
&&(wr_write_cc)) // &&(wr_reg_id[4]) implied |
trap <= 1'b1; |
else if ((wr_reg_ce)&&(wr_write_cc)&&(wr_reg_id[4])) |
trap <= wr_reg_vl[`CPU_TRAP_BIT]; |
trap <= wr_spreg_vl[`CPU_TRAP_BIT]; |
|
`ifdef OPT_ILLEGAL_INSTRUCTION |
initial ill_err_i = 1'b0; |
1454,7 → 1479,7
ill_err_i <= 1'b0; |
// Only the debug interface can clear this bit |
else if ((dbgv)&&(wr_reg_id == {1'b0, `CPU_CC_REG}) |
&&(~wr_reg_vl[`CPU_ILL_BIT])) |
&&(~wr_spreg_vl[`CPU_ILL_BIT])) |
ill_err_i <= 1'b0; |
else if ((alu_pc_valid)&&(alu_illegal)&&(~alu_gie)) |
ill_err_i <= 1'b1; |
1468,7 → 1493,7
// If the supervisor writes to this register, clearing the |
// bit, then clear it |
else if (((~alu_gie)||(dbgv)) |
&&(wr_reg_ce)&&(~wr_reg_vl[`CPU_ILL_BIT]) |
&&(wr_reg_ce)&&(~wr_spreg_vl[`CPU_ILL_BIT]) |
&&(wr_reg_id[4])&&(wr_write_cc)) |
ill_err_u <= 1'b0; |
else if ((alu_pc_valid)&&(alu_illegal)&&(alu_gie)) |
1484,7 → 1509,7
if (i_rst) |
ibus_err_flag <= 1'b0; |
else if ((dbgv)&&(wr_reg_id == {1'b0, `CPU_CC_REG}) |
&&(~wr_reg_vl[`CPU_BUSERR_BIT])) |
&&(~wr_spreg_vl[`CPU_BUSERR_BIT])) |
ibus_err_flag <= 1'b0; |
else if ((bus_err)&&(~alu_gie)) |
ibus_err_flag <= 1'b1; |
1497,7 → 1522,7
else if (w_release_from_interrupt) |
ubus_err_flag <= 1'b0; |
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce) |
&&(~wr_reg_vl[`CPU_BUSERR_BIT]) |
&&(~wr_spreg_vl[`CPU_BUSERR_BIT]) |
&&(wr_reg_id[4])&&(wr_write_cc)) |
ubus_err_flag <= 1'b0; |
else if ((bus_err)&&(alu_gie)) |
1516,7 → 1541,7
if (i_rst) |
r_idiv_err_flag <= 1'b0; |
else if ((dbgv)&&(wr_reg_id == {1'b0, `CPU_CC_REG}) |
&&(~wr_reg_vl[`CPU_DIVERR_BIT])) |
&&(~wr_spreg_vl[`CPU_DIVERR_BIT])) |
r_idiv_err_flag <= 1'b0; |
else if ((div_error)&&(div_valid)&&(~alu_gie)) |
r_idiv_err_flag <= 1'b1; |
1529,7 → 1554,7
else if (w_release_from_interrupt) |
r_udiv_err_flag <= 1'b0; |
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce) |
&&(~wr_reg_vl[`CPU_DIVERR_BIT]) |
&&(~wr_spreg_vl[`CPU_DIVERR_BIT]) |
&&(wr_reg_id[4])&&(wr_write_cc)) |
r_udiv_err_flag <= 1'b0; |
else if ((div_error)&&(alu_gie)&&(div_valid)) |
1553,7 → 1578,7
if (i_rst) |
r_ifpu_err_flag <= 1'b0; |
else if ((dbgv)&&(wr_reg_id == {1'b0, `CPU_CC_REG}) |
&&(~wr_reg_vl[`CPU_FPUERR_BIT])) |
&&(~wr_spreg_vl[`CPU_FPUERR_BIT])) |
r_ifpu_err_flag <= 1'b0; |
else if ((fpu_error)&&(fpu_valid)&&(~alu_gie)) |
r_ifpu_err_flag <= 1'b1; |
1566,7 → 1591,7
else if (w_release_from_interrupt) |
r_ufpu_err_flag <= 1'b0; |
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce) |
&&(~wr_reg_vl[`CPU_FPUERR_BIT]) |
&&(~wr_spreg_vl[`CPU_FPUERR_BIT]) |
&&(wr_reg_id[4])&&(wr_write_cc)) |
r_ufpu_err_flag <= 1'b0; |
else if ((fpu_error)&&(alu_gie)&&(fpu_valid)) |
1612,7 → 1637,7
// a non-gie instruction? |
always @(posedge i_clk) |
if ((wr_reg_ce)&&(wr_reg_id[4])&&(wr_write_pc)) |
upc <= wr_reg_vl[(AW-1):0]; |
upc <= wr_spreg_vl[(AW-1):0]; |
else if ((alu_gie)&& |
(((alu_pc_valid)&&(~clear_pipeline)) |
||(mem_pc_valid))) |
1622,7 → 1647,7
if (i_rst) |
ipc <= RESET_ADDRESS; |
else if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_pc)) |
ipc <= wr_reg_vl[(AW-1):0]; |
ipc <= wr_spreg_vl[(AW-1):0]; |
else if ((~alu_gie)&& |
(((alu_pc_valid)&&(~clear_pipeline)) |
||(mem_pc_valid))) |
1636,7 → 1661,7
else if (w_release_from_interrupt) |
pf_pc <= upc; |
else if ((wr_reg_ce)&&(wr_reg_id[4] == gie)&&(wr_write_pc)) |
pf_pc <= wr_reg_vl[(AW-1):0]; |
pf_pc <= wr_spreg_vl[(AW-1):0]; |
`ifdef OPT_PIPELINED |
else if ((dcd_early_branch)&&(~clear_pipeline)) |
pf_pc <= dcd_branch_pc + 1; |
1696,10 → 1721,12
o_dbg_cc <= { o_break, bus_err, gie, sleep }; |
|
always @(posedge i_clk) |
o_dbg_stall <= (i_halt)&&( |
r_halted <= (i_halt)&&( |
(pf_cyc)||(mem_cyc_gbl)||(mem_cyc_lcl)||(mem_busy) |
||(alu_busy)||(div_busy)||(fpu_busy) |
||((~opvalid)&&(~i_rst)&&(~dcd_illegal)) |
||((~dcdvalid)&&(~i_rst)&&(~pf_illegal))); |
assign o_dbg_stall = r_halted; |
|
// |
// |
1727,7 → 1754,7
// ||((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] |
gie, sleep, wr_reg_ce, wr_gpreg_vl[4:0] |
/* |
i_rst, master_ce, (new_pc), |
((dcd_early_branch)&&(dcdvalid)), |
/zipcpu/trunk/rtl/zipsystem.v
64,7 → 64,7
// |
/////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// Copyright (C) 2015-2016, 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 |
173,7 → 173,7
parameter RESET_ADDRESS=24'h0100000, ADDRESS_WIDTH=24, |
LGICACHE=10, START_HALTED=1, EXTERNAL_INTERRUPTS=1, |
`ifdef OPT_MULTIPLY |
IMPLEMENT_MPY = 1, |
IMPLEMENT_MPY = `OPT_MULTIPLY, |
`else |
IMPLEMENT_MPY = 0, |
`endif |
369,7 → 369,8
// |
wire wdt_ack, wdt_stall, wdt_reset; |
wire [31:0] wdt_data; |
ziptimer watchdog(i_clk, cpu_reset, ~cmd_halt, |
ziptimer #(32,31,0) |
watchdog(i_clk, cpu_reset, ~cmd_halt, |
sys_cyc, ((sys_stb)&&(sys_addr == `WATCHDOG)), sys_we, |
sys_data, |
wdt_ack, wdt_stall, wdt_data, wdt_reset); |
523,7 → 524,7
wire cpu_gbl_cyc; |
assign dmac_stb = (sys_stb)&&(sys_addr[4]); |
`ifdef INCLUDE_DMA_CONTROLLER |
wbdmac #(AW) dma_controller(i_clk, |
wbdmac #(AW) dma_controller(i_clk, cpu_reset, |
sys_cyc, dmac_stb, sys_we, |
sys_addr[1:0], sys_data, |
dmac_ack, dmac_stall, dmac_data, |
535,12 → 536,6
main_int_vector[14:1], 1'b0 }, |
// DMAC interrupt, for upon completion |
dmac_int); |
// Whether or not the CPU wants the bus, and |
// thus we must kick the DMAC off. |
// However, the logic required for this |
// override never worked well, so here |
// we just don't use it. |
// cpu_gbl_cyc); |
`else |
reg r_dmac_ack; |
always @(posedge i_clk) |
677,8 → 672,15
wire [31:0] cpu_dbg_data; |
assign cpu_dbg_we = ((dbg_cyc)&&(dbg_stb)&&(~cmd_addr[5]) |
&&(dbg_we)&&(dbg_addr)); |
zipcpu #(RESET_ADDRESS,ADDRESS_WIDTH,LGICACHE, IMPLEMENT_MPY, |
IMPLEMENT_DIVIDE, IMPLEMENT_FPU, IMPLEMENT_LOCK) |
zipcpu #( |
.RESET_ADDRESS(RESET_ADDRESS), |
.ADDRESS_WIDTH(ADDRESS_WIDTH), |
.LGICACHE(LGICACHE), |
.IMPLEMENT_MPY(IMPLEMENT_MPY), |
.IMPLEMENT_DIVIDE(IMPLEMENT_DIVIDE), |
.IMPLEMENT_FPU(IMPLEMENT_FPU), |
.IMPLEMENT_LOCK(IMPLEMENT_LOCK) |
) |
thecpu(i_clk, cpu_reset, pic_interrupt, |
cpu_halt, cmd_clear_pf_cache, cmd_addr[4:0], cpu_dbg_we, |
dbg_idata, cpu_dbg_stall, cpu_dbg_data, |
726,7 → 728,7
:((~cmd_addr[5])?cpu_dbg_data : wb_data); |
initial dbg_ack = 1'b0; |
always @(posedge i_clk) |
dbg_ack <= (dbg_cyc)&&(~dbg_stall); |
dbg_ack <= (dbg_cyc)&&(dbg_stb)&&(~dbg_stall); |
assign dbg_stall=(dbg_cyc)&&((~sys_dbg_cyc)||(sys_stall))&&(dbg_addr); |
|
// Now for the external wishbone bus |
/zipcpu/trunk/rtl/peripherals/wbdmac.v
81,12 → 81,9
// Creator: Dan Gisselquist |
// Gisselquist Technology, LLC |
// |
// Copyright: 2015 |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// Copyright (C) 2015-2016, 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 |
105,7 → 102,15
/////////////////////////////////////////////////////////////////////////// |
// |
// |
module wbdmac(i_clk, |
`define DMA_IDLE 3'b000 |
`define DMA_WAIT 3'b001 |
`define DMA_READ_REQ 3'b010 |
`define DMA_READ_ACK 3'b011 |
`define DMA_PRE_WRITE 3'b100 |
`define DMA_WRITE_REQ 3'b101 |
`define DMA_WRITE_ACK 3'b110 |
|
module wbdmac(i_clk, i_rst, |
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, |
114,7 → 119,7
o_interrupt); |
parameter ADDRESS_WIDTH=32, LGMEMLEN = 10, |
DW=32, LGDV=5,AW=ADDRESS_WIDTH; |
input i_clk; |
input i_clk, i_rst; |
// Slave/control wishbone inputs |
input i_swb_cyc, i_swb_stb, i_swb_we; |
input [1:0] i_swb_addr; |
124,7 → 129,7
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 wire o_mwb_cyc, o_mwb_stb, o_mwb_we; |
output reg [(AW-1):0] o_mwb_addr; |
output reg [(DW-1):0] o_mwb_data; |
// Master/DMA wishbone responses from the bus |
145,8 → 150,8
// |
|
|
reg cfg_wp; // Write protect |
reg cfg_err; |
reg [2:0] dma_state; |
reg cfg_err, cfg_len_nonzero; |
reg [(AW-1):0] cfg_waddr, cfg_raddr, cfg_len; |
reg [(LGMEMLEN-1):0] cfg_blocklen_sub_one; |
reg cfg_incs, cfg_incd; |
157,134 → 162,253
// memory block here. |
|
reg [(DW-1):0] dma_mem [0:(((1<<LGMEMLEN))-1)]; |
reg [(LGMEMLEN):0] nread, nwritten, nacks; |
wire [(AW-1):0] bus_nacks; |
assign bus_nacks = { {(AW-LGMEMLEN-1){1'b0}}, nacks }; |
reg [(LGMEMLEN):0] nread, nwritten, nwacks, nracks; |
wire [(AW-1):0] bus_nracks; |
assign bus_nracks = { {(AW-LGMEMLEN-1){1'b0}}, nracks }; |
|
reg last_read_request, last_read_ack, |
last_write_request, last_write_ack; |
reg trigger, abort; |
|
initial dma_state = `DMA_IDLE; |
initial o_interrupt = 1'b0; |
initial o_mwb_cyc = 1'b0; |
initial cfg_err = 1'b0; |
initial cfg_wp = 1'b0; |
initial cfg_len = {(AW){1'b0}}; |
initial cfg_blocklen_sub_one = {(LGMEMLEN){1'b1}}; |
initial cfg_on_dev_trigger = 1'b0; |
initial cfg_len_nonzero = 1'b0; |
always @(posedge i_clk) |
if ((o_mwb_cyc)&&(o_mwb_we)) // Write cycle |
case(dma_state) |
`DMA_IDLE: begin |
o_mwb_addr <= cfg_raddr; |
nwritten <= 0; |
nread <= 0; |
nracks <= 0; |
nwacks <= 0; |
cfg_len_nonzero <= (|cfg_len); |
|
// When the slave wishbone writes, and we are in this |
// (ready) configuration, then allow the DMA to be controlled |
// and thus to start. |
if ((i_swb_cyc)&&(i_swb_stb)&&(i_swb_we)) |
begin |
if ((o_mwb_stb)&&(~i_mwb_stall)) |
begin |
nwritten <= nwritten+1; |
if (nwritten == nread-1) |
// Wishbone interruptus |
o_mwb_stb <= 1'b0; |
else if (cfg_incd) begin |
o_mwb_addr <= o_mwb_addr + 1; |
cfg_waddr <= cfg_waddr + 1; |
case(i_swb_addr) |
2'b00: begin |
if ((i_swb_data[27:16] == 12'hfed) |
&&(cfg_len_nonzero)) |
dma_state <= `DMA_WAIT; |
cfg_blocklen_sub_one |
<= i_swb_data[(LGMEMLEN-1):0] |
+ {(LGMEMLEN){1'b1}}; |
// i.e. -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]; |
end |
// o_mwb_data <= dma_mem[nwritten + 1]; |
end |
2'b01: begin |
cfg_len <= i_swb_data[(AW-1):0]; |
cfg_len_nonzero <= (|i_swb_data[(AW-1):0]); |
end |
2'b10: cfg_raddr <= i_swb_data[(AW-1):0]; |
2'b11: cfg_waddr <= i_swb_data[(AW-1):0]; |
endcase |
end end |
`DMA_WAIT: begin |
o_mwb_addr <= cfg_raddr; |
nracks <= 0; |
nwacks <= 0; |
nwritten <= 0; |
nread <= 0; |
if (abort) |
dma_state <= `DMA_IDLE; |
else if (trigger) |
dma_state <= `DMA_READ_REQ; |
end |
`DMA_READ_REQ: begin |
nwritten <= 0; |
|
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 |
if (~i_mwb_stall) |
begin |
if ((o_mwb_stb)&&(~i_mwb_stall)) |
// Number of read acknowledgements needed |
nracks <= nracks+1; |
if (last_read_request) |
//((nracks == {1'b0, cfg_blocklen_sub_one})||(bus_nracks == cfg_len-1)) |
// Wishbone interruptus |
dma_state <= `DMA_READ_ACK; |
if (cfg_incs) |
o_mwb_addr <= o_mwb_addr |
+ {{(AW-1){1'b0}},1'b1}; |
end |
|
if (i_mwb_err) |
begin |
cfg_len <= 0; |
dma_state <= `DMA_IDLE; |
end |
if (abort) |
dma_state <= `DMA_IDLE; |
if (i_mwb_ack) |
begin |
nread <= nread+1; |
if (cfg_incs) |
cfg_raddr <= cfg_raddr |
+ {{(AW-1){1'b0}},1'b1}; |
end end |
`DMA_READ_ACK: begin |
nwritten <= 0; |
|
if (i_mwb_err) |
begin |
cfg_len <= 0; |
dma_state <= `DMA_IDLE; |
end else if (i_mwb_ack) |
begin |
nread <= nread+1; |
if (last_read_ack) // (nread+1 == nracks) |
dma_state <= `DMA_PRE_WRITE; |
if (cfg_incs) |
cfg_raddr <= cfg_raddr |
+ {{(AW-1){1'b0}},1'b1}; |
end |
if (abort) |
dma_state <= `DMA_IDLE; |
end |
`DMA_PRE_WRITE: begin |
o_mwb_addr <= cfg_waddr; |
dma_state <= (abort)?`DMA_IDLE:`DMA_WRITE_REQ; |
end |
`DMA_WRITE_REQ: begin |
if (~i_mwb_stall) |
begin |
nwritten <= nwritten+1; |
if (last_write_request) // (nwritten == nread-1) |
// Wishbone interruptus |
dma_state <= `DMA_WRITE_ACK; |
if (cfg_incd) |
begin |
nacks <= nacks+1; |
if ((nacks == {1'b0, cfg_blocklen_sub_one}) |
||(bus_nacks <= cfg_len-1)) |
// Wishbone interruptus |
o_mwb_stb <= 1'b0; |
else if (cfg_incs) begin |
o_mwb_addr <= o_mwb_addr + 1; |
end |
o_mwb_addr <= o_mwb_addr |
+ {{(AW-1){1'b0}},1'b1}; |
cfg_waddr <= cfg_waddr |
+ {{(AW-1){1'b0}},1'b1}; |
end |
end |
|
if (i_mwb_err) |
if (i_mwb_err) |
begin |
cfg_len <= 0; |
dma_state <= `DMA_IDLE; |
end |
if (i_mwb_ack) |
begin |
nwacks <= nwacks+1; |
cfg_len <= cfg_len +{(AW){1'b1}}; // -1 |
end |
if (abort) |
dma_state <= `DMA_IDLE; |
end |
`DMA_WRITE_ACK: begin |
if (i_mwb_err) |
begin |
cfg_len <= 0; |
nread <= 0; |
dma_state <= `DMA_IDLE; |
end else if (i_mwb_ack) |
begin |
nwacks <= nwacks+1; |
cfg_len <= cfg_len +{(AW){1'b1}};//cfg_len -= 1; |
if (last_write_ack) // (nwacks+1 == nwritten) |
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; |
dma_state <= (cfg_len == 1)?`DMA_IDLE:`DMA_WAIT; |
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] |
+ {(LGMEMLEN){1'b1}}; |
// i.e. -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[(AW-1):0]; |
2'b10: cfg_raddr <= i_swb_data[(AW-1):0]; |
2'b11: cfg_waddr <= i_swb_data[(AW-1):0]; |
endcase |
end |
end |
|
if (abort) |
dma_state <= `DMA_IDLE; |
end |
default: |
dma_state <= `DMA_IDLE; |
endcase |
|
initial o_interrupt = 1'b0; |
always @(posedge i_clk) |
o_interrupt <= (dma_state == `DMA_WRITE_ACK)&&(i_mwb_ack) |
&&(last_write_ack) |
&&(cfg_len == {{(AW-1){1'b0}},1'b1}); |
|
initial cfg_err = 1'b0; |
always @(posedge i_clk) |
if (dma_state == `DMA_IDLE) |
begin |
if ((i_swb_cyc)&&(i_swb_stb)&&(i_swb_we) |
&&(i_swb_addr==2'b00)) |
cfg_err <= 1'b0; |
end else if (((i_mwb_err)&&(o_mwb_cyc))||(abort)) |
cfg_err <= 1'b1; |
|
initial last_read_request = 1'b0; |
always @(posedge i_clk) |
if ((dma_state == `DMA_WAIT)||(dma_state == `DMA_READ_REQ)) |
begin |
if ((~i_mwb_stall)&&(dma_state == `DMA_READ_REQ)) |
begin |
last_read_request <= |
(nracks + 1 == { 1'b0, cfg_blocklen_sub_one}) |
||(bus_nracks == cfg_len-2); |
end else |
last_read_request <= |
(nracks== { 1'b0, cfg_blocklen_sub_one}) |
||(bus_nracks == cfg_len-1); |
end else |
last_read_request <= 1'b0; |
|
initial last_read_ack = 1'b0; |
always @(posedge i_clk) |
if ((dma_state == `DMA_READ_REQ)||(dma_state == `DMA_READ_ACK)) |
begin |
if (i_mwb_ack) |
last_read_ack <= (nread+2 == nracks); |
else |
last_read_ack <= (nread+1 == nracks); |
end else |
last_read_ack <= 1'b0; |
|
initial last_write_request = 1'b0; |
always @(posedge i_clk) |
if (dma_state == `DMA_PRE_WRITE) |
last_write_request <= (nread <= 1); |
else if (dma_state == `DMA_WRITE_REQ) |
begin |
if (i_mwb_stall) |
last_write_request <= (nwritten >= nread-1); |
else |
last_write_request <= (nwritten >= nread-2); |
end else |
last_write_request <= 1'b0; |
|
initial last_write_ack = 1'b0; |
always @(posedge i_clk) |
if((dma_state == `DMA_WRITE_REQ)||(dma_state == `DMA_WRITE_ACK)) |
begin |
if (i_mwb_ack) |
last_write_ack <= (nwacks+2 == nwritten); |
else |
last_write_ack <= (nwacks+1 == nwritten); |
end else |
last_write_ack <= 1'b0; |
|
assign o_mwb_cyc = (dma_state == `DMA_READ_REQ) |
||(dma_state == `DMA_READ_ACK) |
||(dma_state == `DMA_WRITE_REQ) |
||(dma_state == `DMA_WRITE_ACK); |
|
assign o_mwb_stb = (dma_state == `DMA_READ_REQ) |
||(dma_state == `DMA_WRITE_REQ); |
|
assign o_mwb_we = (dma_state == `DMA_PRE_WRITE) |
||(dma_state == `DMA_WRITE_REQ) |
||(dma_state == `DMA_WRITE_ACK); |
|
// |
// 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 |
294,25 → 418,22
// |
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]; |
if((dma_state == `DMA_IDLE)||(dma_state == `DMA_WAIT) |
||(dma_state == `DMA_WRITE_ACK)) |
rdaddr <= 0; |
else if ((dma_state == `DMA_PRE_WRITE) |
||((dma_state==`DMA_WRITE_REQ)&&(~i_mwb_stall))) |
rdaddr <= rdaddr + {{(LGMEMLEN-1){1'b0}},1'b1}; |
always @(posedge i_clk) |
if ((~o_mwb_cyc)||((o_mwb_we)&&(o_mwb_stb)&&(~i_mwb_stall))) |
if ((dma_state != `DMA_WRITE_REQ)||(~i_mwb_stall)) |
o_mwb_data <= dma_mem[rdaddr]; |
always @(posedge i_clk) |
if ((o_mwb_cyc)&&(~o_mwb_we)&&(i_mwb_ack)) |
if((dma_state == `DMA_READ_REQ)||(dma_state == `DMA_READ_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, |
2'b00: o_swb_data <= { (dma_state != `DMA_IDLE), cfg_err, |
~cfg_incs, ~cfg_incd, |
1'b0, nread, |
cfg_on_dev_trigger, cfg_dev_trigger, |
323,14 → 444,28
2'b11: o_swb_data <= { {(DW-AW){1'b0}}, cfg_waddr}; |
endcase |
|
// This causes us to wait a minimum of two clocks before starting: One |
// to go into the wait state, and then one while in the wait state to |
// develop the trigger. |
initial trigger = 1'b0; |
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; |
trigger <= (dma_state == `DMA_WAIT) |
&&((~cfg_on_dev_trigger) |
||(i_dev_ints[cfg_dev_trigger])); |
|
// Ack any access. We'll quietly ignore any access where we are busy, |
// but ack it anyway. In other words, before writing to the device, |
// double check that it isn't busy, and then write. |
always @(posedge i_clk) |
o_swb_ack <= (i_swb_cyc)&&(i_swb_stb); |
|
assign o_swb_stall = 1'b0; |
|
initial abort = 1'b0; |
always @(posedge i_clk) |
abort <= (i_rst)||((i_swb_cyc)&&(i_swb_stb)&&(i_swb_we) |
&&(i_swb_addr == 2'b00) |
&&(i_swb_data == 32'hffed0000)); |
|
endmodule |
|
/zipcpu/trunk/rtl/peripherals/zipcounter.v
27,7 → 27,7
// |
/////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// Copyright (C) 2015-2016, 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 |
61,17 → 61,13
// Interrupt line |
output reg o_int; |
|
initial o_int = 0; |
initial o_wb_data = 32'h00; |
always @(posedge i_clk) |
if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we)) |
o_wb_data <= i_wb_data; |
{ o_int, o_wb_data } <= { 1'b0, i_wb_data }; |
else if (i_ce) |
o_wb_data <= o_wb_data + 1; |
|
initial o_int = 0; |
always @(posedge i_clk) |
if (i_ce) |
o_int <= &o_wb_data; |
{ o_int, o_wb_data } <= o_wb_data+{{(BW-1){1'b0}},1'b1}; |
else |
o_int <= 1'b0; |
|
/zipcpu/trunk/rtl/peripherals/zipjiffies.v
45,7 → 45,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// Copyright (C) 2015-2016, 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 |
67,7 → 67,7
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_data, |
o_wb_ack, o_wb_stall, o_wb_data, |
o_int); |
parameter BW = 32, VW = (BW-2); |
parameter BW = 32; |
input i_clk, i_ce; |
// Wishbone inputs |
input i_wb_cyc, i_wb_stb, i_wb_we; |
104,13 → 104,13
|
initial new_set = 1'b0; |
always @(posedge i_clk) |
begin |
// Delay things by a clock to simplify our logic |
if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we)) |
begin |
new_set <= 1'b1; |
new_when<= i_wb_data; |
end else |
new_set <= 1'b0; |
new_set <= ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we)); |
// new_when is a don't care when new_set = 0, so don't worry |
// about setting it at all times. |
new_when<= i_wb_data; |
end |
|
initial o_int = 1'b0; |
initial int_set = 1'b0; |
118,16 → 118,18
begin |
o_int <= 1'b0; |
if ((i_ce)&&(int_set)&&(r_counter == int_when)) |
begin // Interrupts are self-clearing |
o_int <= 1'b1; // Set the interrupt flag |
int_set <= 1'b0;// Clear the interrupt |
end |
// Interrupts are self-clearing |
o_int <= 1'b1; // Set the interrupt flag for one clock |
else if ((new_set)&&(till_wb <= 0)) |
o_int <= 1'b1; |
|
if ((new_set)&&(till_wb > 0)) |
int_set <= 1'b1; |
else if ((i_ce)&&(r_counter == int_when)) |
int_set <= 1'b0; |
|
if ((new_set)&&(till_wb > 0)&&((till_wb<till_when)||(~int_set))) |
begin |
int_when <= new_when; |
int_set <= ((int_set)||(till_wb>0)); |
end |
end |
|
// |