hp-saturn/saturn_core.v

469 lines
10 KiB
Coq
Raw Normal View History

2019-02-06 10:40:55 +01:00
/*
* Licence: GPLv3 or later
*/
2019-02-04 20:36:47 +01:00
`default_nettype none //
2019-02-16 22:38:44 +01:00
`include "def-clocks.v"
2019-02-11 21:29:04 +01:00
// `include "bus_commands.v"
// `include "hp48_00_bus.v"
// `include "dbg_module.v"
`include "saturn_decoder.v"
`include "saturn_alu.v"
2019-02-16 22:38:44 +01:00
`include "saturn_bus_ctrl.v"
2019-02-04 15:02:33 +01:00
/**************************************************************************************************
*
*
2019-02-05 08:49:14 +01:00
*
*
*
*/
2019-02-06 10:40:55 +01:00
2019-02-04 17:14:08 +01:00
`ifdef SIM
2019-02-04 18:17:14 +01:00
module saturn_core (
i_clk,
i_reset,
o_halt,
i_bus_data_in,
o_bus_data_out,
o_bus_strobe,
o_bus_cmd_data
2019-02-04 18:17:14 +01:00
);
input wire [0:0] i_clk;
input wire [0:0] i_reset;
output wire [0:0] o_halt;
input wire [3:0] i_bus_data_in;
output wire [3:0] o_bus_data_out;
output wire [0:0] o_bus_strobe;
output wire [0:0] o_bus_cmd_data;
2019-02-04 17:46:29 +01:00
`else
2019-02-04 18:17:14 +01:00
module saturn_core (
clk_25mhz,
btn,
led,
i_bus_data_in,
o_bus_data_out,
o_bus_strobe,
o_bus_cmd_data
2019-02-04 09:59:35 +01:00
);
2019-02-04 18:17:14 +01:00
input wire [0:0] clk_25mhz;
input wire [6:0] btn;
output reg [7:0] led;
wire [0:0] i_clk;
wire [0:0] i_reset;
assign i_clk = clk_25mhz;
assign i_reset = btn[1];
input wire [3:0] i_bus_data_in;
output wire [3:0] o_bus_data_out;
output wire [0:0] o_bus_strobe;
output wire [0:0] o_bus_cmd_data;
2019-02-04 18:17:14 +01:00
`endif
2019-02-04 09:59:35 +01:00
2019-02-07 22:54:06 +01:00
// clocks
2019-02-16 22:38:44 +01:00
reg [1:0] clk_phase;
reg [0:0] en_reset;
2019-02-17 08:35:26 +01:00
reg [0:0] ck_debugger; // phase 0
2019-02-16 22:38:44 +01:00
2019-02-17 08:35:26 +01:00
reg [0:0] ck_bus_send; // phase 0
reg [0:0] ck_bus_recv; // phase 1
reg [0:0] ck_bus_ecmd; // phase 3
2019-02-16 22:38:44 +01:00
2019-02-17 08:35:26 +01:00
reg [0:0] ck_inst_dec; // phase 2
reg [0:0] ck_inst_exe; // phase 3
2019-02-16 22:38:44 +01:00
2019-02-17 08:35:26 +01:00
reg [0:0] ck_alu_dump; // phase 0
reg [0:0] ck_alu_init; // phase 3
reg [0:0] ck_alu_prep; // phase 1
reg [0:0] ck_alu_calc; // phase 2
reg [0:0] ck_alu_save; // phase 3
2019-02-16 22:38:44 +01:00
reg [0:0] clock_end;
reg [31:0] cycle_ctr;
reg [31:0] max_cycle;
2019-02-07 22:54:06 +01:00
2019-02-11 19:49:22 +01:00
// hp48_bus bus_ctrl (
// .strobe (bus_strobe),
// .reset (reset),
// .address (bus_address),
// .command (bus_command),
// .nibble_in (bus_nibble_in),
// .nibble_out (bus_nibble_out),
// .bus_error (bus_error)
// );
saturn_decoder m_decoder (
.i_clk (i_clk),
.i_reset (i_reset),
2019-02-12 12:43:36 +01:00
.i_cycles (cycle_ctr),
2019-02-17 08:35:26 +01:00
.i_en_dbg (ck_debugger),
.i_en_dec (ck_inst_dec),
2019-02-12 12:43:36 +01:00
.i_pc (reg_pc),
.i_bus_load_pc (bus_load_pc),
2019-02-16 22:38:44 +01:00
.i_stalled (dec_stalled),
.i_nibble (bus_nibble_in),
2019-02-12 12:43:36 +01:00
.i_reg_p (reg_p),
.o_inc_pc (inc_pc),
.o_push (push),
.o_pop (pop),
2019-02-12 12:43:36 +01:00
.o_dec_error (inv_opcode),
.o_alu_debug (alu_debug),
2019-02-12 08:48:13 +01:00
2019-02-12 12:43:36 +01:00
.o_ins_addr (ins_addr),
.o_ins_decoded (ins_decoded),
.o_fields_table (fields_table),
.o_field (field),
.o_field_start (field_start),
.o_field_last (field_last),
2019-02-13 22:43:04 +01:00
.o_imm_value (imm_value),
2019-02-12 12:43:36 +01:00
.o_alu_op (alu_op),
.o_alu_no_stall (alu_no_stall),
2019-02-13 22:43:04 +01:00
.o_reg_dest (reg_dest),
.o_reg_src1 (reg_src1),
.o_reg_src2 (reg_src2),
2019-02-12 12:43:36 +01:00
.o_ins_rtn (ins_rtn),
.o_set_xm (set_xm),
.o_set_carry (set_carry),
.o_test_carry (test_carry),
2019-02-12 12:43:36 +01:00
.o_carry_val (carry_val),
.o_ins_set_mode (ins_set_mode),
2019-02-13 22:43:04 +01:00
.o_mode_dec (mode_dec),
.o_ins_alu_op (ins_alu_op),
2019-02-17 15:03:36 +01:00
.o_ins_test_go (ins_test_go),
.o_ins_reset (ins_reset),
.o_ins_config (ins_config)
2019-02-11 21:29:04 +01:00
);
wire [0:0] inc_pc;
wire [0:0] push;
wire [0:0] pop;
wire [0:0] inv_opcode;
wire [0:0] alu_debug;
2019-02-12 12:43:36 +01:00
wire [19:0] ins_addr;
2019-02-16 22:38:44 +01:00
wire [0:0] ins_decoded;
2019-02-12 12:43:36 +01:00
wire [1:0] fields_table;
wire [3:0] field;
wire [3:0] field_start;
wire [3:0] field_last;
2019-02-13 22:43:04 +01:00
wire [3:0] imm_value;
2019-02-12 12:43:36 +01:00
wire [4:0] alu_op;
wire [0:0] alu_no_stall;
2019-02-13 22:43:04 +01:00
wire [4:0] reg_dest;
wire [4:0] reg_src1;
wire [4:0] reg_src2;
2019-02-12 12:43:36 +01:00
wire [0:0] ins_rtn;
wire [0:0] set_xm;
wire [0:0] set_carry;
wire [0:0] test_carry;
wire [0:0] carry_val;
wire [0:0] ins_set_mode;
wire [0:0] mode_dec;
wire [0:0] ins_alu_op;
wire [0:0] ins_test_go;
2019-02-17 15:03:36 +01:00
wire [0:0] ins_reset;
wire [0:0] ins_config;
wire [0:0] ins_unconfig;
2019-02-12 12:43:36 +01:00
saturn_alu m_alu (
.i_clk (i_clk),
.i_reset (i_reset),
.i_cycle_ctr (cycle_ctr),
2019-02-17 08:35:26 +01:00
.i_en_alu_dump (ck_alu_dump),
.i_en_alu_prep (ck_alu_prep),
.i_en_alu_calc (ck_alu_calc),
.i_en_alu_init (ck_alu_init),
.i_en_alu_save (ck_alu_save),
2019-02-16 22:38:44 +01:00
.i_stalled (alu_stalled),
.o_bus_address (bus_address),
.o_bus_load_pc (bus_load_pc),
.o_bus_load_dp (bus_load_dp),
.o_bus_pc_read (bus_pc_read),
2019-02-18 07:43:36 +01:00
.o_bus_dp_read (bus_dp_read),
.o_bus_dp_write (bus_dp_write),
.o_bus_config (bus_config),
2019-02-18 07:43:36 +01:00
.i_bus_nibble_in (bus_nibble_in),
2019-02-16 22:38:44 +01:00
.o_bus_nibble_out (bus_nibble_out),
2019-02-13 22:43:04 +01:00
.i_push (push),
.i_pop (pop),
.i_alu_debug (alu_debug),
2019-02-16 22:38:44 +01:00
.o_alu_stall_dec (alu_stalls_dec),
2019-02-13 22:43:04 +01:00
.i_ins_decoded (ins_decoded),
.i_field_start (field_start),
.i_field_last (field_last),
.i_imm_value (imm_value),
.i_alu_op (alu_op),
.i_alu_no_stall (alu_no_stall),
2019-02-13 22:43:04 +01:00
.i_reg_dest (reg_dest),
.i_reg_src1 (reg_src1),
.i_reg_src2 (reg_src2),
.i_ins_alu_op (ins_alu_op),
.i_ins_test_go (ins_test_go),
2019-02-15 07:08:11 +01:00
.i_ins_set_mode (ins_set_mode),
.i_ins_rtn (ins_rtn),
.i_ins_config (ins_config),
.i_ins_unconfig (ins_unconfig),
2019-02-15 07:08:11 +01:00
.i_mode_dec (mode_dec),
.i_set_xm (set_xm),
.i_set_carry (set_carry),
.i_test_carry (test_carry),
2019-02-15 07:08:11 +01:00
.i_carry_val (carry_val),
2019-02-13 22:43:04 +01:00
.o_reg_p (reg_p),
.o_pc (reg_pc)
);
2019-02-12 12:43:36 +01:00
// interconnections
2019-02-16 22:38:44 +01:00
wire [19:0] bus_address;
wire [0:0] bus_pc_read;
2019-02-18 07:43:36 +01:00
wire [0:0] bus_dp_read;
wire [0:0] bus_dp_write;
2019-02-18 07:43:36 +01:00
wire [0:0] bus_load_pc;
wire [0:0] bus_load_dp;
wire [0:0] bus_config;
2019-02-12 12:43:36 +01:00
2019-02-16 22:38:44 +01:00
wire [3:0] bus_nibble_in;
wire [3:0] bus_nibble_out;
wire [0:0] alu_stalls_dec;
2019-02-12 12:43:36 +01:00
wire [3:0] reg_p;
wire [19:0] reg_pc;
2019-02-12 12:43:36 +01:00
/*
2019-02-16 22:38:44 +01:00
*
* Bus controller module
*
*/
2019-02-16 22:38:44 +01:00
saturn_bus_ctrl m_bus_ctrl (
// basic stuff
.i_clk (i_clk),
.i_reset (i_reset),
2019-02-16 22:38:44 +01:00
.i_cycle_ctr (cycle_ctr),
2019-02-17 08:35:26 +01:00
.i_en_bus_send (ck_bus_send),
.i_en_bus_recv (ck_bus_recv),
.i_en_bus_ecmd (ck_bus_ecmd),
2019-02-16 22:38:44 +01:00
.i_stalled (mem_ctrl_stall),
.i_read_stall (dec_stalled),
.o_stalled_by_bus (bus_stalls_core),
//bus i/o
.i_bus_data (i_bus_data_in),
.o_bus_data (o_bus_data_out),
.o_bus_strobe (o_bus_strobe),
.o_bus_cmd_data (o_bus_cmd_data),
2019-02-16 22:38:44 +01:00
// interface to the rest of the machine
.i_alu_pc (reg_pc),
.i_address (bus_address),
.i_load_pc (bus_load_pc),
.i_cmd_load_dp (bus_load_dp),
.i_read_pc (bus_pc_read),
2019-02-18 07:43:36 +01:00
.i_cmd_dp_read (bus_dp_read),
.i_cmd_dp_write (bus_dp_write),
2019-02-17 15:03:36 +01:00
.i_cmd_reset (ins_reset),
.i_cmd_config (bus_config),
2019-02-16 22:38:44 +01:00
.i_nibble (bus_nibble_out),
.o_nibble (bus_nibble_in)
);
reg [0:0] mem_ctrl_stall;
wire [0:0] bus_stalls_core;
// // bus to external modules
// reg [3:0] bus_data_in;
// wire [3:0] bus_data_out;
// wire [0:0] bus_strobe;
// wire [0:0] bus_cmd_data;
2019-02-13 22:43:04 +01:00
2019-02-16 22:38:44 +01:00
// `define DEBUG_CLOCKS
2019-02-13 22:43:04 +01:00
2019-02-16 22:38:44 +01:00
initial begin
2019-02-12 12:43:36 +01:00
clk_phase = 0;
2019-02-16 22:38:44 +01:00
2019-02-17 08:35:26 +01:00
ck_debugger = 0; // phase 0
2019-02-16 22:38:44 +01:00
2019-02-17 08:35:26 +01:00
ck_bus_send = 0; // phase 0
ck_bus_recv = 0; // phase 1
ck_bus_ecmd = 0; // phase 3
2019-02-16 22:38:44 +01:00
2019-02-17 08:35:26 +01:00
ck_inst_dec = 0; // phase 2
ck_inst_exe = 0; // phase 3
2019-02-16 22:38:44 +01:00
2019-02-17 08:35:26 +01:00
ck_alu_dump = 0;
ck_alu_prep = 0; // phase 1
ck_alu_calc = 0; // phase 2
ck_alu_init = 0; // phase 0
ck_alu_save = 0; // phase 3
2019-02-16 22:38:44 +01:00
2019-02-12 12:43:36 +01:00
clock_end = 0;
cycle_ctr = 0;
2019-02-07 22:54:06 +01:00
2019-02-16 22:38:44 +01:00
mem_ctrl_stall = 0;
2019-02-11 20:27:51 +01:00
`ifdef DEBUG_CLOCKS
$monitor("RST %b | CLK %b | CLKP %d | CYCL %d | PC %5h | eRST %b | eDBG %b | eBSND %b | eBRECV %b | eAPR %b | eACALC %b | eINDC %b | eASAVE %b | eINDX %b",
reset, clk, clk_phase, cycle_ctr, reg_pc, en_reset,
2019-02-11 20:27:51 +01:00
en_debugger, en_bus_send,
2019-02-11 19:49:22 +01:00
en_bus_recv, en_alu_prep,
en_alu_calc, en_inst_dec,
en_alu_save, en_inst_exec);
2019-02-11 20:27:51 +01:00
`endif
2019-02-07 22:54:06 +01:00
end
2019-02-07 22:54:06 +01:00
//--------------------------------------------------------------------------------------------------
//
// clock generation
//
//--------------------------------------------------------------------------------------------------
2019-02-04 17:46:29 +01:00
always @(posedge i_clk) begin
if (!i_reset) begin
2019-02-11 20:27:51 +01:00
clk_phase <= clk_phase + 1;
2019-02-17 08:35:26 +01:00
ck_debugger <= clk_phase[1:0] == `PH_DEBUGGER;
2019-02-16 22:38:44 +01:00
2019-02-17 08:35:26 +01:00
ck_bus_send <= clk_phase[1:0] == `PH_BUS_SEND;
ck_bus_recv <= clk_phase[1:0] == `PH_BUS_RECV;
ck_bus_ecmd <= clk_phase[1:0] == `PH_BUS_ECMD;
2019-02-16 22:38:44 +01:00
2019-02-17 08:35:26 +01:00
ck_inst_dec <= clk_phase[1:0] == `PH_INST_DEC;
ck_inst_exe <= clk_phase[1:0] == `PH_INST_EXE;
2019-02-16 22:38:44 +01:00
2019-02-17 08:35:26 +01:00
ck_alu_dump <= clk_phase[1:0] == `PH_ALU_DUMP;
ck_alu_init <= clk_phase[1:0] == `PH_ALU_INIT;
ck_alu_prep <= clk_phase[1:0] == `PH_ALU_PREP;
ck_alu_calc <= clk_phase[1:0] == `PH_ALU_CALC;
ck_alu_save <= clk_phase[1:0] == `PH_ALU_SAVE;
2019-02-16 22:38:44 +01:00
cycle_ctr <= cycle_ctr + { {31{1'b0}}, (clk_phase[1:0] == `PH_BUS_SEND) };
2019-02-14 22:14:52 +01:00
if (cycle_ctr == (max_cycle + 1)) begin
$display(".-----------------------------.");
$display("| OUT OF CYCLES %d |", cycle_ctr);
$display("`-----------------------------´");
2019-02-11 19:49:22 +01:00
clock_end <= 1;
2019-02-14 22:14:52 +01:00
end
2019-02-11 19:49:22 +01:00
end else begin
2019-02-11 20:27:51 +01:00
clk_phase <= ~0;
2019-02-16 22:38:44 +01:00
2019-02-17 08:35:26 +01:00
ck_debugger <= 0;
2019-02-16 22:38:44 +01:00
2019-02-17 08:35:26 +01:00
ck_bus_send <= 0;
ck_bus_recv <= 0;
ck_bus_ecmd <= 0;
2019-02-16 22:38:44 +01:00
2019-02-17 08:35:26 +01:00
ck_inst_dec <= 0;
ck_inst_exe <= 0;
2019-02-16 22:38:44 +01:00
2019-02-17 08:35:26 +01:00
ck_alu_dump <= 0;
ck_alu_init <= 0;
ck_alu_prep <= 0;
ck_alu_calc <= 0;
ck_alu_save <= 0;
2019-02-16 22:38:44 +01:00
2019-02-13 22:43:04 +01:00
clock_end <= 0;
cycle_ctr <= ~0;
max_cycle <= 650;
2019-02-16 22:38:44 +01:00
mem_ctrl_stall <= 0;
`ifndef SIM
2019-02-13 22:43:04 +01:00
led[7:0] <= reg_pc[7:0];
`endif
2019-02-11 19:24:57 +01:00
end
end
2019-02-04 09:59:35 +01:00
//--------------------------------------------------------------------------------------------------
//
// test cases
//
//--------------------------------------------------------------------------------------------------
2019-02-16 22:38:44 +01:00
wire dec_stalled;
wire alu_stalled;
assign dec_stalled = alu_stalls_dec || bus_stalls_core;
assign alu_stalled = bus_stalls_core;
`ifdef SIM
assign o_halt = clock_end || inv_opcode;
`endif
2019-02-07 22:54:06 +01:00
2019-02-04 22:08:17 +01:00
// Verilator lint_off UNUSED
//wire [N-1:0] unused;
//assign unused = { };
// Verilator lint_on UNUSED
2019-02-04 09:59:35 +01:00
endmodule
`ifdef SIM
2019-02-04 17:46:29 +01:00
module saturn_tb;
2019-02-04 09:59:35 +01:00
saturn_core saturn (
.i_clk (clk),
.i_reset (reset),
.o_halt (halt),
.i_bus_data_in (core_bus_data_in),
.o_bus_data_out (core_bus_data_out),
.o_bus_strobe (core_bus_strobe),
.o_bus_cmd_data (core_bus_cmd_data)
2019-02-04 09:59:35 +01:00
);
reg [0:0] clk;
reg [0:0] reset;
wire [0:0] halt;
reg [3:0] core_bus_data_in;
wire [3:0] core_bus_data_out;
wire [0:0] core_bus_strobe;
wire [0:0] core_bus_cmd_data;
2019-02-04 09:59:35 +01:00
always
#10 clk = (clk === 1'b0);
initial begin
// $monitor ("c %b | r %b | in %h | out %h | str %b | cd %b",
// clk, reset, core_bus_data_in, core_bus_data_out, core_bus_strobe, core_bus_cmd_data);
2019-02-04 09:59:35 +01:00
end
initial begin
2019-02-04 15:02:33 +01:00
$display("starting the simulation");
2019-02-04 09:59:35 +01:00
clk <= 0;
reset <= 1;
@(posedge clk);
2019-02-07 22:54:06 +01:00
@(posedge clk);
@(posedge clk);
2019-02-04 09:59:35 +01:00
reset <= 0;
@(posedge halt);
$finish;
end
endmodule
2019-02-13 22:43:04 +01:00
`endif