hp-saturn/saturn-decoder.v

336 lines
8.4 KiB
Coq
Raw Normal View History

2019-02-11 21:29:04 +01:00
/******************************************************************************
*
* Instruction decoder module
*
*****************************************************************************/
`include "def_fields.v"
2019-02-11 21:29:04 +01:00
module saturn_decoder(
2019-02-12 08:48:13 +01:00
i_clk,
i_reset,
i_cycles,
i_en_dbg,
i_en_dec,
i_stalled,
i_pc,
i_nibble,
o_inc_pc,
o_dec_error,
o_ins_addr,
o_ins_decoded,
o_fields_table,
o_field,
o_field_start,
o_field_last,
2019-02-12 08:48:13 +01:00
o_direction,
o_ins_rtn,
o_set_xm,
o_set_carry,
o_carry_val,
o_ins_set_mode,
o_mode_dec,
o_ins_rstk_c
);
2019-02-11 21:29:04 +01:00
/*
* module input / output ports
*/
input wire i_clk;
input wire i_reset;
input wire [31:0] i_cycles;
input wire i_en_dbg;
2019-02-11 21:29:04 +01:00
input wire i_en_dec;
2019-02-12 08:21:32 +01:00
input wire i_stalled;
input wire [19:0] i_pc;
2019-02-11 21:29:04 +01:00
input wire [3:0] i_nibble;
output reg o_inc_pc;
output reg o_dec_error;
2019-02-12 08:48:13 +01:00
// instructions related outputs
output reg [19:0] o_ins_addr;
output reg o_ins_decoded;
output reg [1:0] o_fields_table;
output reg [3:0] o_field;
output reg [3:0] o_field_start;
output reg [3:0] o_field_last;
2019-02-12 08:48:13 +01:00
// generic
output reg o_direction;
// rtn specific
output reg o_ins_rtn;
output reg o_set_xm;
output reg o_set_carry;
output reg o_carry_val;
// setdec/hex
output reg o_ins_set_mode;
output reg o_mode_dec;
// rstk and c
output reg o_ins_rstk_c;
2019-02-11 21:29:04 +01:00
/*
* state registers
*/
reg [31:0] instr_ctr;
initial begin
`ifdef SIM
2019-02-11 22:29:13 +01:00
// $monitor({"i_clk %b | i_reset %b | i_cycles %d | i_en_dec %b | i_en_exec %b |",
// " continue %b | instr_start %b | i_nibble %h"},
// i_clk, i_reset, i_cycles, i_en_dec, i_en_exec, continue,
// instr_start, i_nibble);
// $monitor("i_en_dec %b | i_cycles %d | nb %h | cont %b | b0x %b | rtn %b | sxm %b | sc %b | cv %b",
// i_en_dec, i_cycles, i_nibble, continue, block_0x, ins_rtn, set_xm, set_carry, carry_val);
`endif
2019-02-11 21:29:04 +01:00
end
/*
* debugger
*
*/
always @(posedge i_clk) begin
2019-02-12 08:21:32 +01:00
if (!i_reset && i_en_dbg && !i_stalled)
2019-02-12 08:48:13 +01:00
if (o_ins_decoded) begin
`ifdef SIM
2019-02-12 08:48:13 +01:00
$write("%5h ", o_ins_addr);
if (o_ins_rtn) begin
$write("RTN");
2019-02-12 08:48:13 +01:00
if (o_set_xm) $write("SXM");
if (o_set_carry) $write("%sC", o_carry_val?"S":"C");
$display("");
end
2019-02-12 08:48:13 +01:00
if (o_ins_set_mode) begin
$display("SET%s", o_mode_dec?"DEC":"HEX");
end
2019-02-12 08:48:13 +01:00
if (o_ins_rstk_c) begin
$display("%s", o_direction?"C=RSTK":"RSTK=C");
end
`endif
end
end
/******************************************************************************
*
* handle decoding of the fist nibble
2019-02-11 21:29:04 +01:00
* that's pretty simple though, will get tougher later on :-)
*
*****************************************************************************/
2019-02-11 21:29:04 +01:00
// general variables
reg continue;
reg block_0x;
reg block_0Efx;
reg fields_table;
2019-02-11 21:29:04 +01:00
always @(posedge i_clk) begin
if (i_reset) begin
2019-02-12 08:48:13 +01:00
continue <= 0;
o_inc_pc <= 1;
o_dec_error <= 0;
o_ins_decoded <= 0;
2019-02-11 21:29:04 +01:00
end else begin
2019-02-12 08:21:32 +01:00
if (i_en_dec && !i_stalled) begin
/*
* stuff that is always done
*/
o_inc_pc <= 1; // may be set to 0 later
/*
* cleanup
*/
if (!continue) begin
2019-02-12 08:48:13 +01:00
continue <= 1;
o_ins_decoded <= 0;
// store the address where the instruction starts
2019-02-12 08:48:13 +01:00
o_ins_addr <= i_pc;
// cleanup block variables
block_0x <= 0;
block_0Efx <= 0;
// cleanup fields table variables
fields_table <= 0;
o_fields_table <= 3;
o_field <= 0;
o_field_start <= 0;
o_field_last <= 0;
// cleanup
2019-02-12 08:48:13 +01:00
o_direction <= 0;
2019-02-12 08:48:13 +01:00
o_ins_rtn <= 0;
o_set_xm <= 0;
o_set_carry <= 0;
o_carry_val <= 0;
2019-02-12 08:48:13 +01:00
o_ins_set_mode <= 0;
o_mode_dec <= 0;
2019-02-12 08:48:13 +01:00
o_ins_rstk_c <= 0;
end
/*
* x first nibble
*/
if (!continue) begin
2019-02-11 22:29:13 +01:00
// assign block regs
case (i_nibble)
4'h0: block_0x <= 1;
default: begin
`ifdef SIM
$display("new_instruction: nibble %h not handled", i_nibble);
`endif
o_dec_error <= 1;
end
endcase
2019-02-11 22:29:13 +01:00
end
/******************************************************************************
*
* 0x
*
* 00 RTNSXM
* 01 RTN
* 02 RTNSC
* 03 RTNCC
2019-02-12 08:21:32 +01:00
* 04 SETHEX
* 05 SETDEC
* 06 RSTK=C
* 07 C=RSTK
*
*****************************************************************************/
2019-02-11 21:29:04 +01:00
2019-02-11 22:29:13 +01:00
if (continue && block_0x) begin
case (i_nibble)
4'h0, 4'h1, 4'h2, 4'h3: begin
2019-02-12 08:48:13 +01:00
o_ins_rtn <= 1;
o_set_xm <= (i_nibble == 4'h0);
o_set_carry <= (i_nibble[3:1] == 1);
o_carry_val <= (i_nibble[1] && i_nibble[0]);
end
4'h4, 4'h5: begin
o_ins_set_mode <= 1;
o_mode_dec <= (i_nibble[0]);
end
2019-02-12 08:48:13 +01:00
4'h6, 6'h7: begin
o_ins_rstk_c <= 1;
o_direction <= (i_nibble[0]);
end
2019-02-12 08:48:13 +01:00
4'hE: begin
block_0x <= 0;
o_fields_table <= `FT_TABLE_f;
end
default: begin
`ifdef SIM
$display("block_0x: nibble %h not handled", i_nibble);
`endif
o_dec_error <= 1;
end
2019-02-11 22:29:13 +01:00
endcase
continue <= (i_nibble == 4'hE);
block_0Efx <= (i_nibble == 4'hE);
fields_table <= (i_nibble == 4'hE);
o_ins_decoded <= (i_nibble != 4'hE);
end
2019-02-11 22:29:13 +01:00
2019-02-12 08:48:13 +01:00
/******************************************************************************
*
* 0Ex
*
*
*****************************************************************************/
if (continue && block_0Efx && !fields_table) begin
`ifdef SIM
$display("block_0Efx: nibble %h not handled", i_nibble);
`endif
2019-02-12 08:48:13 +01:00
continue <= 0;
o_dec_error <= 1;
end
/******************************************************************************
*
* fields f table
*
*
*****************************************************************************/
// `define DEBUG_FIELDS_TABLE
if (continue && fields_table) begin
if (fields_table != `FT_TABLE_value) begin
`ifdef DEBUG_FIELDS_TABLE
`ifdef SIM
$display("====== fields_table | table %h | nibble %b", o_fields_table, i_nibble);
$display("table_a : %b", ((o_fields_table == `FT_TABLE_a) && (!i_nibble[3])));
$display("table_b : %b", ((o_fields_table == `FT_TABLE_b) && ( i_nibble[3])));
$display("table_f_cond: %b", ((!i_nibble[3]) || (i_nibble == 4'hF)));
$display("table_f : %b", ((o_fields_table == `FT_TABLE_f) && ((!i_nibble[3]) || (i_nibble == 4'hF) )));
$display("table_f nbl : %h", {4{o_fields_table == `FT_TABLE_f}} );
$display("table_f val : %h", (i_nibble & {4{o_fields_table == `FT_TABLE_f}}) );
$display("case nibble : %h", ((i_nibble & 4'h7) | (i_nibble & {4{fields_table == `FT_TABLE_f}})) );
`endif
`endif
if (((o_fields_table == `FT_TABLE_a) && (!i_nibble[3])) ||
((o_fields_table == `FT_TABLE_b) && ( i_nibble[3])) ||
((o_fields_table == `FT_TABLE_f) && ((!i_nibble[3]) || (i_nibble == 4'hF) ))) begin
case ((i_nibble & 4'h7) | (i_nibble & {4{o_fields_table == `FT_TABLE_f}}))
4'hF: begin
if (o_fields_table == `FT_TABLE_f) begin
`ifdef SIM
$display("fields_table: field A");
`endif
end else begin
// should never happen...
`ifdef SIM
$display("fields_table: table %h nibble %h", o_fields_table, i_nibble);
`endif
end
end
default: begin
`ifdef SIM
$display("fields_table: table %h nibble %h not handled", o_fields_table, i_nibble);
`endif
o_dec_error <= 1;
end
endcase
end else begin
`ifdef SIM
$display("fields_table: table %h invalid nibble %h", o_fields_table, i_nibble);
`endif
o_dec_error <= 1;
end
end else begin
`ifdef SIM
$display("fields_table: there is nothing to decode for table FT_TABLE_value");
`endif
o_dec_error <= 1;
end
fields_table <= 0;
end
end
end
2019-02-11 21:29:04 +01:00
end
endmodule