hp-saturn/saturn_core.v

472 lines
9.8 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 //
`include "bus_commands.v"
2019-02-09 00:01:48 +01:00
`include "hp48_00_bus.v"
2019-02-11 09:13:16 +01:00
`include "dbg_module.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 (
2019-02-04 15:02:33 +01:00
input clk,
input reset,
output halt,
2019-02-07 22:54:06 +01:00
output [3:0] busstate,
2019-02-09 19:18:58 +01:00
output [11:0] decstate
2019-02-04 18:17:14 +01:00
);
2019-02-04 17:46:29 +01:00
`else
2019-02-04 18:17:14 +01:00
module saturn_core (
input clk_25mhz,
2019-02-10 12:04:53 +01:00
input [ 6:0] btn,
// output wifi_gpio0,
2019-02-04 22:08:17 +01:00
output [7:0] led
2019-02-04 09:59:35 +01:00
);
2019-02-04 22:08:17 +01:00
wire clk;
wire reset;
2019-02-07 22:54:06 +01:00
reg clk2;
2019-02-04 18:17:14 +01:00
2019-02-10 12:04:53 +01:00
// assign wifi_gpio0 = 1'b1;
2019-02-04 18:17:14 +01:00
assign clk = clk_25mhz;
assign reset = btn[1];
`endif
2019-02-04 09:59:35 +01:00
2019-02-07 22:54:06 +01:00
// clocks
2019-02-11 19:49:22 +01:00
reg [31:0] clk_phase;
2019-02-11 19:24:57 +01:00
reg en_debugger; // phase 0
reg en_bus_send; // phase 0
reg en_bus_recv; // phase 1
reg en_alu_prep; // phase 1
reg en_alu_calc; // phase 2
reg en_inst_dec; // phase 2
2019-02-11 19:49:22 +01:00
reg en_alu_save; // phase 3
2019-02-11 19:24:57 +01:00
reg en_inst_exec; // phase 3
2019-02-11 19:49:22 +01:00
reg clock_end;
2019-02-07 22:54:06 +01:00
2019-02-04 09:59:35 +01:00
// state machine stuff
2019-02-07 22:54:06 +01:00
wire halt;
2019-02-11 09:13:16 +01:00
reg cycle_ctr_ready;
2019-02-07 22:54:06 +01:00
reg [31:0] cycle_ctr;
2019-02-08 12:46:32 +01:00
reg [31:0] instr_ctr;
2019-02-07 22:54:06 +01:00
reg decode_error;
reg debug_stop;
2019-02-08 19:09:13 +01:00
reg [3:0] cycle_type;
reg [3:0] next_cycle;
2019-02-07 22:54:06 +01:00
reg read_next_pc;
reg execute_cycle;
reg inc_pc;
2019-02-07 22:54:06 +01:00
reg read_nibble;
reg first_nibble;
2019-02-09 19:18:58 +01:00
reg [11:0] decstate;
2019-02-10 18:46:26 +01:00
reg [11:0] fields_return;
reg [3:0] regdump;
2019-02-04 09:59:35 +01:00
// bus access
reg [19:0] bus_address;
2019-02-06 10:40:55 +01:00
reg [3:0] bus_command;
reg [3:0] bus_nibble_in;
wire [3:0] bus_nibble_out;
wire bus_error;
reg bus_load_pc;
2019-02-08 11:47:06 +01:00
reg en_bus_load_pc;
// should go away, the rom should work like any other bus module
2019-02-10 18:46:26 +01:00
reg [7:0] display_counter;
2019-02-05 08:49:14 +01:00
2019-02-04 09:59:35 +01:00
// internal registers
reg [19:0] new_PC;
2019-02-08 11:47:06 +01:00
reg [19:0] next_PC;
2019-02-08 11:15:16 +01:00
reg [19:0] inst_start_PC;
2019-02-09 19:18:58 +01:00
2019-02-04 09:59:35 +01:00
reg [2:0] rstk_ptr;
2019-02-09 19:18:58 +01:00
2019-02-04 09:59:35 +01:00
reg [19:0] jump_base;
reg [19:0] jump_offset;
2019-02-09 19:18:58 +01:00
2019-02-04 15:02:33 +01:00
reg hex_dec;
2019-02-07 22:54:06 +01:00
`define MODE_HEX 0;
`define MODE_DEC 1;
2019-02-05 07:07:19 +01:00
// data transfer registers
reg [3:0] t_offset;
reg [3:0] t_cnt;
reg [3:0] t_ctr;
reg t_dir;
reg t_ptr;
reg t_reg;
2019-02-10 12:04:53 +01:00
reg t_ftype;
2019-02-05 07:07:19 +01:00
reg [3:0] t_field;
2019-02-04 09:59:35 +01:00
2019-02-09 19:18:58 +01:00
reg [3:0] nb_in;
reg [3:0] nb_out;
reg [19:0] add_out;
2019-02-10 12:04:53 +01:00
// temporary stuff
reg t_set_test;
reg t_set_test_val;
2019-02-10 13:39:56 +01:00
reg t_add_sub;
2019-02-10 18:46:26 +01:00
reg [3:0] t_first;
reg [3:0] t_last;
// alu control
reg [3:0] field;
reg [1:0] field_table;
reg [4:0] alu_op;
2019-02-10 18:46:26 +01:00
reg [3:0] alu_first;
reg [3:0] alu_last;
reg [3:0] alu_const;
2019-02-10 18:46:26 +01:00
reg [3:0] alu_reg_src1;
reg [3:0] alu_reg_src2;
reg [3:0] alu_reg_dest;
reg [3:0] alu_src1;
reg [3:0] alu_src2;
2019-02-11 07:04:42 +01:00
reg [3:0] alu_res1;
reg [3:0] alu_res2;
reg alu_res_carry;
2019-02-10 18:46:26 +01:00
reg [3:0] alu_tmp;
reg alu_carry;
reg alu_debug;
2019-02-11 09:13:16 +01:00
reg alu_p1_halt;
reg alu_p2_halt;
2019-02-10 18:46:26 +01:00
reg alu_halt;
reg alu_requested_halt;
reg [11:0] alu_return;
reg [3:0] alu_next_cycle;
2019-02-10 12:04:53 +01:00
2019-02-11 09:13:16 +01:00
// debugger registers
reg [19:0] dbg_op_addr;
reg [15:0] dbg_op_code;
reg [3:0] dbg_reg_dest;
reg [3:0] dbg_reg_src1;
reg [3:0] dbg_reg_src2;
reg [3:0] dbg_field;
reg [3:0] dbg_first;
reg [3:0] dbg_last;
reg [63:0] dbg_data;
2019-02-04 09:59:35 +01:00
// processor registers
reg [19:0] PC;
reg [3:0] P;
reg [15:0] ST;
reg [3:0] HST;
2019-02-04 15:02:33 +01:00
reg Carry;
2019-02-04 09:59:35 +01:00
reg [19:0] RSTK[0:7];
reg [19:0] D0;
reg [19:0] D1;
reg [63:0] A;
reg [63:0] B;
reg [63:0] C;
reg [63:0] D;
reg [63:0] R0;
reg [63:0] R1;
reg [63:0] R2;
reg [63:0] R3;
reg [63:0] R4;
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)
// );
2019-02-07 22:54:06 +01:00
initial
begin
2019-02-11 19:24:57 +01:00
clk_phase = 0;
2019-02-11 19:49:22 +01:00
en_debugger = 0; // phase 0
en_bus_send = 0; // phase 0
en_bus_recv = 0; // phase 1
en_alu_prep = 0; // phase 1
en_alu_calc = 0; // phase 2
en_inst_dec = 0; // phase 2
en_alu_save = 0; // phase 3
en_inst_exec = 0; // phase 3
clock_end = 0;
2019-02-07 22:54:06 +01:00
$display("initialize cycle counter");
2019-02-11 09:13:16 +01:00
cycle_ctr_ready = 0;
cycle_ctr = 0;
2019-02-08 12:46:32 +01:00
instr_ctr = 0;
2019-02-11 09:13:16 +01:00
$display("initializing debugger");
dbg_op_code = 0;
2019-02-07 22:54:06 +01:00
$display("initializing bus_command");
bus_command = `BUSCMD_NOP;
$display("initializing busstate");
2019-02-08 19:09:13 +01:00
next_cycle = `BUSCMD_LOAD_PC;
2019-02-07 22:54:06 +01:00
$display("Initializing decstate");
decstate = 0;
$display("initializing control bits");
decode_error = 0;
debug_stop = 0;
2019-02-07 22:54:06 +01:00
bus_load_pc = 1;
2019-02-08 11:47:06 +01:00
en_bus_load_pc = 1;
2019-02-07 22:54:06 +01:00
read_next_pc = 1;
execute_cycle = 0;
inc_pc = 0;
2019-02-11 09:13:16 +01:00
alu_p1_halt = 0;
alu_p2_halt = 0;
2019-02-10 18:46:26 +01:00
alu_halt = 0;
alu_requested_halt = 0;
2019-02-07 22:54:06 +01:00
$display("should be initializing registers");
2019-02-08 00:02:55 +01:00
hex_dec = `MODE_HEX;
2019-02-07 22:54:06 +01:00
PC = 0;
new_PC = 0;
2019-02-08 11:47:06 +01:00
next_PC = 0;
2019-02-08 11:15:16 +01:00
inst_start_PC = 0;
2019-02-08 00:02:55 +01:00
rstk_ptr = 7;
2019-02-07 22:54:06 +01:00
2019-02-11 19:49:22 +01:00
$monitor("CLK %b | CLKP %d | eDBG %b | eBSND %b | eBRECV %b | eAPR %b | eACALC %b | eINDC %b | eASAVE %b | eINDX %b",
clk, clk_phase,
en_debugger, en_bus_send,
en_bus_recv, en_alu_prep,
en_alu_calc, en_inst_dec,
en_alu_save, en_inst_exec);
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
2019-02-11 19:24:57 +01:00
always @(posedge clk) begin
if (!reset) begin
clk_phase <= clk_phase + 1;
2019-02-11 19:49:22 +01:00
en_debugger <= clk_phase[1:0] == 0;
en_bus_send <= clk_phase[1:0] == 0;
en_bus_recv <= clk_phase[1:0] == 1;
en_alu_prep <= clk_phase[1:0] == 1;
en_alu_calc <= clk_phase[1:0] == 2;
en_inst_dec <= clk_phase[1:0] == 2;
en_alu_save <= clk_phase[1:0] == 3;
en_inst_exec <= clk_phase[1:0] == 3;
// stop after 50 clocks
if (clk_phase == 50)
clock_end <= 1;
end else begin
clk_phase <= 0;
en_debugger <= 0;
en_bus_send <= 0;
en_bus_recv <= 0;
en_alu_prep <= 0;
en_alu_calc <= 0;
en_inst_dec <= 0;
en_alu_save <= 0;
en_inst_exec <= 0;
clock_end <= 0;
2019-02-11 19:24:57 +01:00
end
end
2019-02-04 09:59:35 +01:00
//--------------------------------------------------------------------------------------------------
//
2019-02-07 22:54:06 +01:00
// bus control
2019-02-04 09:59:35 +01:00
//
//--------------------------------------------------------------------------------------------------
2019-02-08 21:11:47 +01:00
`include "fields.v"
// `include "bus_commands.v"
2019-02-11 19:49:22 +01:00
// always @(posedge bus_ctrl_clk)
// begin
// if (!reset) begin
// if (clk3) begin
// en_dec_clk <= 0;
// if (cycle_ctr_ready)
// cycle_ctr <= cycle_ctr + 1;
// else cycle_ctr_ready <= 1;
// case (next_cycle)
// `BUSCMD_NOP: begin
// bus_command <= `BUSCMD_NOP;
// // $display("BUS NOT READING, STILL CLOCKING");
// end
// `BUSCMD_PC_READ: begin
// bus_command <= `BUSCMD_PC_READ;
// en_bus_clk <= 1;
// PC <= next_PC;
// inc_pc <= 1;
// end
// `BUSCMD_DP_READ: begin
// bus_command <= `BUSCMD_DP_READ;
// en_bus_clk <= 1;
// end
// `BUSCMD_DP_WRITE: begin
// bus_command <= `BUSCMD_DP_WRITE;
// bus_nibble_in <= nb_out;
// en_bus_clk <= 1;
// end
// `BUSCMD_LOAD_PC: begin
// bus_command <= `BUSCMD_LOAD_PC;
// bus_address <= new_PC;
// next_PC <= new_PC;
// PC <= new_PC;
// en_bus_clk <= 1;
// end
// `BUSCMD_LOAD_DP: begin
// bus_command <= `BUSCMD_LOAD_DP;
// bus_address <= add_out;
// en_bus_clk <= 1;
// end
// `BUSCMD_CONFIGURE: begin
// bus_command <= `BUSCMD_CONFIGURE;
// bus_address <= add_out;
// en_bus_clk <= 1;
// end
// `BUSCMD_RESET: begin
// bus_command <= `BUSCMD_RESET;
// en_bus_clk <= 1;
// end
// default: begin
// $display("BUS PHASE 1: %h UNIMPLEMENTED", next_cycle);
// end
// endcase
// end
// else begin
// case (next_cycle)
// `BUSCMD_NOP: begin
// en_dec_clk <= 1;
// end
// `BUSCMD_PC_READ: begin
// nb_in <= bus_nibble_out;
// en_dec_clk <= 1;
// if (inc_pc) begin
// next_PC <= PC + 1;
// inc_pc <= 0;
// end
// // $display("reading nibble %h", bus_nibble_out);
// end
// `BUSCMD_DP_READ: begin
// nb_in <= bus_nibble_out;
// en_dec_clk <= 1;
// end
// `BUSCMD_DP_WRITE: begin
// // $display("BUS PHASE 2: DP_WRITE cnt %h | ctr %h", t_cnt, t_ctr);
// en_dec_clk <= 1;
// end
// `BUSCMD_LOAD_PC: begin
// // $display("CYCLE %d | INSTR %d -> BUSCMD_LOAD_PC %5h", cycle_ctr, instr_ctr, new_PC);
// en_dec_clk <= 1;
// end
// `BUSCMD_LOAD_DP: begin
// // $display("CYCLE %d | INSTR %d -> BUSCMD_LOAD_DP %s %5h",
// // cycle_ctr, instr_ctr, t_ptr?"D1":"D0", add_out);
// en_dec_clk <= 1;
// end
// `BUSCMD_CONFIGURE: begin
// // $display("CYCLE %d | INSTR %d -> BUSCMD_CONFIGURE %5h", cycle_ctr, instr_ctr, add_out);
// en_dec_clk <= 1;
// end
// `BUSCMD_RESET: begin
// // $display("CYCLE %d | INSTR %d -> BUSCMD_RESET", cycle_ctr, instr_ctr);
// en_dec_clk <= 1;
// end
// default: begin
// $display("BUS PHASE 2: %h UNIMPLEMENTED", next_cycle);
// end
// endcase
// en_bus_clk <= 0;
// end
// end
// else begin
// $display("RESET");
// end
// end
2019-02-11 19:24:57 +01:00
// always @(posedge ph0) begin
// if (dbg_op_code)
// case (dbg_op_code)
// default: begin
// `ifdef SIM
// $display("DEBUGGER - UNKNOWN OPCODE: %4h", dbg_op_code);
// `endif
// end
// endcase
// `ifdef SIM
// else $display("DEBUGGER - NOTHING TO DO");
// `endif
// end
// always @(posedge ph1) begin
// `include "opcodes/z_alu_phase_1.v"
// end
// always @(posedge ph2) begin
// `include "opcodes/z_alu_phase_2.v"
// end
// always @(posedge ph3) begin
// if (cycle_ctr == 890)
// debug_stop <= 1;
// end
2019-02-07 22:54:06 +01:00
2019-02-11 19:49:22 +01:00
assign halt = clock_end || bus_error || decode_error || debug_stop;
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 15:02:33 +01:00
reg clk;
reg reset;
2019-02-04 09:59:35 +01:00
wire halt;
2019-02-07 22:54:06 +01:00
wire [3:0] busstate;
2019-02-09 19:18:58 +01:00
wire [11:0] decstate;
2019-02-04 09:59:35 +01:00
saturn_core saturn (
2019-02-04 15:02:33 +01:00
.clk (clk),
.reset (reset),
.halt (halt),
2019-02-07 22:54:06 +01:00
.busstate (busstate),
2019-02-04 15:02:33 +01:00
.decstate (decstate)
2019-02-04 09:59:35 +01:00
);
always
#10 clk = (clk === 1'b0);
initial begin
2019-02-04 15:02:33 +01:00
//$monitor ("c %b | r %b | run %h | dec %h", clk, reset, runstate, decstate);
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-04 17:46:29 +01:00
`else
2019-02-04 09:59:35 +01:00
`endif