URL
https://opencores.org/ocsvn/s6soc/s6soc/trunk
Subversion Repositories s6soc
Compare Revisions
- This comparison shows the changes necessary to convert path
/s6soc/trunk/rtl
- from Rev 5 to Rev 7
- ↔ Reverse comparison
Rev 5 → Rev 7
/memdev.v
1,3 → 1,40
/////////////////////////////////////////////////////////////////////////// |
// |
// Filename: memdev.v |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration Project |
// |
// Purpose: This file is really simple: it creates an on-chip memory, |
// accessible via the wishbone bus, that can be used in this |
// project. The memory has single cycle access--although getting to the |
// memory from the ZipCPU may cost another cycle or two in access. Either |
// way, operations can be pipelined for greater speed. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// 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 |
// 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 memdev(i_clk, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, |
o_wb_ack, o_wb_stall, o_wb_data); |
parameter AW=15, DW=32; |
/rtclight.v
53,6 → 53,7
// A once-per-day strobe on the last clock of the day |
o_ppd); |
parameter DEFAULT_SPEED = 32'd2814750, |
IMPLEMENT_TIMER=1, IMPLEMENT_STOPWATCH=1, |
CKBITS = 24; // 100 Mhz |
input i_clk; |
input i_wb_cyc, i_wb_stb, i_wb_we; |
162,90 → 163,101
ck_last_clock <= clock[21:0]; |
|
|
reg tm_pps, tm_ppm, tm_int; |
wire tm_stopped, tm_running, tm_alarm; |
assign tm_stopped = ~timer[24]; |
assign tm_running = timer[24]; |
assign tm_alarm = timer[25]; |
reg [23:0] tm_start; |
reg [7:0] tm_sub; |
initial tm_start = 24'h00; |
initial timer = 26'h00; |
initial tm_int = 1'b0; |
initial tm_pps = 1'b0; |
always @(posedge i_clk) |
wire [31:0] bus_timer_return; |
wire tm_int; |
generate |
if (IMPLEMENT_TIMER != 0) |
begin |
if (ck_carry) |
reg tm_pps, tm_ppm, r_tm_int; |
wire tm_stopped, tm_running, tm_alarm; |
assign tm_stopped = ~timer[24]; |
assign tm_running = timer[24]; |
assign tm_alarm = timer[25]; |
reg [23:0] tm_start; |
reg [7:0] tm_sub; |
initial tm_start = 24'h00; |
initial timer = 26'h00; |
initial r_tm_int = 1'b0; |
initial tm_pps = 1'b0; |
always @(posedge i_clk) |
begin |
tm_sub <= tm_sub + 8'h1; |
tm_pps <= (tm_sub == 8'hff); |
end else |
tm_pps <= 1'b0; |
|
if ((~tm_alarm)&&(tm_running)&&(tm_pps)) |
begin // If we are running ... |
timer[25] <= 1'b0; |
if (timer[23:0] == 24'h00) |
timer[25] <= 1'b1; |
else if (timer[3:0] != 4'h0) |
timer[3:0] <= timer[3:0]-4'h1; |
else begin // last digit is a zero |
timer[3:0] <= 4'h9; |
if (timer[7:4] != 4'h0) |
timer[7:4] <= timer[7:4]-4'h1; |
else begin // last two digits are zero |
timer[7:4] <= 4'h5; |
if (timer[11:8] != 4'h0) |
timer[11:8] <= timer[11:8]-4'h1; |
else begin // last three digits are zero |
timer[11:8] <= 4'h9; |
if (timer[15:12] != 4'h0) |
timer[15:12] <= timer[15:12]-4'h1; |
else begin |
timer[15:12] <= 4'h5; |
if (timer[19:16] != 4'h0) |
timer[19:16] <= timer[19:16]-4'h1; |
if (ck_carry) |
begin |
tm_sub <= tm_sub + 8'h1; |
tm_pps <= (tm_sub == 8'hff); |
end else |
tm_pps <= 1'b0; |
|
if ((~tm_alarm)&&(tm_running)&&(tm_pps)) |
begin // If we are running ... |
timer[25] <= 1'b0; |
if (timer[23:0] == 24'h00) |
timer[25] <= 1'b1; |
else if (timer[3:0] != 4'h0) |
timer[3:0] <= timer[3:0]-4'h1; |
else begin // last digit is a zero |
timer[3:0] <= 4'h9; |
if (timer[7:4] != 4'h0) |
timer[7:4] <= timer[7:4]-4'h1; |
else begin // last two digits are zero |
timer[7:4] <= 4'h5; |
if (timer[11:8] != 4'h0) |
timer[11:8] <= timer[11:8]-4'h1; |
else begin // last three digits are zero |
timer[11:8] <= 4'h9; |
if (timer[15:12] != 4'h0) |
timer[15:12] <= timer[15:12]-4'h1; |
else begin |
// |
timer[19:16] <= 4'h9; |
timer[23:20] <= timer[23:20]-4'h1; |
timer[15:12] <= 4'h5; |
if (timer[19:16] != 4'h0) |
timer[19:16] <= timer[19:16]-4'h1; |
else begin |
// |
timer[19:16] <= 4'h9; |
timer[23:20] <= timer[23:20]-4'h1; |
end |
end |
end |
end |
end |
end |
end |
|
if((~tm_alarm)&&(tm_running)) |
begin |
timer[25] <= (timer[23:0] == 24'h00); |
tm_int <= (timer[23:0] == 24'h00); |
end else tm_int <= 1'b0; |
if (tm_alarm) |
timer[24] <= 1'b0; |
if((~tm_alarm)&&(tm_running)) |
begin |
timer[25] <= (timer[23:0] == 24'h00); |
r_tm_int <= (timer[23:0] == 24'h00); |
end else r_tm_int <= 1'b0; |
if (tm_alarm) |
timer[24] <= 1'b0; |
|
if ((tm_sel)&&(i_wb_we)&&(tm_running)) // Writes while running |
// Only allowed to stop the timer, nothing more |
timer[24] <= i_wb_data[24]; |
else if ((tm_sel)&&(i_wb_we)&&(tm_stopped)) // Writes while off |
begin |
timer[24] <= i_wb_data[24]; |
if ((timer[24])||(i_wb_data[24])) |
if ((tm_sel)&&(i_wb_we)&&(tm_running)) // Writes while running |
// Only allowed to stop the timer, nothing more |
timer[24] <= i_wb_data[24]; |
else if ((tm_sel)&&(i_wb_we)&&(tm_stopped)) // Writes while off |
begin |
timer[24] <= i_wb_data[24]; |
if ((timer[24])||(i_wb_data[24])) |
timer[25] <= 1'b0; |
if (i_wb_data[23:0] != 24'h0000) |
begin |
timer[23:0] <= i_wb_data[23:0]; |
tm_start <= i_wb_data[23:0]; |
tm_sub <= 8'h00; |
end else if (timer[23:0] == 24'h00) |
begin // Resetting timer to last valid timer start val |
timer[23:0] <= tm_start; |
tm_sub <= 8'h00; |
end |
// Any write clears the alarm |
timer[25] <= 1'b0; |
if (i_wb_data[23:0] != 24'h0000) |
begin |
timer[23:0] <= i_wb_data[23:0]; |
tm_start <= i_wb_data[23:0]; |
tm_sub <= 8'h00; |
end else if (timer[23:0] == 24'h00) |
begin // Resetting timer to last valid timer start val |
timer[23:0] <= tm_start; |
tm_sub <= 8'h00; |
end |
// Any write clears the alarm |
timer[25] <= 1'b0; |
end |
end |
assign bus_timer_return = { 6'h00, timer }; |
assign tm_int = r_tm_int; |
end else begin |
assign bus_timer_return = ck_counter[39:8]; |
assign tm_int = 1'b0; |
end endgenerate |
|
// |
// Stopwatch functionality |
256,77 → 268,85
// before or after the write. Hence, writing a '2' to the device |
// will always stop and clear it, whereas writing a '3' to the device |
// will only clear it if it was already stopped. |
reg sw_pps, sw_ppm, sw_pph; |
reg [7:0] sw_sub; |
wire sw_running; |
assign sw_running = stopwatch[0]; |
initial stopwatch = 32'h00000; |
always @(posedge i_clk) |
wire [31:0] bus_stopwatch_return; |
generate |
if (IMPLEMENT_STOPWATCH != 0) |
begin |
sw_pps <= 1'b0; |
if (sw_running) |
reg sw_pps, sw_ppm, sw_pph; |
reg [7:0] sw_sub; |
wire sw_running; |
assign sw_running = stopwatch[0]; |
initial stopwatch = 32'h00000; |
always @(posedge i_clk) |
begin |
if (ck_carry) |
sw_pps <= 1'b0; |
if (sw_running) |
begin |
sw_sub <= sw_sub + 8'h1; |
sw_pps <= (sw_sub == 8'hff); |
if (ck_carry) |
begin |
sw_sub <= sw_sub + 8'h1; |
sw_pps <= (sw_sub == 8'hff); |
end |
end |
end |
|
stopwatch[7:1] <= sw_sub[7:1]; |
stopwatch[7:1] <= sw_sub[7:1]; |
|
if (sw_pps) |
begin // Second hand |
if (stopwatch[11:8] >= 4'h9) |
stopwatch[11:8] <= 4'h0; |
else |
stopwatch[11:8] <= stopwatch[11:8] + 4'h1; |
if (sw_pps) |
begin // Second hand |
if (stopwatch[11:8] >= 4'h9) |
stopwatch[11:8] <= 4'h0; |
else |
stopwatch[11:8] <= stopwatch[11:8] + 4'h1; |
|
if (stopwatch[15:8] >= 8'h59) |
stopwatch[15:12] <= 4'h0; |
else if (stopwatch[11:8] >= 4'h9) |
stopwatch[15:12] <= stopwatch[15:12] + 4'h1; |
sw_ppm <= (stopwatch[15:8] == 8'h59); |
end else sw_ppm <= 1'b0; |
if (stopwatch[15:8] >= 8'h59) |
stopwatch[15:12] <= 4'h0; |
else if (stopwatch[11:8] >= 4'h9) |
stopwatch[15:12] <= stopwatch[15:12] + 4'h1; |
sw_ppm <= (stopwatch[15:8] == 8'h59); |
end else sw_ppm <= 1'b0; |
|
if (sw_ppm) |
begin // Minutes |
if (stopwatch[19:16] >= 4'h9) |
stopwatch[19:16] <= 4'h0; |
else |
stopwatch[19:16] <= stopwatch[19:16]+4'h1; |
if (sw_ppm) |
begin // Minutes |
if (stopwatch[19:16] >= 4'h9) |
stopwatch[19:16] <= 4'h0; |
else |
stopwatch[19:16] <= stopwatch[19:16]+4'h1; |
|
if (stopwatch[23:16] >= 8'h59) |
stopwatch[23:20] <= 4'h0; |
else if (stopwatch[19:16] >= 4'h9) |
stopwatch[23:20] <= stopwatch[23:20]+4'h1; |
sw_pph <= (stopwatch[23:16] == 8'h59); |
end else sw_pph <= 1'b0; |
if (stopwatch[23:16] >= 8'h59) |
stopwatch[23:20] <= 4'h0; |
else if (stopwatch[19:16] >= 4'h9) |
stopwatch[23:20] <= stopwatch[23:20]+4'h1; |
sw_pph <= (stopwatch[23:16] == 8'h59); |
end else sw_pph <= 1'b0; |
|
if (sw_pph) |
begin // And hours |
if (stopwatch[27:24] >= 4'h9) |
stopwatch[27:24] <= 4'h0; |
else |
stopwatch[27:24] <= stopwatch[27:24]+4'h1; |
if (sw_pph) |
begin // And hours |
if (stopwatch[27:24] >= 4'h9) |
stopwatch[27:24] <= 4'h0; |
else |
stopwatch[27:24] <= stopwatch[27:24]+4'h1; |
|
if((stopwatch[27:24] >= 4'h9)&&(stopwatch[31:28] < 4'hf)) |
stopwatch[31:28] <= stopwatch[27:24]+4'h1; |
end |
if((stopwatch[27:24] >= 4'h9)&&(stopwatch[31:28] < 4'hf)) |
stopwatch[31:28] <= stopwatch[27:24]+4'h1; |
end |
|
if ((sw_sel)&&(i_wb_we)) |
begin |
stopwatch[0] <= i_wb_data[0]; |
if((i_wb_data[1])&&((~stopwatch[0])||(~i_wb_data[0]))) |
if ((sw_sel)&&(i_wb_we)) |
begin |
stopwatch[31:1] <= 31'h00; |
sw_sub <= 8'h00; |
sw_pps <= 1'b0; |
sw_ppm <= 1'b0; |
sw_pph <= 1'b0; |
stopwatch[0] <= i_wb_data[0]; |
if((i_wb_data[1])&&((~stopwatch[0])||(~i_wb_data[0]))) |
begin |
stopwatch[31:1] <= 31'h00; |
sw_sub <= 8'h00; |
sw_pps <= 1'b0; |
sw_ppm <= 1'b0; |
sw_pph <= 1'b0; |
end |
end |
end |
end |
assign bus_stopwatch_return = stopwatch; |
end else begin |
assign bus_stopwatch_return = ck_counter[39:8]; |
end endgenerate |
|
// |
// The alarm code |
406,8 → 426,8
always @(posedge i_clk) |
case(i_wb_addr[2:0]) |
3'b000: o_data <= { 10'h0, ck_last_clock }; |
3'b001: o_data <= { 6'h00, timer }; |
3'b010: o_data <= stopwatch; |
3'b001: o_data <= bus_timer_return; |
3'b010: o_data <= bus_stopwatch_return; |
3'b011: o_data <= { 6'h00, al_tripped, al_enabled, 2'b00, alarm_time }; |
3'b100: o_data <= ckspeed; |
default: o_data <= 32'h000; |
/cpu/cpudefs.v
77,7 → 77,7
// instruction that will then trip the illegal instruction trap. |
// |
// |
`define OPT_MULTIPLY |
`define OPT_MULTIPLY 2 |
// |
// |
// |
/cpu/cpuops.v
32,6 → 32,7
// |
/////////////////////////////////////////////////////////////////////////// |
// |
`define LONG_MPY |
module cpuops(i_clk,i_rst, i_ce, i_valid, i_op, i_a, i_b, o_c, o_f, o_valid, |
o_illegal, o_busy); |
parameter IMPLEMENT_MPY = 1; |
90,6 → 91,10
||(i_op == 4'h6) // LSL |
||(i_op == 4'h5)); // LSR |
|
`ifdef LONG_MPY |
reg mpyhi; |
wire mpybusy; |
`endif |
|
// A 4-way multiplexer can be done in one 6-LUT. |
// A 16-way multiplexer can therefore be done in 4x 6-LUT's with |
113,7 → 118,9
4'b0101:{o_c,c } <= w_lsr_result[32:0]; // LSR |
4'b0110:{c,o_c } <= (|i_b[31:5])? 33'h00 : {1'b0, i_a } << i_b[4:0]; // LSL |
4'b0111:{o_c,c } <= w_asr_result[32:0]; // ASR |
`ifndef LONG_MPY |
4'b1000: o_c <= { i_b[15: 0], i_a[15:0] }; // LODIHI |
`endif |
4'b1001: o_c <= { i_a[31:16], i_b[15:0] }; // LODILO |
// 4'h1010: The unimplemented MPYU, |
// 4'h1011: and here for the unimplemented MPYS |
128,12 → 135,141
|
reg r_illegal; |
always @(posedge i_clk) |
r_illegal <= (i_ce)&&((i_op == 4'h3)||(i_op == 4'h4)); |
r_illegal <= (i_ce)&&((i_op == 4'ha)||(i_op == 4'hb) |
`ifdef LONG_MPY |
||(i_op == 4'h8) |
`endif |
); |
assign o_illegal = r_illegal; |
end else begin |
// |
// Multiply pre-logic |
// |
`ifdef LONG_MPY |
reg [63:0] r_mpy_result; |
if (IMPLEMENT_MPY == 1) |
begin // Our two clock option (one clock extra) |
reg signed [64:0] r_mpy_a_input, r_mpy_b_input; |
reg mpypipe, x; |
initial mpypipe = 1'b0; |
always @(posedge i_clk) |
mpypipe <= (i_ce)&&((i_op[3:1]==3'h5)||(i_op[3:0]==4'h8)); |
always @(posedge i_clk) |
if (i_ce) |
begin |
r_mpy_a_input <= {{(33){(i_a[31])&(i_op[0])}}, |
i_a[31:0]}; |
r_mpy_b_input <= {{(33){(i_b[31])&(i_op[0])}}, |
i_b[31:0]}; |
end |
always @(posedge i_clk) |
if (mpypipe) |
{x, r_mpy_result} = r_mpy_a_input |
* r_mpy_b_input; |
always @(posedge i_clk) |
if (i_ce) |
mpyhi = i_op[1]; |
assign mpybusy = mpypipe; |
end else if (IMPLEMENT_MPY == 2) |
begin // The three clock option |
reg [31:0] r_mpy_a_input, r_mpy_b_input; |
reg r_mpy_signed; |
reg [1:0] mpypipe; |
|
// First clock, latch in the inputs |
always @(posedge i_clk) |
begin |
// mpypipe indicates we have a multiply in the |
// pipeline. In this case, the multiply |
// pipeline is a two stage pipeline, so we need |
// two bits in the pipe. |
mpypipe[0] <= (i_ce)&&((i_op[3:1]==3'h5) |
||(i_op[3:0]==4'h8)); |
mpypipe[1] <= mpypipe[0]; |
|
if (i_op[0]) // i.e. if signed multiply |
begin |
r_mpy_a_input <= {(~i_a[31]),i_a[30:0]}; |
r_mpy_b_input <= {(~i_b[31]),i_b[30:0]}; |
end else begin |
r_mpy_a_input <= i_a[31:0]; |
r_mpy_b_input <= i_b[31:0]; |
end |
// The signed bit really only matters in the |
// case of 64 bit multiply. We'll keep track |
// of it, though, and pretend in all other |
// cases. |
r_mpy_signed <= i_op[0]; |
|
if (i_ce) |
mpyhi = i_op[1]; |
end |
|
assign mpybusy = |mpypipe; |
|
// Second clock, do the multiplies, get the "partial |
// products". Here, we break our input up into two |
// halves, |
// |
// A = (2^16 ah + al) |
// B = (2^16 bh + bl) |
// |
// and use these to compute partial products. |
// |
// AB = (2^32 ah*bh + 2^16 (ah*bl + al*bh) + (al*bl) |
// |
// Since we're following the FOIL algorithm to get here, |
// we'll name these partial products according to FOIL. |
// |
// The trick is what happens if A or B is signed. In |
// those cases, the real value of A will not be given by |
// A = (2^16 ah + al) |
// but rather |
// A = (2^16 ah[31^] + al) - 2^31 |
// (where we have flipped the sign bit of A) |
// and so ... |
// |
// AB= (2^16 ah + al - 2^31) * (2^16 bh + bl - 2^31) |
// = 2^32(ah*bh) |
// +2^16 (ah*bl+al*bh) |
// +(al*bl) |
// - 2^31 (2^16 bh+bl + 2^16 ah+al) |
// - 2^62 |
// = 2^32(ah*bh) |
// +2^16 (ah*bl+al*bh) |
// +(al*bl) |
// - 2^31 (2^16 bh+bl + 2^16 ah+al + 2^31) |
// |
reg [31:0] pp_f, pp_l; // pp_o, pp_i, pp_l; |
reg [32:0] pp_oi; |
reg [32:0] pp_s; |
always @(posedge i_clk) |
begin |
pp_f<=r_mpy_a_input[31:16]*r_mpy_b_input[31:16]; |
pp_oi<=r_mpy_a_input[31:16]*r_mpy_b_input[15: 0] |
+ r_mpy_a_input[15: 0]*r_mpy_b_input[31:16]; |
pp_l<=r_mpy_a_input[15: 0]*r_mpy_b_input[15: 0]; |
// And a special one for the sign |
if (r_mpy_signed) |
pp_s <= 32'h8000_0000-( |
r_mpy_a_input[31:0] |
+ r_mpy_b_input[31:0]); |
else |
pp_s <= 33'h0; |
end |
|
// Third clock, add the results and produce a product |
always @(posedge i_clk) |
begin |
r_mpy_result[15:0] <= pp_l[15:0]; |
r_mpy_result[63:16] <= |
{ 32'h00, pp_l[31:16] } |
+ { 15'h00, pp_oi } |
+ { pp_s, 15'h00 } |
+ { pp_f, 16'h00 }; |
end |
end // Fourth clock -- results are available for writeback. |
`else |
wire signed [16:0] w_mpy_a_input, w_mpy_b_input; |
wire [33:0] w_mpy_result; |
reg [31:0] r_mpy_result; |
143,6 → 279,7
always @(posedge i_clk) |
if (i_ce) |
r_mpy_result = w_mpy_result[31:0]; |
`endif |
|
// |
// The master ALU case statement |
161,10 → 298,19
4'b0101:{o_c,c } <= w_lsr_result[32:0]; // LSR |
4'b0110:{c,o_c } <= (|i_b[31:5])? 33'h00 : {1'b0, i_a } << i_b[4:0]; // LSL |
4'b0111:{o_c,c } <= w_asr_result[32:0]; // ASR |
`ifdef LONG_MPY |
4'b1000: o_c <= r_mpy_result[31:0]; // MPY |
`else |
4'b1000: o_c <= { i_b[15: 0], i_a[15:0] }; // LODIHI |
`endif |
4'b1001: o_c <= { i_a[31:16], i_b[15:0] }; // LODILO |
`ifdef LONG_MPY |
4'b1010: o_c <= r_mpy_result[63:32]; // MPYHU |
4'b1011: o_c <= r_mpy_result[63:32]; // MPYHS |
`else |
4'b1010: o_c <= r_mpy_result; // MPYU |
4'b1011: o_c <= r_mpy_result; // MPYS |
`endif |
4'b1100: o_c <= w_brev_result; // BREV |
4'b1101: o_c <= w_popc_result; // POPC |
4'b1110: o_c <= w_rol_result; // ROL |
171,13 → 317,22
default: o_c <= i_b; // MOV, LDI |
endcase |
end else if (r_busy) |
`ifdef LONG_MPY |
o_c <= (mpyhi)?r_mpy_result[63:32]:r_mpy_result[31:0]; |
`else |
o_c <= r_mpy_result; |
`endif |
|
reg r_busy; |
initial r_busy = 1'b0; |
always @(posedge i_clk) |
r_busy <= (~i_rst)&&(i_ce)&&(i_valid) |
`ifdef LONG_MPY |
&&((i_op[3:1] == 3'h5) |
||(i_op[3:0] == 4'h8))||mpybusy; |
`else |
&&(i_op[3:1] == 3'h5); |
`endif |
|
assign o_busy = r_busy; |
|
195,6 → 350,11
if (i_rst) |
o_valid <= 1'b0; |
else |
o_valid <= (i_ce)&&(i_valid)&&(i_op[3:1] != 3'h5) |
||(o_busy); |
o_valid <= (i_ce)&&(i_valid) |
`ifdef LONG_MPY |
&&(i_op[3:1] != 3'h5)&&(i_op[3:0] != 4'h8) |
||(o_busy)&&(~mpybusy); |
`else |
&&(i_op[3:1] != 3'h5)||(o_busy); |
`endif |
endmodule |
/cpu/zipcpu.v
137,7 → 137,7
parameter RESET_ADDRESS=32'h0100000, ADDRESS_WIDTH=24, |
LGICACHE=6; |
`ifdef OPT_MULTIPLY |
parameter IMPLEMENT_MPY = 1; |
parameter IMPLEMENT_MPY = `OPT_MULTIPLY; |
`else |
parameter IMPLEMENT_MPY = 0; |
`endif |
284,7 → 284,7
wire [13:0] opFl; |
reg [5:0] r_opF; |
wire [7:0] opF; |
wire op_ce, op_phase; |
wire op_ce, op_phase, op_pipe; |
// Some pipeline control wires |
`ifdef OPT_PIPELINED |
reg opA_alu, opA_mem; |
304,7 → 304,7
// |
// |
reg [(AW-1):0] alu_pc; |
reg alu_pc_valid; |
reg alu_pc_valid, mem_pc_valid; |
wire alu_phase; |
wire alu_ce, alu_stall; |
wire [31:0] alu_result; |
608,9 → 608,9
`endif |
|
`ifdef OPT_PIPELINED_BUS_ACCESS |
reg op_pipe; |
reg r_op_pipe; |
|
initial op_pipe = 1'b0; |
initial r_op_pipe = 1'b0; |
// To be a pipeable operation, there must be |
// two valid adjacent instructions |
// Both must be memory instructions |
622,7 → 622,10
// calculated in the instruction decoder. |
always @(posedge i_clk) |
if (op_ce) |
op_pipe <= dcd_pipe; |
r_op_pipe <= dcd_pipe; |
assign op_pipe = r_op_pipe; |
`else |
assign op_pipe = 1'b0; |
`endif |
|
// |
633,6 → 636,55
assign w_opA = regset[dcdA]; |
assign w_opB = regset[dcdB]; |
|
wire [8:0] w_cpu_info; |
assign w_cpu_info = { |
`ifdef OPT_ILLEGAL_INSTRUCTION |
1'b1, |
`else |
1'b0, |
`endif |
`ifdef OPT_MULTIPLY |
1'b1, |
`else |
1'b0, |
`endif |
`ifdef OPT_DIVIDE |
1'b1, |
`else |
1'b0, |
`endif |
`ifdef OPT_IMPLEMENT_FPU |
1'b1, |
`else |
1'b0, |
`endif |
`ifdef OPT_PIPELINED |
1'b1, |
`else |
1'b0, |
`endif |
`ifdef OPT_TRADITIONAL_CACHE |
1'b1, |
`else |
1'b0, |
`endif |
`ifdef OPT_EARLY_BRANCHING |
1'b1, |
`else |
1'b0, |
`endif |
`ifdef OPT_PIPELINED_BUS_ACCESS |
1'b1, |
`else |
1'b0, |
`endif |
`ifdef OPT_VLIW |
1'b1 |
`else |
1'b0 |
`endif |
}; |
|
wire [31:0] w_pcA_v; |
generate |
if (AW < 32) |
662,7 → 714,7
else if (dcdA_pc) |
r_opA <= w_pcA_v; |
else if (dcdA_cc) |
r_opA <= { w_opA[31:14], (dcdA[4])?w_uflags:w_iflags }; |
r_opA <= { w_cpu_info, w_opA[22:14], (dcdA[4])?w_uflags:w_iflags }; |
else |
r_opA <= w_opA; |
`ifdef OPT_PIPELINED |
688,7 → 740,8
assign w_opBnI = (~dcdB_rd) ? 32'h00 |
: (((wr_reg_ce)&&(wr_reg_id == dcdB)) ? wr_reg_vl |
: ((dcdB_pc) ? w_pcB_v |
: ((dcdB_cc) ? { w_opB[31:14], (dcdB[4])?w_uflags:w_iflags} |
: ((dcdB_cc) ? { w_cpu_info, w_opB[22:14], // w_opB[31:14], |
(dcdB[4])?w_uflags:w_iflags} |
: w_opB))); |
|
always @(posedge i_clk) |
942,11 → 995,14
// We'll use the last values from that stage |
// (opR_wr, opF_wr, opR) in our logic below. |
&&((opvalid)||(mem_rdbusy) |
||(div_busy)||(fpu_busy)) |
||(div_busy)||(fpu_busy)||(alu_busy)) |
&&( |
// Stall on memory ops writing to my register |
// (i.e. loads), or on any write to my |
// register if I have an immediate offset |
// Actually, this is worse. I can't tell |
// whether or not my register is going to |
// be written to, so |
// Note the exception for writing to the PC: |
// if I write to the PC, the whole next |
// instruction is invalid, not just the |
962,8 → 1018,10
// following each other constitutes a |
// fairly unusualy code structure.) |
// |
((~dcd_zI)&&(opR == dcdB)&&(opR_wr)) |
// &&(opR != { op_gie, `CPU_PC_REG } ) |
((~dcd_zI)&&( |
((opR == dcdB)&&(opR_wr)) |
||(((opvalid_mem)||(mem_rdbusy)) |
&&(op_pipe)))) |
// Stall following any instruction that will |
// set the flags, if we're going to need the |
// flags (CC) register for opB. |
1075,14 → 1133,17
else if ((i_halt)&&(i_dbg_we)) |
alu_reg <= i_dbg_reg; |
|
reg [31:0] dbg_val; |
// |
// DEBUG Register write access starts here |
// |
reg dbgv; |
always @(posedge i_clk) |
dbg_val <= i_dbg_data; |
initial dbgv = 1'b0; |
always @(posedge i_clk) |
dbgv <= (~i_rst)&&(~alu_ce)&&((i_halt)&&(i_dbg_we)); |
reg [31:0] dbg_val; |
always @(posedge i_clk) |
dbg_val <= i_dbg_data; |
always @(posedge i_clk) |
if ((alu_ce)||(mem_ce)) |
alu_gie <= op_gie; |
always @(posedge i_clk) |
1101,14 → 1162,18
assign alu_illegal = (alu_illegal_op)||(r_alu_illegal); |
`endif |
|
// This _almost_ is equal to (alu_ce)||(mem_ce). The only |
// problem is that mem_ce is gated by the set_cond, and |
// the PC will be valid independent of the set condition. Hence, this |
// equals (alu_ce)||(everything in mem_ce but the set condition) |
initial alu_pc_valid = 1'b0; |
initial mem_pc_valid = 1'b0; |
always @(posedge i_clk) |
alu_pc_valid <= ((alu_ce) |
||((master_ce)&&(opvalid_mem)&&(~clear_pipeline)&&(~mem_stalled))); |
if (i_rst) |
alu_pc_valid <= 1'b0; |
else |
alu_pc_valid <= (alu_ce); |
always @(posedge i_clk) |
if (i_rst) |
mem_pc_valid <= 1'b0; |
else |
mem_pc_valid <= (mem_ce); |
|
wire bus_lock; |
`ifdef OPT_PIPELINED |
1168,8 → 1233,16
o_wb_we, o_wb_addr, o_wb_data, |
i_wb_ack, i_wb_stall, i_wb_err); |
|
|
|
// |
// |
// |
// |
// |
// |
// |
// |
// PIPELINE STAGE #5 :: Write-back results |
// |
// |
1187,12 → 1260,12
// 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 = (~alu_illegal)&& |
assign wr_reg_ce = (dbgv)||(~alu_illegal)&& |
(((alu_wr)&&(~clear_pipeline) |
&&((alu_valid)||(div_valid)||(fpu_valid))) |
||(mem_valid)); |
`else |
assign wr_reg_ce = ((alu_wr)&&(~clear_pipeline))||(mem_valid)||(div_valid)||(fpu_valid); |
assign wr_reg_ce = (dbgv)||((alu_wr)&&(~clear_pipeline))||(mem_valid)||(div_valid)||(fpu_valid); |
`endif |
// Which register shall be written? |
// COULD SIMPLIFY THIS: by adding three bits to these registers, |
1279,7 → 1352,9
assign o_break = (((break_en)||(~op_gie))&&(op_break) |
&&(~alu_valid)&&(~mem_valid)&&(~mem_busy) |
&&(~clear_pipeline)) |
||((~alu_gie)&&(bus_err)); |
||((~alu_gie)&&(bus_err)) |
||((~alu_gie)&&(div_valid)&&(div_error)) |
||((~alu_gie)&&(fpu_valid)&&(fpu_error)); |
`endif |
|
|
1315,7 → 1390,7
step <= 1'b0; |
else if ((wr_reg_ce)&&(~alu_gie)&&(wr_reg_id[4])&&(wr_write_cc)) |
step <= wr_reg_vl[`CPU_STEP_BIT]; |
else if ((alu_pc_valid)&&(step)&&(gie)) |
else if (((alu_pc_valid)||(mem_pc_valid))&&(step)&&(gie)) |
step <= 1'b0; |
|
// The GIE register. Only interrupts can disable the interrupt register |
1323,7 → 1398,7
// On interrupt (obviously) |
((i_interrupt)&&(~alu_phase)&&(~bus_lock)) |
// If we are stepping the CPU |
||((alu_pc_valid)&&(step)&&(~alu_phase)&&(~bus_lock)) |
||(((alu_pc_valid)||(mem_pc_valid))&&(step)&&(~alu_phase)&&(~bus_lock)) |
// If we encounter a break instruction, if the break |
// enable isn't set. |
||((master_ce)&&(~mem_rdbusy)&&(~div_busy)&&(~fpu_busy) |
1361,11 → 1436,13
always @(posedge i_clk) |
if (i_rst) |
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]) |
&&(wr_write_cc)) // &&(wr_reg_id[4]) implied |
trap <= 1'b1; |
else if (w_release_from_interrupt) |
trap <= 1'b0; |
else if ((wr_reg_ce)&&(wr_write_cc)&&(wr_reg_id[4])) |
trap <= wr_reg_vl[`CPU_TRAP_BIT]; |
|
`ifdef OPT_ILLEGAL_INSTRUCTION |
initial ill_err_i = 1'b0; |
1372,7 → 1449,7
always @(posedge i_clk) |
if (i_rst) |
ill_err_i <= 1'b0; |
// The debug interface can clear this bit |
// 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])) |
ill_err_i <= 1'b0; |
1416,10 → 1493,6
ubus_err_flag <= 1'b0; |
else if (w_release_from_interrupt) |
ubus_err_flag <= 1'b0; |
// else if ((i_halt)&&(i_dbg_we)&&(~i_dbg_reg[4]) |
// &&(i_dbg_reg == {1'b1, `CPU_CC_REG}) |
// &&(~i_dbg_data[`CPU_BUSERR_BIT])) |
// ubus_err_flag <= 1'b0; |
else if (((~alu_gie)||(dbgv))&&(wr_reg_ce) |
&&(~wr_reg_vl[`CPU_BUSERR_BIT]) |
&&(wr_reg_id[4])&&(wr_write_cc)) |
1537,7 → 1610,9
always @(posedge i_clk) |
if ((wr_reg_ce)&&(wr_reg_id[4])&&(wr_write_pc)) |
upc <= wr_reg_vl[(AW-1):0]; |
else if ((alu_gie)&&(alu_pc_valid)&&(~clear_pipeline)) |
else if ((alu_gie)&& |
(((alu_pc_valid)&&(~clear_pipeline)) |
||(mem_pc_valid))) |
upc <= alu_pc; |
|
always @(posedge i_clk) |
1545,7 → 1620,9
ipc <= RESET_ADDRESS; |
else if ((wr_reg_ce)&&(~wr_reg_id[4])&&(wr_write_pc)) |
ipc <= wr_reg_vl[(AW-1):0]; |
else if ((~alu_gie)&&(alu_pc_valid)&&(~clear_pipeline)) |
else if ((~alu_gie)&& |
(((alu_pc_valid)&&(~clear_pipeline)) |
||(mem_pc_valid))) |
ipc <= alu_pc; |
|
always @(posedge i_clk) |
1616,8 → 1693,8
always @(posedge i_clk) |
o_dbg_stall <= (i_halt)&&( |
(pf_cyc)||(mem_cyc_gbl)||(mem_cyc_lcl)||(mem_busy) |
||((~opvalid)&&(~i_rst)) |
||((~dcdvalid)&&(~i_rst))); |
||((~opvalid)&&(~i_rst)&&(~dcd_illegal)) |
||((~dcdvalid)&&(~i_rst)&&(~pf_illegal))); |
|
// |
// |
1632,7 → 1709,8
`ifdef DEBUG_SCOPE |
always @(posedge i_clk) |
o_debug <= { |
pf_pc[3:0], flags, |
o_break, i_wb_err, pf_pc[1:0], |
flags, |
pf_valid, dcdvalid, opvalid, alu_valid, mem_valid, |
op_ce, alu_ce, mem_ce, |
// |
1644,8 → 1722,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_reg_vl[4:0] |
/* |
i_rst, master_ce, (new_pc), |
((dcd_early_branch)&&(dcdvalid)), |
1654,6 → 1731,25
pf_cyc, pf_stb, pf_we, pf_ack, pf_stall, pf_err, |
pf_pc[7:0], pf_addr[7:0] |
*/ |
/* |
i_wb_err, gie, alu_illegal, |
(new_pc)||((dcd_early_branch)&&(~clear_pipeline)), |
mem_busy, |
(mem_busy)?{ (o_wb_gbl_stb|o_wb_lcl_stb), o_wb_we, |
o_wb_addr[8:0] } |
: { instruction[31:21] }, |
pf_valid, (pf_valid) ? alu_pc[14:0] |
:{ pf_cyc, pf_stb, pf_pc[12:0] } |
*/ |
/* |
i_wb_err, gie, new_pc, dcd_early_branch, // 4 |
pf_valid, pf_cyc, pf_stb, instruction_pc[0], // 4 |
instruction[30:27], // 4 |
dcd_gie, mem_busy, o_wb_gbl_cyc, o_wb_gbl_stb, // 4 |
dcdvalid, |
((dcd_early_branch)&&(~clear_pipeline)) // 15 |
? dcd_branch_pc[14:0]:pf_pc[14:0] |
*/ |
}; |
`endif |
|
/wbgpio.v
1,3 → 1,52
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: wbgpio.v |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: A General Purpose Input/Output controller. This controller |
// allows a user to read the current state of the 16-GPIO input |
// pins, or to set the state of the 16-GPIO output pins. Specific numbers |
// of pins are configurable from 1-16. |
// |
// Unlike other controllers, this controller offers no capability to |
// change input/output direction, or to implement pull-up or pull-down |
// resistors. It simply changes and adjusts the values going out the |
// output pins, while allowing a user to read the values on the input |
// pins. |
// |
// Any change of an input pin value will result in the generation of an |
// interrupt signal. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// 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 |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
module wbgpio(i_clk, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_data, o_wb_data, |
i_gpio, o_gpio, o_int); |
parameter NIN=16, NOUT=16, DEFAULT=16'h00; |
/builddate.v
0,0 → 1,52
`define DATESTAMP 32'h20160422 |
/busmaster.v
44,8 → 44,8
`define FANCY_ICAP_ACCESS |
`endif |
`define FLASH_ACCESS |
// `define CFG_SCOPE // About 204 LUTs, at 2^6 addresses |
`define INCLUDE_RTC // About 90 LUTs |
`define DBG_SCOPE // About 204 LUTs, at 2^6 addresses |
// `define INCLUDE_RTC // About 90 LUTs |
module busmaster(i_clk, i_rst, |
i_rx_stb, i_rx_data, o_tx_stb, o_tx_data, i_tx_busy, |
o_uart_rts, |
290,7 → 290,7
assign rtc_ack = r_rtc_ack; |
|
rtclight |
#(32'h35afe5,23) // 80 MHz clock |
#(32'h35afe5,23,0,0) // 80 MHz clock |
thetime(i_clk, wb_cyc, |
((wb_stb)&&(rtc_sel)), wb_we, |
{ 1'b0, wb_addr[1:0] }, wb_data, rtc_data, |
352,7 → 352,8
// hardware buffer. |
// |
// We'll add the flag for two stop bits. |
assign o_uart_setup = 30'h080002b6; // 115200 MBaud @ an 80MHz clock |
// assign o_uart_setup = 30'h080002b6; // 115200 MBaud @ an 80MHz clock |
assign o_uart_setup = 30'h0000208d; // 9600 MBaud, 8N1 |
|
initial o_tx_stb = 1'b0; |
initial o_tx_data = 8'h00; |
441,10 → 442,10
// |
wire [31:0] scop_cfg_data; |
wire scop_cfg_ack, scop_cfg_stall, scop_cfg_interrupt; |
`ifdef CFG_SCOPE |
`ifdef DBG_SCOPE |
wire scop_cfg_trigger; |
assign scop_cfg_trigger = (wb_cyc)&&(wb_stb)&&(cfg_sel); |
wbscope #(5'h6) wbcfgscope(i_clk, 1'b1, scop_cfg_trigger, cfg_scope, |
wbscope #(5'ha) wbcfgscope(i_clk, 1'b1, scop_cfg_trigger, cfg_scope, |
// Wishbone interface |
i_clk, wb_cyc, (wb_stb)&&(scop_sel), |
wb_we, wb_addr[0], wb_data, |
/spio.v
1,3 → 1,41
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: spio.v |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: |
// |
// Creator: Dan Gisselquist, Ph.D. |
// 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 |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
|
module spio(i_clk, i_wb_cyc, i_wb_stb, i_wb_we, i_wb_data, o_wb_data, |
o_kp_col, i_kp_row, i_btn, o_led, |
o_kp_int, o_btn_int); |