diff options
Diffstat (limited to 'tests/openmsp430/rtl/omsp_frontend.v')
-rw-r--r-- | tests/openmsp430/rtl/omsp_frontend.v | 966 |
1 files changed, 966 insertions, 0 deletions
diff --git a/tests/openmsp430/rtl/omsp_frontend.v b/tests/openmsp430/rtl/omsp_frontend.v new file mode 100644 index 000000000..343944bd2 --- /dev/null +++ b/tests/openmsp430/rtl/omsp_frontend.v @@ -0,0 +1,966 @@ +//---------------------------------------------------------------------------- +// Copyright (C) 2009 , Olivier Girard +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the authors nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE +// +//---------------------------------------------------------------------------- +// +// *File Name: omsp_frontend.v +// +// *Module Description: +// openMSP430 Instruction fetch and decode unit +// +// *Author(s): +// - Olivier Girard, olgirard@gmail.com +// +//---------------------------------------------------------------------------- +// $Rev: 134 $ +// $LastChangedBy: olivier.girard $ +// $LastChangedDate: 2012-03-22 21:31:06 +0100 (Thu, 22 Mar 2012) $ +//---------------------------------------------------------------------------- +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_defines.v" +`endif + +module omsp_frontend ( + +// OUTPUTs + dbg_halt_st, // Halt/Run status from CPU + decode_noirq, // Frontend decode instruction + e_state, // Execution state + exec_done, // Execution completed + inst_ad, // Decoded Inst: destination addressing mode + inst_as, // Decoded Inst: source addressing mode + inst_alu, // ALU control signals + inst_bw, // Decoded Inst: byte width + inst_dest, // Decoded Inst: destination (one hot) + inst_dext, // Decoded Inst: destination extended instruction word + inst_irq_rst, // Decoded Inst: Reset interrupt + inst_jmp, // Decoded Inst: Conditional jump + inst_mov, // Decoded Inst: mov instruction + inst_sext, // Decoded Inst: source extended instruction word + inst_so, // Decoded Inst: Single-operand arithmetic + inst_src, // Decoded Inst: source (one hot) + inst_type, // Decoded Instruction type + irq_acc, // Interrupt request accepted (one-hot signal) + mab, // Frontend Memory address bus + mb_en, // Frontend Memory bus enable + mclk_enable, // Main System Clock enable + mclk_wkup, // Main System Clock wake-up (asynchronous) + nmi_acc, // Non-Maskable interrupt request accepted + pc, // Program counter + pc_nxt, // Next PC value (for CALL & IRQ) + +// INPUTs + cpu_en_s, // Enable CPU code execution (synchronous) + cpuoff, // Turns off the CPU + dbg_halt_cmd, // Halt CPU command + dbg_reg_sel, // Debug selected register for rd/wr access + fe_pmem_wait, // Frontend wait for Instruction fetch + gie, // General interrupt enable + irq, // Maskable interrupts + mclk, // Main system clock + mdb_in, // Frontend Memory data bus input + nmi_pnd, // Non-maskable interrupt pending + nmi_wkup, // NMI Wakeup + pc_sw, // Program counter software value + pc_sw_wr, // Program counter software write + puc_rst, // Main system reset + scan_enable, // Scan enable (active during scan shifting) + wdt_irq, // Watchdog-timer interrupt + wdt_wkup, // Watchdog Wakeup + wkup // System Wake-up (asynchronous) +); + +// OUTPUTs +//========= +output dbg_halt_st; // Halt/Run status from CPU +output decode_noirq; // Frontend decode instruction +output [3:0] e_state; // Execution state +output exec_done; // Execution completed +output [7:0] inst_ad; // Decoded Inst: destination addressing mode +output [7:0] inst_as; // Decoded Inst: source addressing mode +output [11:0] inst_alu; // ALU control signals +output inst_bw; // Decoded Inst: byte width +output [15:0] inst_dest; // Decoded Inst: destination (one hot) +output [15:0] inst_dext; // Decoded Inst: destination extended instruction word +output inst_irq_rst; // Decoded Inst: Reset interrupt +output [7:0] inst_jmp; // Decoded Inst: Conditional jump +output inst_mov; // Decoded Inst: mov instruction +output [15:0] inst_sext; // Decoded Inst: source extended instruction word +output [7:0] inst_so; // Decoded Inst: Single-operand arithmetic +output [15:0] inst_src; // Decoded Inst: source (one hot) +output [2:0] inst_type; // Decoded Instruction type +output [13:0] irq_acc; // Interrupt request accepted (one-hot signal) +output [15:0] mab; // Frontend Memory address bus +output mb_en; // Frontend Memory bus enable +output mclk_enable; // Main System Clock enable +output mclk_wkup; // Main System Clock wake-up (asynchronous) +output nmi_acc; // Non-Maskable interrupt request accepted +output [15:0] pc; // Program counter +output [15:0] pc_nxt; // Next PC value (for CALL & IRQ) + +// INPUTs +//========= +input cpu_en_s; // Enable CPU code execution (synchronous) +input cpuoff; // Turns off the CPU +input dbg_halt_cmd; // Halt CPU command +input [3:0] dbg_reg_sel; // Debug selected register for rd/wr access +input fe_pmem_wait; // Frontend wait for Instruction fetch +input gie; // General interrupt enable +input [13:0] irq; // Maskable interrupts +input mclk; // Main system clock +input [15:0] mdb_in; // Frontend Memory data bus input +input nmi_pnd; // Non-maskable interrupt pending +input nmi_wkup; // NMI Wakeup +input [15:0] pc_sw; // Program counter software value +input pc_sw_wr; // Program counter software write +input puc_rst; // Main system reset +input scan_enable; // Scan enable (active during scan shifting) +input wdt_irq; // Watchdog-timer interrupt +input wdt_wkup; // Watchdog Wakeup +input wkup; // System Wake-up (asynchronous) + + +//============================================================================= +// 1) UTILITY FUNCTIONS +//============================================================================= + +// 16 bits one-hot decoder +function [15:0] one_hot16; + input [3:0] binary; + begin + one_hot16 = 16'h0000; + one_hot16[binary] = 1'b1; + end +endfunction + +// 8 bits one-hot decoder +function [7:0] one_hot8; + input [2:0] binary; + begin + one_hot8 = 8'h00; + one_hot8[binary] = 1'b1; + end +endfunction + + +//============================================================================= +// 2) PARAMETER DEFINITIONS +//============================================================================= + +// +// 2.1) Instruction State machine definitons +//------------------------------------------- + +parameter I_IRQ_FETCH = `I_IRQ_FETCH; +parameter I_IRQ_DONE = `I_IRQ_DONE; +parameter I_DEC = `I_DEC; // New instruction ready for decode +parameter I_EXT1 = `I_EXT1; // 1st Extension word +parameter I_EXT2 = `I_EXT2; // 2nd Extension word +parameter I_IDLE = `I_IDLE; // CPU is in IDLE mode + +// +// 2.2) Execution State machine definitons +//------------------------------------------- + +parameter E_IRQ_0 = `E_IRQ_0; +parameter E_IRQ_1 = `E_IRQ_1; +parameter E_IRQ_2 = `E_IRQ_2; +parameter E_IRQ_3 = `E_IRQ_3; +parameter E_IRQ_4 = `E_IRQ_4; +parameter E_SRC_AD = `E_SRC_AD; +parameter E_SRC_RD = `E_SRC_RD; +parameter E_SRC_WR = `E_SRC_WR; +parameter E_DST_AD = `E_DST_AD; +parameter E_DST_RD = `E_DST_RD; +parameter E_DST_WR = `E_DST_WR; +parameter E_EXEC = `E_EXEC; +parameter E_JUMP = `E_JUMP; +parameter E_IDLE = `E_IDLE; + + +//============================================================================= +// 3) FRONTEND STATE MACHINE +//============================================================================= + +// The wire "conv" is used as state bits to calculate the next response +reg [2:0] i_state; +reg [2:0] i_state_nxt; + +reg [1:0] inst_sz; +wire [1:0] inst_sz_nxt; +wire irq_detect; +wire [2:0] inst_type_nxt; +wire is_const; +reg [15:0] sconst_nxt; +reg [3:0] e_state_nxt; + +// CPU on/off through the debug interface or cpu_en port +wire cpu_halt_cmd = dbg_halt_cmd | ~cpu_en_s; + +// States Transitions +always @(i_state or inst_sz or inst_sz_nxt or pc_sw_wr or exec_done or + irq_detect or cpuoff or cpu_halt_cmd or e_state) + case(i_state) + I_IDLE : i_state_nxt = (irq_detect & ~cpu_halt_cmd) ? I_IRQ_FETCH : + (~cpuoff & ~cpu_halt_cmd) ? I_DEC : I_IDLE; + I_IRQ_FETCH: i_state_nxt = I_IRQ_DONE; + I_IRQ_DONE : i_state_nxt = I_DEC; + I_DEC : i_state_nxt = irq_detect ? I_IRQ_FETCH : + (cpuoff | cpu_halt_cmd) & exec_done ? I_IDLE : + cpu_halt_cmd & (e_state==E_IDLE) ? I_IDLE : + pc_sw_wr ? I_DEC : + ~exec_done & ~(e_state==E_IDLE) ? I_DEC : // Wait in decode state + (inst_sz_nxt!=2'b00) ? I_EXT1 : I_DEC; // until execution is completed + I_EXT1 : i_state_nxt = pc_sw_wr ? I_DEC : + (inst_sz!=2'b01) ? I_EXT2 : I_DEC; + I_EXT2 : i_state_nxt = I_DEC; + // pragma coverage off + default : i_state_nxt = I_IRQ_FETCH; + // pragma coverage on + endcase + +// State machine +always @(posedge mclk or posedge puc_rst) + if (puc_rst) i_state <= I_IRQ_FETCH; + else i_state <= i_state_nxt; + +// Utility signals +wire decode_noirq = ((i_state==I_DEC) & (exec_done | (e_state==E_IDLE))); +wire decode = decode_noirq | irq_detect; +wire fetch = ~((i_state==I_DEC) & ~(exec_done | (e_state==E_IDLE))) & ~(e_state_nxt==E_IDLE); + +// Debug interface cpu status +reg dbg_halt_st; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) dbg_halt_st <= 1'b0; + else dbg_halt_st <= cpu_halt_cmd & (i_state_nxt==I_IDLE); + + +//============================================================================= +// 4) INTERRUPT HANDLING & SYSTEM WAKEUP +//============================================================================= + +// +// 4.1) INTERRUPT HANDLING +//----------------------------------------- + +// Detect reset interrupt +reg inst_irq_rst; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) inst_irq_rst <= 1'b1; + else if (exec_done) inst_irq_rst <= 1'b0; + +// Detect other interrupts +assign irq_detect = (nmi_pnd | ((|irq | wdt_irq) & gie)) & ~cpu_halt_cmd & ~dbg_halt_st & (exec_done | (i_state==I_IDLE)); + +`ifdef CLOCK_GATING +wire mclk_irq_num; +omsp_clock_gate clock_gate_irq_num (.gclk(mclk_irq_num), + .clk (mclk), .enable(irq_detect), .scan_enable(scan_enable)); +`else +wire mclk_irq_num = mclk; +`endif + +// Select interrupt vector +reg [3:0] irq_num; +always @(posedge mclk_irq_num or posedge puc_rst) + if (puc_rst) irq_num <= 4'hf; +`ifdef CLOCK_GATING + else irq_num <= nmi_pnd ? 4'he : +`else + else if (irq_detect) irq_num <= nmi_pnd ? 4'he : +`endif + irq[13] ? 4'hd : + irq[12] ? 4'hc : + irq[11] ? 4'hb : + (irq[10] | wdt_irq) ? 4'ha : + irq[9] ? 4'h9 : + irq[8] ? 4'h8 : + irq[7] ? 4'h7 : + irq[6] ? 4'h6 : + irq[5] ? 4'h5 : + irq[4] ? 4'h4 : + irq[3] ? 4'h3 : + irq[2] ? 4'h2 : + irq[1] ? 4'h1 : + irq[0] ? 4'h0 : 4'hf; + +wire [15:0] irq_addr = {11'h7ff, irq_num, 1'b0}; + +// Interrupt request accepted +wire [15:0] irq_acc_all = one_hot16(irq_num) & {16{(i_state==I_IRQ_FETCH)}}; +wire [13:0] irq_acc = irq_acc_all[13:0]; +wire nmi_acc = irq_acc_all[14]; + +// +// 4.2) SYSTEM WAKEUP +//----------------------------------------- +`ifdef CPUOFF_EN + +// Generate the main system clock enable signal + // Keep the clock running if: +wire mclk_enable = inst_irq_rst ? cpu_en_s : // - the RESET interrupt is currently executing + // and if the CPU is enabled + // otherwise if: + ~((cpuoff | ~cpu_en_s) & // - the CPUOFF flag, cpu_en command, instruction + (i_state==I_IDLE) & // and execution state machines are all two + (e_state==E_IDLE)); // not idle. + + +// Wakeup condition from maskable interrupts +wire mirq_wkup; +omsp_and_gate and_mirq_wkup (.y(mirq_wkup), .a(wkup | wdt_wkup), .b(gie)); + +// Combined asynchronous wakeup detection from nmi & irq (masked if the cpu is disabled) +omsp_and_gate and_mclk_wkup (.y(mclk_wkup), .a(nmi_wkup | mirq_wkup), .b(cpu_en_s)); + +`else + +// In the CPUOFF feature is disabled, the wake-up and enable signals are always 1 +assign mclk_wkup = 1'b1; +assign mclk_enable = 1'b1; +`endif + +//============================================================================= +// 5) FETCH INSTRUCTION +//============================================================================= + +// +// 5.1) PROGRAM COUNTER & MEMORY INTERFACE +//----------------------------------------- + +// Program counter +reg [15:0] pc; + +// Compute next PC value +wire [15:0] pc_incr = pc + {14'h0000, fetch, 1'b0}; +wire [15:0] pc_nxt = pc_sw_wr ? pc_sw : + (i_state==I_IRQ_FETCH) ? irq_addr : + (i_state==I_IRQ_DONE) ? mdb_in : pc_incr; + +`ifdef CLOCK_GATING +wire pc_en = fetch | + pc_sw_wr | + (i_state==I_IRQ_FETCH) | + (i_state==I_IRQ_DONE); +wire mclk_pc; +omsp_clock_gate clock_gate_pc (.gclk(mclk_pc), + .clk (mclk), .enable(pc_en), .scan_enable(scan_enable)); +`else +wire mclk_pc = mclk; +`endif + +always @(posedge mclk_pc or posedge puc_rst) + if (puc_rst) pc <= 16'h0000; + else pc <= pc_nxt; + +// Check if ROM has been busy in order to retry ROM access +reg pmem_busy; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) pmem_busy <= 1'b0; + else pmem_busy <= fe_pmem_wait; + +// Memory interface +wire [15:0] mab = pc_nxt; +wire mb_en = fetch | pc_sw_wr | (i_state==I_IRQ_FETCH) | pmem_busy | (dbg_halt_st & ~cpu_halt_cmd); + + +// +// 5.2) INSTRUCTION REGISTER +//-------------------------------- + +// Instruction register +wire [15:0] ir = mdb_in; + +// Detect if source extension word is required +wire is_sext = (inst_as[`IDX] | inst_as[`SYMB] | inst_as[`ABS] | inst_as[`IMM]); + +// For the Symbolic addressing mode, add -2 to the extension word in order +// to make up for the PC address +wire [15:0] ext_incr = ((i_state==I_EXT1) & inst_as[`SYMB]) | + ((i_state==I_EXT2) & inst_ad[`SYMB]) | + ((i_state==I_EXT1) & ~inst_as[`SYMB] & + ~(i_state_nxt==I_EXT2) & inst_ad[`SYMB]) ? 16'hfffe : 16'h0000; + +wire [15:0] ext_nxt = ir + ext_incr; + +// Store source extension word +reg [15:0] inst_sext; + +`ifdef CLOCK_GATING +wire inst_sext_en = (decode & is_const) | + (decode & inst_type_nxt[`INST_JMP]) | + ((i_state==I_EXT1) & is_sext); +wire mclk_inst_sext; +omsp_clock_gate clock_gate_inst_sext (.gclk(mclk_inst_sext), + .clk (mclk), .enable(inst_sext_en), .scan_enable(scan_enable)); +`else +wire mclk_inst_sext = mclk; +`endif + +always @(posedge mclk_inst_sext or posedge puc_rst) + if (puc_rst) inst_sext <= 16'h0000; + else if (decode & is_const) inst_sext <= sconst_nxt; + else if (decode & inst_type_nxt[`INST_JMP]) inst_sext <= {{5{ir[9]}},ir[9:0],1'b0}; +`ifdef CLOCK_GATING + else inst_sext <= ext_nxt; +`else + else if ((i_state==I_EXT1) & is_sext) inst_sext <= ext_nxt; +`endif + +// Source extension word is ready +wire inst_sext_rdy = (i_state==I_EXT1) & is_sext; + + +// Store destination extension word +reg [15:0] inst_dext; + +`ifdef CLOCK_GATING +wire inst_dext_en = ((i_state==I_EXT1) & ~is_sext) | + (i_state==I_EXT2); +wire mclk_inst_dext; +omsp_clock_gate clock_gate_inst_dext (.gclk(mclk_inst_dext), + .clk (mclk), .enable(inst_dext_en), .scan_enable(scan_enable)); +`else +wire mclk_inst_dext = mclk; +`endif + +always @(posedge mclk_inst_dext or posedge puc_rst) + if (puc_rst) inst_dext <= 16'h0000; + else if ((i_state==I_EXT1) & ~is_sext) inst_dext <= ext_nxt; +`ifdef CLOCK_GATING + else inst_dext <= ext_nxt; +`else + else if (i_state==I_EXT2) inst_dext <= ext_nxt; +`endif + +// Destination extension word is ready +wire inst_dext_rdy = (((i_state==I_EXT1) & ~is_sext) | (i_state==I_EXT2)); + + +//============================================================================= +// 6) DECODE INSTRUCTION +//============================================================================= + +`ifdef CLOCK_GATING +wire mclk_decode; +omsp_clock_gate clock_gate_decode (.gclk(mclk_decode), + .clk (mclk), .enable(decode), .scan_enable(scan_enable)); +`else +wire mclk_decode = mclk; +`endif + +// +// 6.1) OPCODE: INSTRUCTION TYPE +//---------------------------------------- +// Instructions type is encoded in a one hot fashion as following: +// +// 3'b001: Single-operand arithmetic +// 3'b010: Conditional jump +// 3'b100: Two-operand arithmetic + +reg [2:0] inst_type; +assign inst_type_nxt = {(ir[15:14]!=2'b00), + (ir[15:13]==3'b001), + (ir[15:13]==3'b000)} & {3{~irq_detect}}; + +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_type <= 3'b000; +`ifdef CLOCK_GATING + else inst_type <= inst_type_nxt; +`else + else if (decode) inst_type <= inst_type_nxt; +`endif + +// +// 6.2) OPCODE: SINGLE-OPERAND ARITHMETIC +//---------------------------------------- +// Instructions are encoded in a one hot fashion as following: +// +// 8'b00000001: RRC +// 8'b00000010: SWPB +// 8'b00000100: RRA +// 8'b00001000: SXT +// 8'b00010000: PUSH +// 8'b00100000: CALL +// 8'b01000000: RETI +// 8'b10000000: IRQ + +reg [7:0] inst_so; +wire [7:0] inst_so_nxt = irq_detect ? 8'h80 : (one_hot8(ir[9:7]) & {8{inst_type_nxt[`INST_SO]}}); + +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_so <= 8'h00; +`ifdef CLOCK_GATING + else inst_so <= inst_so_nxt; +`else + else if (decode) inst_so <= inst_so_nxt; +`endif + +// +// 6.3) OPCODE: CONDITIONAL JUMP +//-------------------------------- +// Instructions are encoded in a one hot fashion as following: +// +// 8'b00000001: JNE/JNZ +// 8'b00000010: JEQ/JZ +// 8'b00000100: JNC/JLO +// 8'b00001000: JC/JHS +// 8'b00010000: JN +// 8'b00100000: JGE +// 8'b01000000: JL +// 8'b10000000: JMP + +reg [2:0] inst_jmp_bin; +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_jmp_bin <= 3'h0; +`ifdef CLOCK_GATING + else inst_jmp_bin <= ir[12:10]; +`else + else if (decode) inst_jmp_bin <= ir[12:10]; +`endif + +wire [7:0] inst_jmp = one_hot8(inst_jmp_bin) & {8{inst_type[`INST_JMP]}}; + + +// +// 6.4) OPCODE: TWO-OPERAND ARITHMETIC +//------------------------------------- +// Instructions are encoded in a one hot fashion as following: +// +// 12'b000000000001: MOV +// 12'b000000000010: ADD +// 12'b000000000100: ADDC +// 12'b000000001000: SUBC +// 12'b000000010000: SUB +// 12'b000000100000: CMP +// 12'b000001000000: DADD +// 12'b000010000000: BIT +// 12'b000100000000: BIC +// 12'b001000000000: BIS +// 12'b010000000000: XOR +// 12'b100000000000: AND + +wire [15:0] inst_to_1hot = one_hot16(ir[15:12]) & {16{inst_type_nxt[`INST_TO]}}; +wire [11:0] inst_to_nxt = inst_to_1hot[15:4]; + +reg inst_mov; +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_mov <= 1'b0; +`ifdef CLOCK_GATING + else inst_mov <= inst_to_nxt[`MOV]; +`else + else if (decode) inst_mov <= inst_to_nxt[`MOV]; +`endif + + +// +// 6.5) SOURCE AND DESTINATION REGISTERS +//--------------------------------------- + +// Destination register +reg [3:0] inst_dest_bin; +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_dest_bin <= 4'h0; +`ifdef CLOCK_GATING + else inst_dest_bin <= ir[3:0]; +`else + else if (decode) inst_dest_bin <= ir[3:0]; +`endif + +wire [15:0] inst_dest = dbg_halt_st ? one_hot16(dbg_reg_sel) : + inst_type[`INST_JMP] ? 16'h0001 : + inst_so[`IRQ] | + inst_so[`PUSH] | + inst_so[`CALL] ? 16'h0002 : + one_hot16(inst_dest_bin); + + +// Source register +reg [3:0] inst_src_bin; +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_src_bin <= 4'h0; +`ifdef CLOCK_GATING + else inst_src_bin <= ir[11:8]; +`else + else if (decode) inst_src_bin <= ir[11:8]; +`endif + +wire [15:0] inst_src = inst_type[`INST_TO] ? one_hot16(inst_src_bin) : + inst_so[`RETI] ? 16'h0002 : + inst_so[`IRQ] ? 16'h0001 : + inst_type[`INST_SO] ? one_hot16(inst_dest_bin) : 16'h0000; + + +// +// 6.6) SOURCE ADDRESSING MODES +//-------------------------------- +// Source addressing modes are encoded in a one hot fashion as following: +// +// 13'b0000000000001: Register direct. +// 13'b0000000000010: Register indexed. +// 13'b0000000000100: Register indirect. +// 13'b0000000001000: Register indirect autoincrement. +// 13'b0000000010000: Symbolic (operand is in memory at address PC+x). +// 13'b0000000100000: Immediate (operand is next word in the instruction stream). +// 13'b0000001000000: Absolute (operand is in memory at address x). +// 13'b0000010000000: Constant 4. +// 13'b0000100000000: Constant 8. +// 13'b0001000000000: Constant 0. +// 13'b0010000000000: Constant 1. +// 13'b0100000000000: Constant 2. +// 13'b1000000000000: Constant -1. + +reg [12:0] inst_as_nxt; + +wire [3:0] src_reg = inst_type_nxt[`INST_SO] ? ir[3:0] : ir[11:8]; + +always @(src_reg or ir or inst_type_nxt) + begin + if (inst_type_nxt[`INST_JMP]) + inst_as_nxt = 13'b0000000000001; + else if (src_reg==4'h3) // Addressing mode using R3 + case (ir[5:4]) + 2'b11 : inst_as_nxt = 13'b1000000000000; + 2'b10 : inst_as_nxt = 13'b0100000000000; + 2'b01 : inst_as_nxt = 13'b0010000000000; + default: inst_as_nxt = 13'b0001000000000; + endcase + else if (src_reg==4'h2) // Addressing mode using R2 + case (ir[5:4]) + 2'b11 : inst_as_nxt = 13'b0000100000000; + 2'b10 : inst_as_nxt = 13'b0000010000000; + 2'b01 : inst_as_nxt = 13'b0000001000000; + default: inst_as_nxt = 13'b0000000000001; + endcase + else if (src_reg==4'h0) // Addressing mode using R0 + case (ir[5:4]) + 2'b11 : inst_as_nxt = 13'b0000000100000; + 2'b10 : inst_as_nxt = 13'b0000000000100; + 2'b01 : inst_as_nxt = 13'b0000000010000; + default: inst_as_nxt = 13'b0000000000001; + endcase + else // General Addressing mode + case (ir[5:4]) + 2'b11 : inst_as_nxt = 13'b0000000001000; + 2'b10 : inst_as_nxt = 13'b0000000000100; + 2'b01 : inst_as_nxt = 13'b0000000000010; + default: inst_as_nxt = 13'b0000000000001; + endcase + end +assign is_const = |inst_as_nxt[12:7]; + +reg [7:0] inst_as; +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_as <= 8'h00; +`ifdef CLOCK_GATING + else inst_as <= {is_const, inst_as_nxt[6:0]}; +`else + else if (decode) inst_as <= {is_const, inst_as_nxt[6:0]}; +`endif + + +// 13'b0000010000000: Constant 4. +// 13'b0000100000000: Constant 8. +// 13'b0001000000000: Constant 0. +// 13'b0010000000000: Constant 1. +// 13'b0100000000000: Constant 2. +// 13'b1000000000000: Constant -1. +always @(inst_as_nxt) + begin + if (inst_as_nxt[7]) sconst_nxt = 16'h0004; + else if (inst_as_nxt[8]) sconst_nxt = 16'h0008; + else if (inst_as_nxt[9]) sconst_nxt = 16'h0000; + else if (inst_as_nxt[10]) sconst_nxt = 16'h0001; + else if (inst_as_nxt[11]) sconst_nxt = 16'h0002; + else if (inst_as_nxt[12]) sconst_nxt = 16'hffff; + else sconst_nxt = 16'h0000; + end + + +// +// 6.7) DESTINATION ADDRESSING MODES +//----------------------------------- +// Destination addressing modes are encoded in a one hot fashion as following: +// +// 8'b00000001: Register direct. +// 8'b00000010: Register indexed. +// 8'b00010000: Symbolic (operand is in memory at address PC+x). +// 8'b01000000: Absolute (operand is in memory at address x). + +reg [7:0] inst_ad_nxt; + +wire [3:0] dest_reg = ir[3:0]; + +always @(dest_reg or ir or inst_type_nxt) + begin + if (~inst_type_nxt[`INST_TO]) + inst_ad_nxt = 8'b00000000; + else if (dest_reg==4'h2) // Addressing mode using R2 + case (ir[7]) + 1'b1 : inst_ad_nxt = 8'b01000000; + default: inst_ad_nxt = 8'b00000001; + endcase + else if (dest_reg==4'h0) // Addressing mode using R0 + case (ir[7]) + 1'b1 : inst_ad_nxt = 8'b00010000; + default: inst_ad_nxt = 8'b00000001; + endcase + else // General Addressing mode + case (ir[7]) + 1'b1 : inst_ad_nxt = 8'b00000010; + default: inst_ad_nxt = 8'b00000001; + endcase + end + +reg [7:0] inst_ad; +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_ad <= 8'h00; +`ifdef CLOCK_GATING + else inst_ad <= inst_ad_nxt; +`else + else if (decode) inst_ad <= inst_ad_nxt; +`endif + + +// +// 6.8) REMAINING INSTRUCTION DECODING +//------------------------------------- + +// Operation size +reg inst_bw; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) inst_bw <= 1'b0; + else if (decode) inst_bw <= ir[6] & ~inst_type_nxt[`INST_JMP] & ~irq_detect & ~cpu_halt_cmd; + +// Extended instruction size +assign inst_sz_nxt = {1'b0, (inst_as_nxt[`IDX] | inst_as_nxt[`SYMB] | inst_as_nxt[`ABS] | inst_as_nxt[`IMM])} + + {1'b0, ((inst_ad_nxt[`IDX] | inst_ad_nxt[`SYMB] | inst_ad_nxt[`ABS]) & ~inst_type_nxt[`INST_SO])}; +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_sz <= 2'b00; +`ifdef CLOCK_GATING + else inst_sz <= inst_sz_nxt; +`else + else if (decode) inst_sz <= inst_sz_nxt; +`endif + + +//============================================================================= +// 7) EXECUTION-UNIT STATE MACHINE +//============================================================================= + +// State machine registers +reg [3:0] e_state; + + +// State machine control signals +//-------------------------------- + +wire src_acalc_pre = inst_as_nxt[`IDX] | inst_as_nxt[`SYMB] | inst_as_nxt[`ABS]; +wire src_rd_pre = inst_as_nxt[`INDIR] | inst_as_nxt[`INDIR_I] | inst_as_nxt[`IMM] | inst_so_nxt[`RETI]; +wire dst_acalc_pre = inst_ad_nxt[`IDX] | inst_ad_nxt[`SYMB] | inst_ad_nxt[`ABS]; +wire dst_acalc = inst_ad[`IDX] | inst_ad[`SYMB] | inst_ad[`ABS]; +wire dst_rd_pre = inst_ad_nxt[`IDX] | inst_so_nxt[`PUSH] | inst_so_nxt[`CALL] | inst_so_nxt[`RETI]; +wire dst_rd = inst_ad[`IDX] | inst_so[`PUSH] | inst_so[`CALL] | inst_so[`RETI]; + +wire inst_branch = (inst_ad_nxt[`DIR] & (ir[3:0]==4'h0)) | inst_type_nxt[`INST_JMP] | inst_so_nxt[`RETI]; + +reg exec_jmp; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) exec_jmp <= 1'b0; + else if (inst_branch & decode) exec_jmp <= 1'b1; + else if (e_state==E_JUMP) exec_jmp <= 1'b0; + +reg exec_dst_wr; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) exec_dst_wr <= 1'b0; + else if (e_state==E_DST_RD) exec_dst_wr <= 1'b1; + else if (e_state==E_DST_WR) exec_dst_wr <= 1'b0; + +reg exec_src_wr; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) exec_src_wr <= 1'b0; + else if (inst_type[`INST_SO] & (e_state==E_SRC_RD)) exec_src_wr <= 1'b1; + else if ((e_state==E_SRC_WR) || (e_state==E_DST_WR)) exec_src_wr <= 1'b0; + +reg exec_dext_rdy; +always @(posedge mclk or posedge puc_rst) + if (puc_rst) exec_dext_rdy <= 1'b0; + else if (e_state==E_DST_RD) exec_dext_rdy <= 1'b0; + else if (inst_dext_rdy) exec_dext_rdy <= 1'b1; + +// Execution first state +wire [3:0] e_first_state = ~dbg_halt_st & inst_so_nxt[`IRQ] ? E_IRQ_0 : + cpu_halt_cmd | (i_state==I_IDLE) ? E_IDLE : + cpuoff ? E_IDLE : + src_acalc_pre ? E_SRC_AD : + src_rd_pre ? E_SRC_RD : + dst_acalc_pre ? E_DST_AD : + dst_rd_pre ? E_DST_RD : E_EXEC; + + +// State machine +//-------------------------------- + +// States Transitions +always @(e_state or dst_acalc or dst_rd or inst_sext_rdy or + inst_dext_rdy or exec_dext_rdy or exec_jmp or exec_dst_wr or + e_first_state or exec_src_wr) + case(e_state) + E_IDLE : e_state_nxt = e_first_state; + E_IRQ_0 : e_state_nxt = E_IRQ_1; + E_IRQ_1 : e_state_nxt = E_IRQ_2; + E_IRQ_2 : e_state_nxt = E_IRQ_3; + E_IRQ_3 : e_state_nxt = E_IRQ_4; + E_IRQ_4 : e_state_nxt = E_EXEC; + + E_SRC_AD : e_state_nxt = inst_sext_rdy ? E_SRC_RD : E_SRC_AD; + + E_SRC_RD : e_state_nxt = dst_acalc ? E_DST_AD : + dst_rd ? E_DST_RD : E_EXEC; + + E_DST_AD : e_state_nxt = (inst_dext_rdy | + exec_dext_rdy) ? E_DST_RD : E_DST_AD; + + E_DST_RD : e_state_nxt = E_EXEC; + + E_EXEC : e_state_nxt = exec_dst_wr ? E_DST_WR : + exec_jmp ? E_JUMP : + exec_src_wr ? E_SRC_WR : e_first_state; + + E_JUMP : e_state_nxt = e_first_state; + E_DST_WR : e_state_nxt = exec_jmp ? E_JUMP : e_first_state; + E_SRC_WR : e_state_nxt = e_first_state; + // pragma coverage off + default : e_state_nxt = E_IRQ_0; + // pragma coverage on + endcase + +// State machine +always @(posedge mclk or posedge puc_rst) + if (puc_rst) e_state <= E_IRQ_1; + else e_state <= e_state_nxt; + + +// Frontend State machine control signals +//---------------------------------------- + +wire exec_done = exec_jmp ? (e_state==E_JUMP) : + exec_dst_wr ? (e_state==E_DST_WR) : + exec_src_wr ? (e_state==E_SRC_WR) : (e_state==E_EXEC); + + +//============================================================================= +// 8) EXECUTION-UNIT STATE CONTROL +//============================================================================= + +// +// 8.1) ALU CONTROL SIGNALS +//------------------------------------- +// +// 12'b000000000001: Enable ALU source inverter +// 12'b000000000010: Enable Incrementer +// 12'b000000000100: Enable Incrementer on carry bit +// 12'b000000001000: Select Adder +// 12'b000000010000: Select AND +// 12'b000000100000: Select OR +// 12'b000001000000: Select XOR +// 12'b000010000000: Select DADD +// 12'b000100000000: Update N, Z & C (C=~Z) +// 12'b001000000000: Update all status bits +// 12'b010000000000: Update status bit for XOR instruction +// 12'b100000000000: Don't write to destination + +reg [11:0] inst_alu; + +wire alu_src_inv = inst_to_nxt[`SUB] | inst_to_nxt[`SUBC] | + inst_to_nxt[`CMP] | inst_to_nxt[`BIC] ; + +wire alu_inc = inst_to_nxt[`SUB] | inst_to_nxt[`CMP]; + +wire alu_inc_c = inst_to_nxt[`ADDC] | inst_to_nxt[`DADD] | + inst_to_nxt[`SUBC]; + +wire alu_add = inst_to_nxt[`ADD] | inst_to_nxt[`ADDC] | + inst_to_nxt[`SUB] | inst_to_nxt[`SUBC] | + inst_to_nxt[`CMP] | inst_type_nxt[`INST_JMP] | + inst_so_nxt[`RETI]; + + +wire alu_and = inst_to_nxt[`AND] | inst_to_nxt[`BIC] | + inst_to_nxt[`BIT]; + +wire alu_or = inst_to_nxt[`BIS]; + +wire alu_xor = inst_to_nxt[`XOR]; + +wire alu_dadd = inst_to_nxt[`DADD]; + +wire alu_stat_7 = inst_to_nxt[`BIT] | inst_to_nxt[`AND] | + inst_so_nxt[`SXT]; + +wire alu_stat_f = inst_to_nxt[`ADD] | inst_to_nxt[`ADDC] | + inst_to_nxt[`SUB] | inst_to_nxt[`SUBC] | + inst_to_nxt[`CMP] | inst_to_nxt[`DADD] | + inst_to_nxt[`BIT] | inst_to_nxt[`XOR] | + inst_to_nxt[`AND] | + inst_so_nxt[`RRC] | inst_so_nxt[`RRA] | + inst_so_nxt[`SXT]; + +wire alu_shift = inst_so_nxt[`RRC] | inst_so_nxt[`RRA]; + +wire exec_no_wr = inst_to_nxt[`CMP] | inst_to_nxt[`BIT]; + +wire [11:0] inst_alu_nxt = {exec_no_wr, + alu_shift, + alu_stat_f, + alu_stat_7, + alu_dadd, + alu_xor, + alu_or, + alu_and, + alu_add, + alu_inc_c, + alu_inc, + alu_src_inv}; + +always @(posedge mclk_decode or posedge puc_rst) + if (puc_rst) inst_alu <= 12'h000; +`ifdef CLOCK_GATING + else inst_alu <= inst_alu_nxt; +`else + else if (decode) inst_alu <= inst_alu_nxt; +`endif + + +endmodule // omsp_frontend + +`ifdef OMSP_NO_INCLUDE +`else +`include "openMSP430_undefines.v" +`endif |