mirror of
https://github.com/sxpert/hp-saturn
synced 2024-11-16 19:50:19 +01:00
c62d562008
in the same cycle as the instruction modify the way jump and rtn are handled add some registers to the debugger
352 lines
No EOL
11 KiB
Verilog
352 lines
No EOL
11 KiB
Verilog
/*
|
|
(c) Raphaël Jacquot 2019
|
|
|
|
This file is part of hp_saturn.
|
|
|
|
hp_saturn is free software: 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
|
|
any later version.
|
|
|
|
hp_saturn is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
`default_nettype none
|
|
|
|
module saturn_bus_controller (
|
|
i_clk,
|
|
i_clk_en,
|
|
i_reset,
|
|
i_phases,
|
|
i_phase,
|
|
i_cycle_ctr,
|
|
|
|
o_bus_clk_en,
|
|
o_bus_is_data,
|
|
o_bus_nibble_out,
|
|
i_bus_nibble_in,
|
|
|
|
o_debug_cycle,
|
|
o_instr_decoded,
|
|
o_char_to_send,
|
|
o_char_counter,
|
|
o_char_valid,
|
|
o_char_send,
|
|
i_serial_busy,
|
|
o_halt
|
|
);
|
|
|
|
input wire [0:0] i_clk;
|
|
input wire [0:0] i_clk_en;
|
|
input wire [0:0] i_reset;
|
|
input wire [3:0] i_phases;
|
|
input wire [1:0] i_phase;
|
|
input wire [31:0] i_cycle_ctr;
|
|
|
|
output reg [0:0] o_bus_clk_en;
|
|
output reg [0:0] o_bus_is_data;
|
|
output reg [3:0] o_bus_nibble_out;
|
|
input wire [3:0] i_bus_nibble_in;
|
|
|
|
output wire [0:0] o_debug_cycle;
|
|
output wire [0:0] o_instr_decoded;
|
|
assign o_instr_decoded = dec_instr_decoded;
|
|
output wire [7:0] o_char_to_send;
|
|
output wire [9:0] o_char_counter;
|
|
output wire [0:0] o_char_valid;
|
|
output wire [0:0] o_char_send;
|
|
input wire [0:0] i_serial_busy;
|
|
output wire [0:0] o_halt;
|
|
|
|
/**************************************************************************************************
|
|
*
|
|
* master control unit
|
|
*
|
|
*************************************************************************************************/
|
|
|
|
saturn_control_unit control_unit (
|
|
.i_clk (i_clk),
|
|
.i_clk_en (bus_clk_en),
|
|
.i_reset (i_reset),
|
|
.i_phases (i_phases),
|
|
.i_phase (i_phase),
|
|
.i_cycle_ctr (i_cycle_ctr),
|
|
.i_bus_busy (bus_busy),
|
|
.o_program_address (ctrl_unit_prog_addr),
|
|
.i_program_address (bus_prog_addr),
|
|
.o_program_data (ctrl_unit_prog_data),
|
|
|
|
.o_no_read (ctrl_unit_no_read),
|
|
.i_nibble (i_bus_nibble_in),
|
|
|
|
.o_error (ctrl_unit_error),
|
|
|
|
.o_alu_busy (alu_busy),
|
|
.o_exec_unit_busy (exec_unit_busy),
|
|
|
|
/* debugger interface */
|
|
.o_current_pc (ctrl_current_pc),
|
|
.o_reg_alu_mode (ctrl_reg_alu_mode),
|
|
.o_reg_carry (ctrl_reg_carry),
|
|
.o_reg_hst (ctrl_reg_hst),
|
|
.o_reg_st (ctrl_reg_st),
|
|
.o_reg_p (ctrl_reg_p),
|
|
|
|
.i_dbg_register (dbg_register),
|
|
.i_dbg_reg_ptr (dbg_reg_ptr),
|
|
.o_dbg_reg_nibble (ctrl_reg_nibble),
|
|
.i_dbg_rstk_ptr (dbg_rstk_ptr),
|
|
.o_dbg_rstk_val (ctrl_rstk_val),
|
|
.o_reg_rstk_ptr (ctrl_reg_rstk_ptr),
|
|
|
|
.o_alu_reg_dest (dec_alu_reg_dest),
|
|
.o_alu_reg_src_1 (dec_alu_reg_src_1),
|
|
.o_alu_reg_src_2 (dec_alu_reg_src_2),
|
|
.o_alu_imm_value (dec_alu_imm_value),
|
|
.o_alu_opcode (dec_alu_opcode),
|
|
|
|
.o_instr_type (dec_instr_type),
|
|
.o_instr_decoded (dec_instr_decoded),
|
|
.o_instr_execute (dec_instr_execute)
|
|
);
|
|
|
|
wire [0:0] ctrl_unit_error;
|
|
wire [4:0] ctrl_unit_prog_addr;
|
|
wire [4:0] ctrl_unit_prog_data;
|
|
wire [0:0] ctrl_unit_no_read;
|
|
|
|
wire [0:0] alu_busy;
|
|
wire [0:0] exec_unit_busy;
|
|
|
|
/* debugger insterface */
|
|
wire [19:0] ctrl_current_pc;
|
|
wire [0:0] ctrl_reg_alu_mode;
|
|
wire [0:0] ctrl_reg_carry;
|
|
wire [3:0] ctrl_reg_hst;
|
|
wire [15:0] ctrl_reg_st;
|
|
wire [3:0] ctrl_reg_p;
|
|
|
|
wire [3:0] ctrl_reg_nibble;
|
|
wire [19:0] ctrl_rstk_val;
|
|
wire [2:0] ctrl_reg_rstk_ptr;
|
|
|
|
wire [4:0] dec_alu_reg_dest;
|
|
wire [4:0] dec_alu_reg_src_1;
|
|
wire [4:0] dec_alu_reg_src_2;
|
|
wire [3:0] dec_alu_imm_value;
|
|
wire [4:0] dec_alu_opcode;
|
|
|
|
wire [3:0] dec_instr_type;
|
|
wire [0:0] dec_instr_decoded;
|
|
wire [0:0] dec_instr_execute;
|
|
|
|
/**************************************************************************************************
|
|
*
|
|
* debugger module
|
|
*
|
|
*************************************************************************************************/
|
|
|
|
saturn_debugger debugger (
|
|
.i_clk (i_clk),
|
|
.i_clk_en (i_clk_en),
|
|
.i_reset (i_reset),
|
|
.i_phases (i_phases),
|
|
.i_phase (i_phase),
|
|
.i_cycle_ctr (i_cycle_ctr),
|
|
|
|
.o_debug_cycle (dbg_debug_cycle),
|
|
.i_alu_busy (alu_busy),
|
|
.i_exec_unit_busy (exec_unit_busy),
|
|
|
|
/* debugger interface */
|
|
.i_current_pc (ctrl_current_pc),
|
|
.i_reg_alu_mode (ctrl_reg_alu_mode),
|
|
.i_reg_carry (ctrl_reg_carry),
|
|
.i_reg_hst (ctrl_reg_hst),
|
|
.i_reg_st (ctrl_reg_st),
|
|
.i_reg_p (ctrl_reg_p),
|
|
|
|
.o_dbg_register (dbg_register),
|
|
.o_dbg_reg_ptr (dbg_reg_ptr),
|
|
.i_dbg_reg_nibble (ctrl_reg_nibble),
|
|
.o_dbg_rstk_ptr (dbg_rstk_ptr),
|
|
.i_dbg_rstk_val (ctrl_rstk_val),
|
|
.i_reg_rstk_ptr (ctrl_reg_rstk_ptr),
|
|
|
|
.i_alu_reg_dest (dec_alu_reg_dest),
|
|
.i_alu_reg_src_1 (dec_alu_reg_src_1),
|
|
.i_alu_reg_src_2 (dec_alu_reg_src_2),
|
|
.i_alu_imm_value (dec_alu_imm_value),
|
|
.i_alu_opcode (dec_alu_opcode),
|
|
|
|
.i_instr_type (dec_instr_type),
|
|
.i_instr_decoded (dec_instr_decoded),
|
|
.i_instr_execute (dec_instr_execute),
|
|
.i_bus_busy (bus_busy),
|
|
|
|
.o_char_to_send (o_char_to_send),
|
|
.o_char_counter (o_char_counter),
|
|
.o_char_valid (o_char_valid),
|
|
.o_char_send (o_char_send),
|
|
.i_serial_busy (i_serial_busy),
|
|
|
|
.i_bus_debug (dbg_bus_info),
|
|
.i_bus_action (dbg_bus_action),
|
|
.i_bus_data (dbg_bus_data)
|
|
);
|
|
|
|
wire [4:0] dbg_register;
|
|
wire [3:0] dbg_reg_ptr;
|
|
wire [2:0] dbg_rstk_ptr;
|
|
|
|
wire [0:0] dbg_debug_cycle;
|
|
assign o_debug_cycle = dbg_debug_cycle;
|
|
|
|
reg [0:0] dbg_bus_info;
|
|
reg [1:0] dbg_bus_action;
|
|
reg [3:0] dbg_bus_data;
|
|
|
|
/**************************************************************************************************
|
|
*
|
|
* the bus controller module
|
|
*
|
|
*************************************************************************************************/
|
|
|
|
/*
|
|
* local registers
|
|
*/
|
|
|
|
reg [0:0] bus_error;
|
|
reg [0:0] bus_busy;
|
|
wire [0:0] bus_clk_en = !o_debug_cycle && i_clk_en;
|
|
|
|
/*
|
|
* program list for the bus controller
|
|
* this is used for the control unit to send the bus controller
|
|
* the list of things that need to be done for long sequences
|
|
*/
|
|
reg [4:0] bus_prog_addr;
|
|
wire [0:0] more_to_write;
|
|
|
|
assign more_to_write = (bus_prog_addr != ctrl_unit_prog_addr);
|
|
|
|
/*
|
|
* this should come from the debugger
|
|
*/
|
|
|
|
assign o_halt = bus_error || ctrl_unit_error;
|
|
|
|
initial begin
|
|
dbg_bus_info = 1'b0;
|
|
dbg_bus_action = 2'b00;
|
|
dbg_bus_data = 4'h0;
|
|
bus_error = 1'b0;
|
|
bus_prog_addr = 5'd0;
|
|
bus_busy = 1'b1;
|
|
end
|
|
|
|
// wire [0:0] bus_read_valid = bus_clk_en && i_phases[2] && !bus_busy && !alu_busy;
|
|
// wire [0:0] bus_write_valid = bus_clk_en && i_phases[1] && bus_busy && !alu_busy;
|
|
|
|
/*
|
|
* bus chronograms
|
|
*
|
|
* The bus works on a 4 phase system
|
|
*
|
|
*/
|
|
|
|
always @(posedge i_clk) begin
|
|
dbg_bus_action <= 2'b11;
|
|
dbg_bus_data <= 4'h0;
|
|
if (bus_clk_en && !alu_busy) begin
|
|
case (i_phases)
|
|
4'b0001:
|
|
begin
|
|
/*
|
|
* in this phase, we can send a command or data from the processor
|
|
*/
|
|
// $display("BUSCTRL %0d: [%d] cycle start", i_phase, i_cycle_ctr);
|
|
if (more_to_write) begin
|
|
$write("BUSCTRL %0d: [%d] %0d|%0d : %5b ", i_phase, i_cycle_ctr,
|
|
bus_prog_addr, ctrl_unit_prog_addr, ctrl_unit_prog_data);
|
|
if (ctrl_unit_prog_data[4]) $write("CMD : ");
|
|
else $write("DATA : ");
|
|
$write("%h\n", ctrl_unit_prog_data[3:0]);
|
|
bus_prog_addr <= bus_prog_addr + 5'b1;
|
|
o_bus_is_data <= !ctrl_unit_prog_data[4];
|
|
o_bus_nibble_out <= ctrl_unit_prog_data[3:0];
|
|
o_bus_clk_en <= 1'b1;
|
|
bus_busy <= 1'b1;
|
|
|
|
/* data for the debugger */
|
|
dbg_bus_info <= 1'b1;
|
|
dbg_bus_action <= { 1'b0, ctrl_unit_prog_data[4]};
|
|
dbg_bus_data <= ctrl_unit_prog_data[3:0];
|
|
end
|
|
/*
|
|
* nothing to send, see if we can read, and do it
|
|
*/
|
|
if (!more_to_write && !ctrl_unit_no_read) begin
|
|
// $display("BUSCTRL %0d: [%d] setting up read", i_phase, i_cycle_ctr);
|
|
o_bus_is_data <= 1'b1;
|
|
o_bus_clk_en <= 1'b1;
|
|
end
|
|
end
|
|
4'b0010:
|
|
begin
|
|
/*
|
|
* this phase is reserved for reading data from the bus
|
|
*/
|
|
if (o_bus_clk_en) begin
|
|
// $display("BUSCTRL %0d: [%d] lowering bus clock_en", i_phase, i_cycle_ctr);
|
|
o_bus_clk_en <= 1'b0;
|
|
end
|
|
|
|
/* memories write to the bus in this state */
|
|
end
|
|
4'b0100:
|
|
begin
|
|
/*
|
|
* this phase is when the instruction decoder does it's job
|
|
*/
|
|
if (!more_to_write && bus_busy) begin
|
|
$display("BUSCTRL %0d: [%d] done sending the entire program", i_phase, i_cycle_ctr);
|
|
bus_busy <= 1'b0;
|
|
end
|
|
|
|
/* at that poing, weread data in for the debugger */
|
|
if (!bus_busy && !alu_busy) begin
|
|
dbg_bus_info <= 1'b1;
|
|
dbg_bus_action <= 2'b10;
|
|
dbg_bus_data <= i_bus_nibble_in;
|
|
$display("BUSCTRL %0d: [%d] READ %h", i_phase, i_cycle_ctr, i_bus_nibble_in);
|
|
end
|
|
end
|
|
4'b1000:
|
|
begin
|
|
/*
|
|
* instructions that can be handled in one clock are done here, otherwise, we start the ALU
|
|
*/
|
|
end
|
|
default: begin end // other states should not exist
|
|
endcase
|
|
end
|
|
|
|
if (dbg_bus_info)
|
|
dbg_bus_info <= 1'b0;
|
|
|
|
if (i_reset) begin
|
|
bus_error <= 1'b0;
|
|
bus_prog_addr <= 5'd0;
|
|
bus_busy <= 1'b1;
|
|
end
|
|
end
|
|
|
|
endmodule |