implement more instructions

This commit is contained in:
Raphael Jacquot 2019-02-14 22:14:52 +01:00
parent 94ab98a175
commit 4b7e59fa21
8 changed files with 194 additions and 73 deletions

12
README
View file

@ -17,4 +17,14 @@ phase_1: ________________________| |_____________________________
_________
phase_2: __________________________________| |___________________
_________
phase_3: ____________________________________________| |_________
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"

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
3 4 1 0 0 0 0
F A // NOP3