implement CONFIG and RTN* (0[0-3])

This commit is contained in:
Raphaël Jacquot 2019-03-05 05:39:34 +01:00
parent 9168cbc1a2
commit 28483afe9a
7 changed files with 128 additions and 34 deletions

View file

@ -167,7 +167,7 @@ always @(posedge i_clk) begin
end end
`ifdef SIM `ifdef SIM
if (cycle_ctr == 110) begin if (cycle_ctr == 130) begin
bus_halt <= 1'b1; bus_halt <= 1'b1;
$display("BUS %0d: [%d] enough cycles for now", phase, cycle_ctr); $display("BUS %0d: [%d] enough cycles for now", phase, cycle_ctr);
end end

View file

@ -91,6 +91,7 @@ saturn_control_unit control_unit (
/* debugger interface */ /* debugger interface */
.o_current_pc (ctrl_current_pc), .o_current_pc (ctrl_current_pc),
.o_reg_alu_mode (ctrl_reg_alu_mode), .o_reg_alu_mode (ctrl_reg_alu_mode),
.o_reg_carry (ctrl_reg_carry),
.o_reg_hst (ctrl_reg_hst), .o_reg_hst (ctrl_reg_hst),
.o_reg_st (ctrl_reg_st), .o_reg_st (ctrl_reg_st),
.o_reg_p (ctrl_reg_p), .o_reg_p (ctrl_reg_p),
@ -121,6 +122,7 @@ wire [0:0] ctrl_unit_no_read;
/* debugger insterface */ /* debugger insterface */
wire [19:0] ctrl_current_pc; wire [19:0] ctrl_current_pc;
wire [0:0] ctrl_reg_alu_mode; wire [0:0] ctrl_reg_alu_mode;
wire [0:0] ctrl_reg_carry;
wire [3:0] ctrl_reg_hst; wire [3:0] ctrl_reg_hst;
wire [15:0] ctrl_reg_st; wire [15:0] ctrl_reg_st;
wire [3:0] ctrl_reg_p; wire [3:0] ctrl_reg_p;
@ -158,6 +160,7 @@ saturn_debugger debugger (
/* debugger interface */ /* debugger interface */
.i_current_pc (ctrl_current_pc), .i_current_pc (ctrl_current_pc),
.i_reg_alu_mode (ctrl_reg_alu_mode), .i_reg_alu_mode (ctrl_reg_alu_mode),
.i_reg_carry (ctrl_reg_carry),
.i_reg_hst (ctrl_reg_hst), .i_reg_hst (ctrl_reg_hst),
.i_reg_st (ctrl_reg_st), .i_reg_st (ctrl_reg_st),
.i_reg_p (ctrl_reg_p), .i_reg_p (ctrl_reg_p),

View file

@ -46,6 +46,7 @@ module saturn_control_unit (
o_current_pc, o_current_pc,
o_reg_alu_mode, o_reg_alu_mode,
o_reg_carry,
o_reg_p, o_reg_p,
o_reg_hst, o_reg_hst,
o_reg_st, o_reg_st,
@ -91,7 +92,7 @@ assign o_error = control_unit_error || dec_error;
output wire [19:0] o_current_pc; output wire [19:0] o_current_pc;
output wire [0:0] o_reg_alu_mode; 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_p;
output wire [3:0] o_reg_hst; output wire [3:0] o_reg_hst;
output wire [15:0] o_reg_st; 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; output wire [0:0] o_instr_execute;
assign o_current_pc = reg_PC; 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_p = reg_P;
assign o_reg_hst = reg_HST; assign o_reg_hst = reg_HST;
assign o_reg_st = reg_ST; assign o_reg_st = reg_ST;
@ -157,6 +160,7 @@ saturn_inst_decoder instruction_decoder(
.o_alu_opcode (dec_alu_opcode), .o_alu_opcode (dec_alu_opcode),
.o_jump_length (dec_jump_length), .o_jump_length (dec_jump_length),
.o_block_0x (dec_block_0x),
.o_instr_type (dec_instr_type), .o_instr_type (dec_instr_type),
.o_push_pc (dec_push_pc), .o_push_pc (dec_push_pc),
@ -175,6 +179,8 @@ wire [3:0] dec_alu_imm_value;
wire [4:0] dec_alu_opcode; wire [4:0] dec_alu_opcode;
wire [2:0] dec_jump_length; 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 [3:0] dec_instr_type;
wire [0:0] dec_push_pc; 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_alu = (dec_instr_type == `INSTR_TYPE_ALU);
wire [0:0] inst_jump = (dec_instr_type == `INSTR_TYPE_JUMP); 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_c = (dec_alu_reg_dest == `ALU_REG_C);
wire [0:0] reg_dest_hst = (dec_alu_reg_dest == `ALU_REG_HST); 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_nibble (i_nibble),
.i_jump_instr (inst_jump), .i_jump_instr (inst_jump),
.i_jump_length (dec_jump_length), .i_jump_length (dec_jump_length),
.i_block_0x (dec_block_0x),
.i_push_pc (dec_push_pc), .i_push_pc (dec_push_pc),
.i_rtn_instr (inst_rtn),
.o_current_pc (reg_PC), .o_current_pc (reg_PC),
.o_reload_pc (reload_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_alu_mode;
reg [0:0] reg_CARRY;
reg [3:0] reg_C[0:15]; reg [3:0] reg_C[0:15];
reg [3:0] reg_HST; reg [3:0] reg_HST;
reg [15:0] reg_ST; reg [15:0] reg_ST;
@ -284,6 +294,7 @@ reg [4:0] bus_program[0:31];
reg [4:0] bus_prog_addr; reg [4:0] bus_prog_addr;
reg [2:0] addr_nibble_ptr; reg [2:0] addr_nibble_ptr;
reg [0:0] load_pc_loop; reg [0:0] load_pc_loop;
reg [0:0] send_reg_C_A;
reg [0:0] send_pc_read; reg [0:0] send_pc_read;
wire [3:0] reg_PC_nibble = reg_PC[addr_nibble_ptr*4+:4]; wire [3:0] reg_PC_nibble = reg_PC[addr_nibble_ptr*4+:4];
@ -301,9 +312,12 @@ initial begin
bus_prog_addr = 5'd0; bus_prog_addr = 5'd0;
addr_nibble_ptr = 3'd0; addr_nibble_ptr = 3'd0;
load_pc_loop = 1'b0; load_pc_loop = 1'b0;
send_reg_C_A = 1'b0;
send_pc_read = 1'b0;
/* registers */ /* registers */
reg_alu_mode = 1'b0; reg_alu_mode = 1'b0;
reg_CARRY = 1'b0;
reg_HST = 4'b0; reg_HST = 4'b0;
reg_ST = 16'b0; reg_ST = 16'b0;
reg_P = 4'b0; reg_P = 4'b0;
@ -448,6 +462,17 @@ always @(posedge i_clk) begin
reg_alu_mode <= dec_alu_imm_value[0]; reg_alu_mode <= dec_alu_imm_value[0];
end end
`INSTR_TYPE_JUMP: begin 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: `INSTR_TYPE_LOAD:
begin begin
case (dec_alu_reg_dest) 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); $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; reg_C[dec_alu_ptr_begin] <= dec_alu_imm_value;
end 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 endcase
end 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: `INSTR_TYPE_RESET:
begin begin
$display("CTRL %0d: [%d] exec : RESET", i_phase, i_cycle_ctr); $display("CTRL %0d: [%d] exec : RESET", i_phase, i_cycle_ctr);
@ -470,10 +507,29 @@ always @(posedge i_clk) begin
default: default:
begin begin
$display("CTRL %0d: [%d] unsupported instruction", i_phase, i_cycle_ctr); $display("CTRL %0d: [%d] unsupported instruction", i_phase, i_cycle_ctr);
control_unit_error <= 1'b1;
end end
endcase endcase
end 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 if (send_pc_read) begin
$display("CTRL %0d: [%d] exec : RESET - send PC_READ", i_phase, i_cycle_ctr); $display("CTRL %0d: [%d] exec : RESET - send PC_READ", i_phase, i_cycle_ctr);
bus_program[bus_prog_addr] <= {1'b1, `BUSCMD_PC_READ }; bus_program[bus_prog_addr] <= {1'b1, `BUSCMD_PC_READ };
@ -493,9 +549,12 @@ always @(posedge i_clk) begin
bus_prog_addr <= 5'd0; bus_prog_addr <= 5'd0;
addr_nibble_ptr <= 3'd0; addr_nibble_ptr <= 3'd0;
load_pc_loop <= 1'b0; load_pc_loop <= 1'b0;
send_reg_C_A <= 1'b0;
send_pc_read <= 1'b0;
/* registers */ /* registers */
reg_alu_mode <= 1'b0; reg_alu_mode <= 1'b0;
reg_CARRY <= 1'b0;
reg_HST <= 4'b0; reg_HST <= 4'b0;
reg_ST <= 16'b0; reg_ST <= 16'b0;
reg_P <= 4'b0; reg_P <= 4'b0;

View file

@ -36,6 +36,7 @@ module saturn_debugger (
/* interface from the control unit */ /* interface from the control unit */
i_current_pc, i_current_pc,
i_reg_alu_mode, i_reg_alu_mode,
i_reg_carry,
i_reg_hst, i_reg_hst,
i_reg_st, i_reg_st,
i_reg_p, i_reg_p,
@ -81,6 +82,7 @@ output reg [0:0] o_debug_cycle;
/* inteface from the control unit */ /* inteface from the control unit */
input wire [19:0] i_current_pc; input wire [19:0] i_current_pc;
input wire [0:0] i_reg_alu_mode; input wire [0:0] i_reg_alu_mode;
input wire [0:0] i_reg_carry;
input wire [3:0] i_reg_hst; input wire [3:0] i_reg_hst;
input wire [15:0] i_reg_st; input wire [15:0] i_reg_st;
input wire [3:0] i_reg_p; input wire [3:0] i_reg_p;
@ -135,8 +137,6 @@ reg [6:0] registers_state;
reg [5:0] registers_reg_ptr; reg [5:0] registers_reg_ptr;
reg [0:0] registers_done; reg [0:0] registers_done;
reg [0:0] carry;
initial begin initial begin
o_debug_cycle = 1'b0; o_debug_cycle = 1'b0;
counter = 9'd0; counter = 9'd0;
@ -164,7 +164,6 @@ initial begin
registers_done = 1'b0; registers_done = 1'b0;
o_char_valid = 1'b0; o_char_valid = 1'b0;
o_char_send = 1'b0; o_char_send = 1'b0;
carry = 1'b1;
end end
/************************************************************************************************** /**************************************************************************************************
@ -243,7 +242,7 @@ always @(posedge i_clk) begin
6'd4: registers_str[registers_ctr] <= "y"; 6'd4: registers_str[registers_ctr] <= "y";
6'd5: registers_str[registers_ctr] <= ":"; 6'd5: registers_str[registers_ctr] <= ":";
6'd6: 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] <= " "; 6'd8: registers_str[registers_ctr] <= " ";
endcase endcase
registers_reg_ptr <= registers_reg_ptr + 6'd1; registers_reg_ptr <= registers_reg_ptr + 6'd1;
@ -538,36 +537,15 @@ always @(posedge i_clk) begin
end end
end end
/*
* dumps nibbles read from the bus
*/
if (i_bus_read_valid) begin if (i_bus_read_valid) begin
o_char_send <= ~o_char_send; o_char_send <= ~o_char_send;
o_char_to_send <= hex[i_bus_nibble_in]; o_char_to_send <= hex[i_bus_nibble_in];
o_char_valid <= 1'b1; o_char_valid <= 1'b1;
end 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 */ /* clear the char clock enable */
if (o_char_valid) begin if (o_char_valid) begin
o_char_valid <= 1'b0; o_char_valid <= 1'b0;

View file

@ -47,6 +47,7 @@
`define ALU_OP_JMP_ABS5 20 `define ALU_OP_JMP_ABS5 20
`define ALU_OP_CLR_MASK 21 `define ALU_OP_CLR_MASK 21
`define ALU_OP_SET_CRY 28
`define ALU_OP_TEST_GO 30 `define ALU_OP_TEST_GO 30
`define ALU_OP_NOP 31 `define ALU_OP_NOP 31
@ -101,8 +102,11 @@
`define INSTR_TYPE_ALU 1 `define INSTR_TYPE_ALU 1
`define INSTR_TYPE_SET_MODE 2 `define INSTR_TYPE_SET_MODE 2
`define INSTR_TYPE_JUMP 3 `define INSTR_TYPE_JUMP 3
`define INSTR_TYPE_LOAD 4 `define INSTR_TYPE_RTN 4
`define INSTR_TYPE_RESET 5 `define INSTR_TYPE_LOAD 5
`define INSTR_TYPE_CONFIG 6
`define INSTR_TYPE_RESET 7
`define INSTR_TYPE_NONE 15 `define INSTR_TYPE_NONE 15

View file

@ -47,6 +47,7 @@ module saturn_inst_decoder (
o_alu_opcode, o_alu_opcode,
o_jump_length, o_jump_length,
o_block_0x,
o_instr_type, o_instr_type,
o_push_pc, o_push_pc,
@ -82,6 +83,8 @@ output reg [3:0] o_alu_imm_value;
output reg [4:0] o_alu_opcode; output reg [4:0] o_alu_opcode;
output reg [2:0] o_jump_length; 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 [3:0] o_instr_type;
output reg [0:0] o_push_pc; output reg [0:0] o_push_pc;
@ -247,6 +250,16 @@ always @(posedge i_clk) begin
if (block_0x) begin if (block_0x) begin
case (i_nibble) 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: 4'h4, 4'h5:
begin begin
o_instr_type <= `INSTR_TYPE_SET_MODE; o_instr_type <= `INSTR_TYPE_SET_MODE;
@ -323,6 +336,13 @@ always @(posedge i_clk) begin
if (block_80x) begin if (block_80x) begin
case (i_nibble) 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 */ 4'hA: /* RESET */
begin begin
o_instr_type <= `INSTR_TYPE_RESET; o_instr_type <= `INSTR_TYPE_RESET;

View file

@ -33,7 +33,9 @@ module saturn_regs_pc_rstk (
i_nibble, i_nibble,
i_jump_instr, i_jump_instr,
i_jump_length, i_jump_length,
i_block_0x,
i_push_pc, i_push_pc,
i_rtn_instr,
o_current_pc, o_current_pc,
o_reload_pc, o_reload_pc,
@ -56,7 +58,9 @@ input wire [0:0] i_bus_busy;
input wire [3:0] i_nibble; input wire [3:0] i_nibble;
input wire [0:0] i_jump_instr; input wire [0:0] i_jump_instr;
input wire [2:0] i_jump_length; 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_push_pc;
input wire [0:0] i_rtn_instr;
output wire [19:0] o_current_pc; output wire [19:0] o_current_pc;
output reg [0:0] o_reload_pc; output reg [0:0] o_reload_pc;
@ -196,6 +200,32 @@ always @(posedge i_clk) begin
o_reload_pc <= 1'b0; o_reload_pc <= 1'b0;
end 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 end
// if (i_phases[0] && i_clk_en) begin // if (i_phases[0] && i_clk_en) begin