From 4b7e59fa21fe651e23106cb905c066f8fe46189f Mon Sep 17 00:00:00 2001 From: Raphael Jacquot Date: Thu, 14 Feb 2019 22:14:52 +0100 Subject: [PATCH] implement more instructions --- README | 12 +++- def-alu.v | 1 + history.txt | 1 + saturn-core.ESP5.ys | 2 +- saturn_alu.v | 70 +++++++++++++++--- saturn_core.v | 8 ++- saturn_decoder.v | 169 +++++++++++++++++++++++++++++--------------- testrom-2.hex | 4 +- 8 files changed, 194 insertions(+), 73 deletions(-) diff --git a/README b/README index dde30bd..b0d7541 100644 --- a/README +++ b/README @@ -17,4 +17,14 @@ phase_1: ________________________| |_____________________________ _________ phase_2: __________________________________| |___________________ _________ -phase_3: ____________________________________________| |_________ \ No newline at end of file +phase_3: ____________________________________________| |_________ + +notes for using the ULX3S + +Maybe linux ujprog won't find port because of insufficient priviledge. Either run ujprog as root or have udev rule:# this is for usb-serial tty device +SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", \ +MODE="664", GROUP="dialout" +this is for ujprog libusb access + +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", \ +GROUP="dialout", MODE="666" \ No newline at end of file diff --git a/def-alu.v b/def-alu.v index 895cecb..2216e40 100644 --- a/def-alu.v +++ b/def-alu.v @@ -39,6 +39,7 @@ `define ALU_OP_JMP_REL3 18 `define ALU_OP_JMP_REL4 19 `define ALU_OP_JMP_ABS5 20 +`define ALU_OP_CLR_MASK 21 // registers diff --git a/history.txt b/history.txt index 932db49..9594315 100644 --- a/history.txt +++ b/history.txt @@ -24,3 +24,4 @@ 2019-02-13 14:53 51 153.35MHz 16.74ns 3.40ns 273 155.47MHz 5.53ns 2.09ns 2019-02-13 23:21 318 113.77MHz 25.44ns 13.97ns 3061 117.75MHz 9.56ns 4.08ns 2019-02-14 09:00 353 118.23MHz 26.00ns 12.28ns 3334 119.40MHz 10.08ns 3.84ns +2019-02-14 22:11 403 115.09Mhz 27.38ns 11.32ns 2430 111.51Mhz 12.62ns 3.57ns diff --git a/saturn-core.ESP5.ys b/saturn-core.ESP5.ys index 792c617..6219226 100644 --- a/saturn-core.ESP5.ys +++ b/saturn-core.ESP5.ys @@ -1,2 +1,2 @@ -read_verilog -I. saturn-core.v +read_verilog -I. saturn_core.v synth_ecp5 -top saturn_core -json saturn-core.json diff --git a/saturn_alu.v b/saturn_alu.v index 973dc79..1d41544 100644 --- a/saturn_alu.v +++ b/saturn_alu.v @@ -17,10 +17,10 @@ module saturn_alu ( i_clk, i_reset, i_en_alu_dump, - i_en_alu_prep, - i_en_alu_calc, + i_en_alu_prep, + i_en_alu_calc, i_en_alu_init, - i_en_alu_save, + i_en_alu_save, i_push, i_pop, @@ -101,10 +101,11 @@ reg [3:0] f_last; reg [3:0] p_src1; reg [3:0] p_src2; -reg p_carry; +reg [0:0] p_carry; reg [3:0] c_res1; reg [3:0] c_res2; -reg c_carry; +reg [0:0] c_carry; +reg [0:0] is_zero; /* alu status */ @@ -159,6 +160,14 @@ initial begin alu_run = 0; alu_done = 0; + + p_src1 = 0; + p_src2 = 0; + p_carry = 0; + c_res1 = 0; + c_res2 = 0; + c_carry = 0; + is_zero = 0; // o_alu_stall_dec = 0; // processor registers PC = 0; @@ -271,7 +280,6 @@ always @(posedge i_clk) begin `endif end - always @(posedge i_clk) begin // this happens in phase 3, right after the instruction decoder (in phase 2) is finished if (do_alu_init) begin @@ -330,13 +338,12 @@ always @(posedge i_clk) begin `endif end - // setup value for src1 - case (alu_op) `ALU_OP_ZERO: begin end // no source required `ALU_OP_COPY, `ALU_OP_RST_BIT, `ALU_OP_SET_BIT, + `ALU_OP_2CMPL, `ALU_OP_JMP_REL3, `ALU_OP_JMP_REL4, `ALU_OP_JMP_ABS5: @@ -349,10 +356,16 @@ always @(posedge i_clk) begin `ALU_REG_D1: p_src1 <= D1[f_start*4+:4]; `ALU_REG_P: p_src1 <= P; `ALU_REG_IMM: p_src1 <= i_imm_value; + default: $display("####UNHANDLED REGISTER %0d", reg_src1); endcase + default: $display("####UNHANDLED OPERATION %0d", alu_op); endcase // setup p_carry + // $display("fs %h | fs=0 %b | cc %b | npc %b", f_start, (f_start == 0), c_carry, (f_start == 0)?1'b1:c_carry); + case (alu_op) + `ALU_OP_2CMPL: p_carry <= (f_start == 0)?1'b1:c_carry; + endcase end end @@ -380,6 +393,11 @@ always @(posedge i_clk) begin `ALU_OP_COPY, `ALU_OP_RST_BIT, `ALU_OP_SET_BIT: c_res1 <= p_src1; + `ALU_OP_2CMPL: begin + c_carry <= (~p_src1 == 4'hf) && p_carry ; + c_res1 <= ~p_src1 + p_carry; + is_zero <= ((~p_src1 + p_carry) == 0) && (f_start == 0)?1:is_zero; + end `ALU_OP_JMP_REL3, `ALU_OP_JMP_REL4, `ALU_OP_JMP_ABS5: jump_off[f_start*4+:4] <= p_src1; @@ -391,6 +409,11 @@ always @(posedge i_clk) begin `ALU_OP_JMP_REL4: if (alu_finish) jump_off <= { {4{p_src1[3]}}, p_src1, jump_off[11:0] }; endcase + + // $display("-------C- SRC1 %b %h | ~SRC1 %b %h | PC %b | RES1 %b %h | CC %b", + // p_src1, p_src1, ~p_src1, ~p_src1, p_carry, + // (~p_src1) + p_carry, (~p_src1) + p_carry, + // (~p_src1) == 4'hf ); end end @@ -407,11 +430,20 @@ always @(posedge i_clk) begin alu_run, alu_done, o_alu_stall_dec, alu_op, f_start, f_last, jump_bse, jump_off, jump_pc, alu_finish); `endif + // $display("-------S- SRC1 %b %h | ~SRC1 %b %h | PC %b | RES1 %b %h | CC %b", + // p_src1, p_src1, ~p_src1, ~p_src1, p_carry, + // (~p_src1) + p_carry, (~p_src1) + p_carry, + // (~p_src1) == 4'hf ); + case (alu_op) `ALU_OP_ZERO, - `ALU_OP_COPY: + `ALU_OP_COPY, + `ALU_OP_2CMPL: case (reg_dest) + `ALU_REG_A: A [f_start*4+:4] <= c_res1; + `ALU_REG_B: B [f_start*4+:4] <= c_res1; `ALU_REG_C: C [f_start*4+:4] <= c_res1; + `ALU_REG_D: D [f_start*4+:4] <= c_res1; `ALU_REG_D0: D0[f_start*4+:4] <= c_res1; `ALU_REG_D1: D1[f_start*4+:4] <= c_res1; `ALU_REG_ST: ST[f_start*4+:4] <= c_res1; @@ -426,11 +458,21 @@ always @(posedge i_clk) begin endcase endcase + case (alu_op) + `ALU_OP_2CMPL: CARRY <= !is_zero; + endcase + end end wire [19:0] next_pc; -assign next_pc = (is_alu_op_jump && alu_finish)?jump_pc:PC + 1; +wire [0:0] update_pc; +wire [0:0] push_pc; + +assign next_pc = (is_alu_op_jump && alu_finish)?jump_pc:PC + 1; +assign update_pc = !o_alu_stall_dec || is_alu_op_jump; +assign push_pc = update_pc && i_push && alu_done; + always @(posedge i_clk) begin if (i_reset) PC <= ~0; @@ -454,9 +496,15 @@ always @(posedge i_clk) begin $display("ALU_PC 3: !stl %b | nx %5h | jmp %b | push %b", !o_alu_stall_dec, next_pc, is_alu_op_jump, i_push); `endif - if (!o_alu_stall_dec || is_alu_op_jump) begin + if (update_pc) begin PC <= next_pc; end + + if (push_pc) begin + $display("PUSH PC %5h to RSTK[%0d]", PC, rstk_ptr); + RSTK[rstk_ptr] <= PC; + rstk_ptr <= rstk_ptr + 1; + end end end diff --git a/saturn_core.v b/saturn_core.v index 2e945ad..a9e2b35 100644 --- a/saturn_core.v +++ b/saturn_core.v @@ -251,8 +251,12 @@ always @(posedge clk) begin en_inst_exec <= clk_phase[1:0] == 3; cycle_ctr <= cycle_ctr + { {31{1'b0}}, (clk_phase[1:0] == 0) }; // stop after 50 clocks - if (cycle_ctr == (max_cycle + 1)) + if (cycle_ctr == (max_cycle + 1)) begin + $display(".-------------------."); + $display("| OUT OF CYCLES |"); + $display("`-------------------ยด"); clock_end <= 1; + end end else begin clk_phase <= ~0; en_alu_dump <= 0; @@ -267,7 +271,7 @@ always @(posedge clk) begin en_inst_exec <= 0; clock_end <= 0; cycle_ctr <= ~0; - max_cycle <= 40; + max_cycle <= 100; `ifndef SIM led[7:0] <= reg_pc[7:0]; `endif diff --git a/saturn_decoder.v b/saturn_decoder.v index 79fabdf..b4e325f 100644 --- a/saturn_decoder.v +++ b/saturn_decoder.v @@ -46,6 +46,7 @@ module saturn_decoder( o_set_xm, o_set_carry, o_en_intr, + o_test_carry, o_carry_val, o_ins_set_mode, o_mode_dec, @@ -101,6 +102,7 @@ output reg o_direction; output reg o_ins_rtn; output reg o_set_xm; output reg o_set_carry; +output reg o_test_carry; output reg o_carry_val; output reg o_en_intr; @@ -124,7 +126,7 @@ output reg [4:0] o_mem_pos; * state registers */ -reg [31:0] instr_ctr; +reg [31:0] inst_counter; reg [0:0] next_nibble; reg [4:0] inst_cycles; @@ -190,7 +192,7 @@ always @(posedge i_clk) begin */ `ifdef SIM if (o_ins_decoded) begin - $write("DBG 0: "); + $write("DBG[%5d]: ", inst_counter); $write("%5h ", o_ins_addr); // $write("[%2d] ", o_dbg_nb_nbls); @@ -205,10 +207,9 @@ always @(posedge i_clk) begin $write("RT%s", o_en_intr?"I":"N"); if (o_set_xm) $write("SXM"); if (o_set_carry) $write("%sC", o_carry_val?"S":"C"); - $display(""); end if (o_ins_set_mode) begin - $display("SET%s", o_mode_dec?"DEC":"HEX"); + $write("SET%s", o_mode_dec?"DEC":"HEX"); end if (o_ins_alu_op) begin @@ -254,6 +255,7 @@ always @(posedge i_clk) begin `ALU_OP_RST_BIT, `ALU_OP_SET_BIT: if (!is_lc_hex) $write("="); + `ALU_OP_2CMPL: $write("=-"); `ALU_OP_EXCH, `ALU_OP_JMP_REL3, `ALU_OP_JMP_REL4, @@ -269,7 +271,8 @@ always @(posedge i_clk) begin `ALU_OP_INC, `ALU_OP_DEC, `ALU_OP_ADD, - `ALU_OP_SUB: + `ALU_OP_SUB, + `ALU_OP_2CMPL: case (o_reg_src1) `ALU_REG_A: $write("A"); `ALU_REG_B: $write("B"); @@ -336,6 +339,7 @@ always @(posedge i_clk) begin // (o_reg_dest == `ALU_REG_P) || (o_reg_src1 == `ALU_REG_P ))) begin $write("\t"); if (o_field_valid) begin + // $write("[FT%d]", o_fields_table); if (o_fields_table != `FT_TABLE_value) case (o_field) @@ -350,24 +354,26 @@ always @(posedge i_clk) begin `FT_FIELD_A: $write("A"); endcase else $write("%0d", o_field_last+1); + end else begin + // $write("@%b@", is_load_imm); + if (is_load_imm) begin + if (is_p_eq) $write("%0d", o_imm_value); + else + for(nibble_pos=(o_mem_pos - 1); nibble_pos!=31; nibble_pos=nibble_pos-1) + $write("%h", o_mem_load[nibble_pos*4+:4]); + end + else + case (o_reg_dest) + `ALU_REG_P, + `ALU_REG_ST: begin end + `ALU_REG_C: + if (o_reg_src1 == `ALU_REG_P) + $write("%0d", o_field_start); + default: $write("[%h:%h]", o_field_start, o_field_last); + endcase end - - // $write("@%b@", is_load_imm); - if (is_load_imm) begin - if (is_p_eq) $write("%0d", o_imm_value); - else - for(nibble_pos=(o_mem_pos - 1); nibble_pos!=31; nibble_pos=nibble_pos-1) - $write("%h", o_mem_load[nibble_pos*4+:4]); - end - else - case (o_reg_dest) - `ALU_REG_P, - `ALU_REG_ST: begin end - default: $write("[%h:%h]", o_field_start, o_field_last); - endcase - - $display("\t(%0d cycles)", inst_cycles); end + $display("\t(%0d cycles)", inst_cycles); end // $display("new [%5h]--------------------------------------------------------------------", new_pc); `endif @@ -400,6 +406,8 @@ reg block_jmp2_cry_clr; reg block_8x; reg block_80x; +reg block_80Cx; +reg block_82x; reg block_Fx; @@ -432,12 +440,11 @@ wire do_block_mem_transfer; wire do_block_pointer_arith_const; wire do_block_load_p; wire do_block_load_c_hex; -wire do_block_jmp2_cry_set; -wire do_block_jmp2_cry_clr; wire do_block_8x; wire do_block_80x; - +wire do_block_80Cx; +wire do_block_82x; wire do_block_Fx; assign do_block_0x = do_on_other_nibbles && block_0x; @@ -455,11 +462,11 @@ assign do_block_mem_transfer = do_on_other_nibbles && block_mem_transfer; assign do_block_pointer_arith_const = do_on_other_nibbles && block_pointer_arith_const; assign do_block_load_p = do_on_other_nibbles && block_load_p; assign do_block_load_c_hex = do_on_other_nibbles && block_load_c_hex; -assign do_block_jmp2_cry_set = do_on_other_nibbles && block_jmp2_cry_set; -assign do_block_jmp2_cry_clr = do_on_other_nibbles && block_jmp2_cry_clr; assign do_block_8x = do_on_other_nibbles && block_8x; assign do_block_80x = do_on_other_nibbles && block_80x; +assign do_block_80Cx = do_on_other_nibbles && block_80Cx; +assign do_block_82x = do_on_other_nibbles && block_82x; assign do_block_Fx = do_on_other_nibbles && block_Fx; @@ -497,6 +504,7 @@ assign dbg_write_pos = (!next_nibble?0:o_dbg_nb_nbls); always @(posedge i_clk) begin if (i_reset) begin inst_cycles <= 0; + inst_counter <= 0; next_nibble <= 0; use_fields_tbl <= 0; o_inc_pc <= 1; @@ -530,6 +538,7 @@ always @(posedge i_clk) begin * cleanup */ if (do_on_first_nibble) begin + inst_counter <= inst_counter + 1; inst_cycles <= 1; next_nibble <= 1; use_fields_tbl <= 0; @@ -555,12 +564,11 @@ always @(posedge i_clk) begin block_pointer_arith_const <= 0; block_load_p <= 0; block_load_c_hex <= 0; - block_jmp2_cry_set <= 0; - block_jmp2_cry_clr <= 0; - + block_8x <= 0; block_80x <= 0; - + block_80Cx <= 0; + block_82x <= 0; block_Fx <= 0; // decoder subroutine states @@ -605,13 +613,26 @@ always @(posedge i_clk) begin 4'h1: block_1x <= 1; 4'h2: block_load_p <= 1; 4'h3: block_load_c_hex <= 1; - 4'h4: block_jmp2_cry_set <= 1; - 4'h5: block_jmp2_cry_clr <= 1; - 4'h6: begin + 4'h4, 4'h5: begin + // 400 RTNC + // 420 NOP3 + // 4xy GOC + // 500 RTNNC + // 5xy GONC + o_alu_no_stall <= 1; + o_alu_op <= `ALU_OP_JMP_REL2; + mem_load_max <= 1; + o_mem_pos <= 0; + o_test_carry <= 1; + o_carry_val <= !i_nibble[0]; + block_jmp <= 1; + end + 4'h6, 4'h7: begin o_alu_no_stall <= 1; o_alu_op <= `ALU_OP_JMP_REL3; mem_load_max <= 2; - o_mem_pos <= 0; + o_mem_pos <= 0; + o_push <= i_nibble[0]; block_jmp <= 1; end 4'h8: block_8x <= 1; @@ -810,16 +831,14 @@ always @(posedge i_clk) begin block_load_c_hex <= 0; end - if (do_block_jmp2_cry_clr) begin - - end - if (do_block_8x) begin $display("block_8x %h | op %d", i_nibble, o_alu_op); case (i_nibble) 4'h0: // block_80x <= 1; + 4'h2: + block_82x <= 1; 4'h4, 4'h5: // ST=[01] n begin o_alu_op <= i_nibble[0]?`ALU_OP_SET_BIT:`ALU_OP_RST_BIT; @@ -837,7 +856,7 @@ always @(posedge i_clk) begin o_mem_pos <= 0; block_jmp <= 1; // debug for cases not tested - o_alu_debug <= i_nibble[1] || !i_nibble[0]; + o_alu_debug <= !i_nibble[0]; end default: begin $display("block_8x %h error", i_nibble); @@ -850,13 +869,11 @@ always @(posedge i_clk) begin if (do_block_80x) begin $display("block_80x %h | op %d", i_nibble, o_alu_op); case (i_nibble) - 4'hC: // C=P n - begin - o_ins_alu_op <= 1; - o_alu_op <= `ALU_OP_COPY; - next_nibble <= 0; - o_ins_decoded <= 1; + 4'hA: begin // RESET + next_nibble <= 0; + o_ins_decoded <= 1; end + 4'hC: block_80Cx <= 1; default: begin $display("block_80x %h error", i_nibble); o_dec_error <= 1; @@ -865,10 +882,38 @@ always @(posedge i_clk) begin block_80x <= 0; end + if (do_block_80Cx) begin + o_ins_alu_op <= 1; + o_alu_op <= `ALU_OP_COPY; + next_nibble <= 0; + o_ins_decoded <= 1; + end + + // 821 XM=0 + // 822 SB=0 + // 824 SR=0 + // 828 MP=0 + // 82F CLRHST + // 82x CLRHST x + if (do_block_82x) begin + o_ins_alu_op <= 1; + o_alu_op <= `ALU_OP_CLR_MASK; + next_nibble <= 0; + o_ins_decoded <= 1; + end + if (do_block_Fx) begin - $display("block_Fx %h | op %d", i_nibble, o_alu_op); case (i_nibble) + 4'h8, 4'h9, 4'hA, 4'hB: // r=-r A + begin + o_fields_table <= `FT_TABLE_f; + //o_alu_debug <= 1; + o_ins_alu_op <= 1; + o_alu_op <= `ALU_OP_2CMPL; + next_nibble <= 0; + o_ins_decoded <= 1; + end default: begin $display("block_Fx %h error", i_nibble); o_dec_error <= 1; @@ -1076,17 +1121,22 @@ always @(posedge i_clk) begin endcase end - if (do_block_80x) begin + if (do_block_80Cx) begin + o_reg_dest <= `ALU_REG_C; + o_reg_src1 <= `ALU_REG_P; + o_reg_src2 <= 0; + end + + if (do_block_Fx) begin case (i_nibble) - 4'hC: begin - o_reg_dest <= `ALU_REG_C; - o_reg_src1 <= `ALU_REG_P; - o_reg_src2 <= 0; + 4'h8, 4'h9, 4'hA, 4'hB: begin + o_reg_dest <= reg_ABCD; + o_reg_src1 <= reg_ABCD; + o_reg_src2 <= 0; end endcase end - end @@ -1240,11 +1290,18 @@ always @(posedge i_clk) begin endcase end - if (do_block_80x) begin + if (do_block_80Cx) begin + o_field_start <= i_nibble; + o_field_last <= i_nibble; + end + + if (do_block_Fx) begin case (i_nibble) - 4'hC: begin - o_field_start <= i_nibble; - o_field_last <= i_nibble; + 4'h8, 4'h9, 4'hA, 4'hB: begin + o_field <= `FT_FIELD_A; + o_field_start <= 0; + o_field_last <= 4; + o_field_valid <= 1; end endcase end diff --git a/testrom-2.hex b/testrom-2.hex index 775cb3a..cb31a03 100644 --- a/testrom-2.hex +++ b/testrom-2.hex @@ -1,2 +1,2 @@ -3 F 0 1 2 3 4 5 6 7 8 9 A B C D E F -6 3 2 7 // NOP3 \ No newline at end of file +3 4 1 0 0 0 0 +F A // NOP3 \ No newline at end of file