From 28483afe9adbc0e88fbfabeca4421fee4943d03a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Jacquot?= Date: Tue, 5 Mar 2019 05:39:34 +0100 Subject: [PATCH] implement CONFIG and RTN* (0[0-3]) --- saturn_bus.v | 2 +- saturn_bus_controller.v | 3 ++ saturn_control_unit.v | 63 +++++++++++++++++++++++++++++++++++++++-- saturn_debugger.v | 34 ++++------------------ saturn_def_alu.v | 8 ++++-- saturn_inst_decoder.v | 22 +++++++++++++- saturn_regs_pc_rstk.v | 30 ++++++++++++++++++++ 7 files changed, 128 insertions(+), 34 deletions(-) diff --git a/saturn_bus.v b/saturn_bus.v index 7f3d706..f7949d2 100644 --- a/saturn_bus.v +++ b/saturn_bus.v @@ -167,7 +167,7 @@ always @(posedge i_clk) begin end `ifdef SIM - if (cycle_ctr == 110) begin + if (cycle_ctr == 130) begin bus_halt <= 1'b1; $display("BUS %0d: [%d] enough cycles for now", phase, cycle_ctr); end diff --git a/saturn_bus_controller.v b/saturn_bus_controller.v index 5527842..eeee6f5 100644 --- a/saturn_bus_controller.v +++ b/saturn_bus_controller.v @@ -91,6 +91,7 @@ saturn_control_unit control_unit ( /* 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), @@ -121,6 +122,7 @@ wire [0:0] ctrl_unit_no_read; /* 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; @@ -158,6 +160,7 @@ saturn_debugger debugger ( /* 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), diff --git a/saturn_control_unit.v b/saturn_control_unit.v index 202e1c6..69a18cd 100644 --- a/saturn_control_unit.v +++ b/saturn_control_unit.v @@ -46,6 +46,7 @@ module saturn_control_unit ( o_current_pc, o_reg_alu_mode, + o_reg_carry, o_reg_p, o_reg_hst, o_reg_st, @@ -91,7 +92,7 @@ assign o_error = control_unit_error || dec_error; output wire [19:0] o_current_pc; output wire [0:0] o_reg_alu_mode; -assign o_reg_alu_mode = reg_alu_mode; +output wire [0:0] o_reg_carry; output wire [3:0] o_reg_p; output wire [3:0] o_reg_hst; output wire [15:0] o_reg_st; @@ -114,6 +115,8 @@ output wire [0:0] o_instr_decoded; output wire [0:0] o_instr_execute; assign o_current_pc = reg_PC; +assign o_reg_alu_mode = reg_alu_mode; +assign o_reg_carry = reg_CARRY; assign o_reg_p = reg_P; assign o_reg_hst = reg_HST; assign o_reg_st = reg_ST; @@ -157,6 +160,7 @@ saturn_inst_decoder instruction_decoder( .o_alu_opcode (dec_alu_opcode), .o_jump_length (dec_jump_length), + .o_block_0x (dec_block_0x), .o_instr_type (dec_instr_type), .o_push_pc (dec_push_pc), @@ -175,6 +179,8 @@ wire [3:0] dec_alu_imm_value; wire [4:0] dec_alu_opcode; wire [2:0] dec_jump_length; +/* this is necessary to identify possible RTN in time */ +wire [0:0] dec_block_0x; wire [3:0] dec_instr_type; wire [0:0] dec_push_pc; @@ -189,6 +195,7 @@ wire [0:0] dec_error; wire [0:0] inst_alu = (dec_instr_type == `INSTR_TYPE_ALU); wire [0:0] inst_jump = (dec_instr_type == `INSTR_TYPE_JUMP); +wire [0:0] inst_rtn = (dec_instr_type == `INSTR_TYPE_RTN); wire [0:0] reg_dest_c = (dec_alu_reg_dest == `ALU_REG_C); wire [0:0] reg_dest_hst = (dec_alu_reg_dest == `ALU_REG_HST); @@ -236,7 +243,9 @@ saturn_regs_pc_rstk regs_pc_rstk ( .i_nibble (i_nibble), .i_jump_instr (inst_jump), .i_jump_length (dec_jump_length), + .i_block_0x (dec_block_0x), .i_push_pc (dec_push_pc), + .i_rtn_instr (inst_rtn), .o_current_pc (reg_PC), .o_reload_pc (reload_PC), @@ -254,6 +263,7 @@ saturn_regs_pc_rstk regs_pc_rstk ( reg [0:0] reg_alu_mode; +reg [0:0] reg_CARRY; reg [3:0] reg_C[0:15]; reg [3:0] reg_HST; reg [15:0] reg_ST; @@ -284,6 +294,7 @@ reg [4:0] bus_program[0:31]; reg [4:0] bus_prog_addr; reg [2:0] addr_nibble_ptr; reg [0:0] load_pc_loop; +reg [0:0] send_reg_C_A; reg [0:0] send_pc_read; wire [3:0] reg_PC_nibble = reg_PC[addr_nibble_ptr*4+:4]; @@ -301,9 +312,12 @@ initial begin bus_prog_addr = 5'd0; addr_nibble_ptr = 3'd0; load_pc_loop = 1'b0; + send_reg_C_A = 1'b0; + send_pc_read = 1'b0; /* registers */ reg_alu_mode = 1'b0; + reg_CARRY = 1'b0; reg_HST = 4'b0; reg_ST = 16'b0; reg_P = 4'b0; @@ -448,6 +462,17 @@ always @(posedge i_clk) begin reg_alu_mode <= dec_alu_imm_value[0]; end `INSTR_TYPE_JUMP: begin end + `INSTR_TYPE_RTN: + begin + case (dec_alu_opcode) + `ALU_OP_SET_CRY: reg_CARRY <= o_alu_imm_value[0]; + default: + begin + $display("CTRL %0d: [%d] alu_opcode for RTN %0d", i_phase, i_cycle_ctr, dec_alu_opcode); + control_unit_error <= 1'b1; + end + endcase + end `INSTR_TYPE_LOAD: begin case (dec_alu_reg_dest) @@ -457,9 +482,21 @@ always @(posedge i_clk) begin $display("CTRL %0d: [%d] C[%2d] <= %h", i_phase, i_cycle_ctr, dec_alu_ptr_begin, dec_alu_imm_value); reg_C[dec_alu_ptr_begin] <= dec_alu_imm_value; end - default: $display("CTRL %0d: [%d] unsupported register for load %0d", i_phase, i_cycle_ctr, dec_alu_reg_dest); + default: + begin + $display("CTRL %0d: [%d] unsupported register for load %0d", i_phase, i_cycle_ctr, dec_alu_reg_dest); + control_unit_error <= 1'b1; + end endcase end + `INSTR_TYPE_CONFIG: + begin + $display("CTRL %0d: [%d] exec : CONFIG", i_phase, i_cycle_ctr); + bus_program[bus_prog_addr] <= {1'b1, `BUSCMD_CONFIGURE }; + bus_prog_addr <= bus_prog_addr + 5'd1; + addr_nibble_ptr <= 3'b0; + send_reg_C_A <= 1'b1; + end `INSTR_TYPE_RESET: begin $display("CTRL %0d: [%d] exec : RESET", i_phase, i_cycle_ctr); @@ -470,10 +507,29 @@ always @(posedge i_clk) begin default: begin $display("CTRL %0d: [%d] unsupported instruction", i_phase, i_cycle_ctr); + control_unit_error <= 1'b1; end endcase end + + /* + * send C(A) + * used for CONFIG and UNCNFG + */ + if (send_reg_C_A) begin + bus_program[bus_prog_addr] <= { 1'b0, reg_C[{1'b0, addr_nibble_ptr}]}; + addr_nibble_ptr <= addr_nibble_ptr + 3'd1; + bus_prog_addr <= bus_prog_addr + 5'd1; + if (addr_nibble_ptr == 3'd4) begin + addr_nibble_ptr <= 3'd0; + send_pc_read <= 1'b1; + send_reg_C_A <= 1'b0; + end + end + /* + * sends the PC_READ command to restore devices after some other bus command + */ if (send_pc_read) begin $display("CTRL %0d: [%d] exec : RESET - send PC_READ", i_phase, i_cycle_ctr); bus_program[bus_prog_addr] <= {1'b1, `BUSCMD_PC_READ }; @@ -493,9 +549,12 @@ always @(posedge i_clk) begin bus_prog_addr <= 5'd0; addr_nibble_ptr <= 3'd0; load_pc_loop <= 1'b0; + send_reg_C_A <= 1'b0; + send_pc_read <= 1'b0; /* registers */ reg_alu_mode <= 1'b0; + reg_CARRY <= 1'b0; reg_HST <= 4'b0; reg_ST <= 16'b0; reg_P <= 4'b0; diff --git a/saturn_debugger.v b/saturn_debugger.v index 13eed2b..09db021 100644 --- a/saturn_debugger.v +++ b/saturn_debugger.v @@ -36,6 +36,7 @@ module saturn_debugger ( /* interface from the control unit */ i_current_pc, i_reg_alu_mode, + i_reg_carry, i_reg_hst, i_reg_st, i_reg_p, @@ -81,6 +82,7 @@ output reg [0:0] o_debug_cycle; /* inteface from the control unit */ input wire [19:0] i_current_pc; input wire [0:0] i_reg_alu_mode; +input wire [0:0] i_reg_carry; input wire [3:0] i_reg_hst; input wire [15:0] i_reg_st; input wire [3:0] i_reg_p; @@ -135,8 +137,6 @@ reg [6:0] registers_state; reg [5:0] registers_reg_ptr; reg [0:0] registers_done; -reg [0:0] carry; - initial begin o_debug_cycle = 1'b0; counter = 9'd0; @@ -164,7 +164,6 @@ initial begin registers_done = 1'b0; o_char_valid = 1'b0; o_char_send = 1'b0; - carry = 1'b1; end /************************************************************************************************** @@ -243,7 +242,7 @@ always @(posedge i_clk) begin 6'd4: registers_str[registers_ctr] <= "y"; 6'd5: registers_str[registers_ctr] <= ":"; 6'd6: registers_str[registers_ctr] <= " "; - 6'd7: registers_str[registers_ctr] <= hex[{3'b000,carry}]; + 6'd7: registers_str[registers_ctr] <= hex[{3'b000,i_reg_carry}]; 6'd8: registers_str[registers_ctr] <= " "; endcase registers_reg_ptr <= registers_reg_ptr + 6'd1; @@ -538,36 +537,15 @@ always @(posedge i_clk) begin end end + /* + * dumps nibbles read from the bus + */ if (i_bus_read_valid) begin o_char_send <= ~o_char_send; o_char_to_send <= hex[i_bus_nibble_in]; o_char_valid <= 1'b1; end - if (i_clk_en && i_bus_busy) begin - o_char_send <= ~o_char_send; - case (i_phase) - 2'b00: o_char_to_send <= "!"; - 2'b01: o_char_to_send <= "@"; - 2'b10: o_char_to_send <= "#"; - 2'b11: o_char_to_send <= "$"; - endcase - if (i_instr_decoded) o_char_to_send <= "="; - o_char_valid <= 1'b1; - end - - if (i_clk_en && i_instr_execute && i_phases[3]) begin - o_char_send <= ~o_char_send; - o_char_to_send <= "^"; - o_char_valid <= 1'b1; - end - - if (i_clk_en && i_instr_decoded && i_phases[3]) begin - o_char_send <= ~o_char_send; - o_char_to_send <= "|"; - o_char_valid <= 1'b1; - end - /* clear the char clock enable */ if (o_char_valid) begin o_char_valid <= 1'b0; diff --git a/saturn_def_alu.v b/saturn_def_alu.v index fffa0d3..6ff618a 100644 --- a/saturn_def_alu.v +++ b/saturn_def_alu.v @@ -47,6 +47,7 @@ `define ALU_OP_JMP_ABS5 20 `define ALU_OP_CLR_MASK 21 +`define ALU_OP_SET_CRY 28 `define ALU_OP_TEST_GO 30 `define ALU_OP_NOP 31 @@ -101,8 +102,11 @@ `define INSTR_TYPE_ALU 1 `define INSTR_TYPE_SET_MODE 2 `define INSTR_TYPE_JUMP 3 -`define INSTR_TYPE_LOAD 4 -`define INSTR_TYPE_RESET 5 +`define INSTR_TYPE_RTN 4 +`define INSTR_TYPE_LOAD 5 +`define INSTR_TYPE_CONFIG 6 +`define INSTR_TYPE_RESET 7 + `define INSTR_TYPE_NONE 15 diff --git a/saturn_inst_decoder.v b/saturn_inst_decoder.v index c7c7541..b38e5d6 100644 --- a/saturn_inst_decoder.v +++ b/saturn_inst_decoder.v @@ -47,6 +47,7 @@ module saturn_inst_decoder ( o_alu_opcode, o_jump_length, + o_block_0x, o_instr_type, o_push_pc, @@ -82,6 +83,8 @@ output reg [3:0] o_alu_imm_value; output reg [4:0] o_alu_opcode; output reg [2:0] o_jump_length; +output wire [0:0] o_block_0x; +assign o_block_0x = block_0x; output reg [3:0] o_instr_type; output reg [0:0] o_push_pc; @@ -247,9 +250,19 @@ always @(posedge i_clk) begin if (block_0x) begin case (i_nibble) + 4'h2, 4'h3: + begin + $display("DECODER %0d: [%d] RTN%cC", i_phase, i_cycle_ctr, i_nibble[0]?"C":"S"); + o_instr_type <= `INSTR_TYPE_RTN; + o_alu_imm_value <= {3'b000, !i_nibble[0]}; + o_alu_opcode <= `ALU_OP_SET_CRY; + o_instr_decoded <= 1'b1; + o_instr_execute <= 1'b1; + decode_started <= 1'b0; + end 4'h4, 4'h5: begin - o_instr_type <= `INSTR_TYPE_SET_MODE; + o_instr_type <= `INSTR_TYPE_SET_MODE; o_alu_imm_value <= {3'b000, i_nibble[0]}; o_instr_decoded <= 1'b1; o_instr_execute <= 1'b1; @@ -323,6 +336,13 @@ always @(posedge i_clk) begin if (block_80x) begin case (i_nibble) + 4'h5: /* CONFIG */ + begin + o_instr_type <= `INSTR_TYPE_CONFIG; + o_instr_decoded <= 1'b1; + o_instr_execute <= 1'b1; + decode_started <= 1'b0; + end 4'hA: /* RESET */ begin o_instr_type <= `INSTR_TYPE_RESET; diff --git a/saturn_regs_pc_rstk.v b/saturn_regs_pc_rstk.v index e51ef28..dc16c68 100644 --- a/saturn_regs_pc_rstk.v +++ b/saturn_regs_pc_rstk.v @@ -33,7 +33,9 @@ module saturn_regs_pc_rstk ( i_nibble, i_jump_instr, i_jump_length, + i_block_0x, i_push_pc, + i_rtn_instr, o_current_pc, o_reload_pc, @@ -56,7 +58,9 @@ input wire [0:0] i_bus_busy; input wire [3:0] i_nibble; input wire [0:0] i_jump_instr; input wire [2:0] i_jump_length; +input wire [0:0] i_block_0x; input wire [0:0] i_push_pc; +input wire [0:0] i_rtn_instr; output wire [19:0] o_current_pc; output reg [0:0] o_reload_pc; @@ -196,6 +200,32 @@ always @(posedge i_clk) begin o_reload_pc <= 1'b0; end + /* + * RTN instruction + */ + + /* this happens at the same time in the decoder */ + if (i_phases[2] && i_block_0x && (i_nibble[3:2] == 2'b00)) begin + /* this is an RTN */ + $write("PC_RSTK %0d: [%d] RTN", i_phase, i_cycle_ctr); + case (i_nibble) + 4'h0: $display("SXM"); + 4'h2: $display("SC"); + 4'h3: $display("CC"); + default: begin end + endcase + o_reload_pc <= 1'b1; + end + + if (i_phases[3] && i_rtn_instr) begin + $display("PC_RSTK %0d: [%d] execute RTN back to %5h", i_phase, i_cycle_ctr, reg_RSTK[reg_rstk_ptr]); + reg_PC <= reg_RSTK[reg_rstk_ptr]; + reg_RSTK[reg_rstk_ptr] <= 20'h00000; + reg_rstk_ptr <= (reg_rstk_ptr - 3'd1) & 3'd7; + /* o_reload_pc was set in advance above */ + o_reload_pc <= 1'b0; + end + end // if (i_phases[0] && i_clk_en) begin