/* Copyright (C) 2008 Martin Furter This file is part of wbavr. wbavr is free software/hardware; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. wbavr is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wbavr; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ==============================================================================*/ /* wbavr_opdecode: Opcode decoder. */ `include "wbavr_consts.v" module wbavr_opdecode( // inputs opcode_i, // opcode irq_req_i, // interrupt request irq_vect_i, // interrupt vector cycle_i, // cycle input, for multi-cycle instructions // outputs alu_func_o, // ALU function alu_i0_sel_o, // ALU parameter 0 selection alu_i1_sel_o, // ALU parameter 1 selection gp_rd_adr_0_o, // GP read register 0 address gp_rd_adr_1_o, // GP read register 1 address gp_wr_adr_0_o, // GP write register 0 address gp_wr_adr_1_o, // GP write register 1 address gp_wr_en_0_o, // GP write register 0 enable gp_wr_en_1_o, // GP write register 1 enable avr_cadr_sel_o, // AVR code bus address selection avr_code_rd_o, // AVR code bus read avr_code_wr_o, // AVR code bus write avr_dadr_sel_o, // AVR data bus address selection avr_ddat_sel_o, // AVR data bus write data selection avr_data_rd_o, // AVR data bus read avr_data_wr_o, // AVR data bus write address_o, // address interrupt_flag_o, // new value for the interrupt flag flag_sel_o, // flag selection pc_sel_o, // program counter selection tmp_lo_sel_o, // temporary register low byte selection tmp_hi_sel_o, // temporary register high byte selection skip_sel_o, // skip selection const1_o, // constant 1 from opcode const2_o, // constant 2 from opcode sleep_o, // sleep instruction wdr_o, // watchdog reset instruction break_o, // break instruction irq_ack_o, // interrupt acknowledge double_word_o, // double word instruction (0=1 word, 1=2 words) illegal_op_o, // illegal opcode cycle_o // next cycle output, for multi-cycle instructions ); parameter irq_vect_width; // inputs input [15:0] opcode_i; input irq_req_i; input [irq_vect_width-1:0] irq_vect_i; input [1:0] cycle_i; // outputs output [4:0] alu_func_o; reg [4:0] alu_func_o; output [2:0] alu_i0_sel_o; reg [2:0] alu_i0_sel_o; output [2:0] alu_i1_sel_o; reg [2:0] alu_i1_sel_o; output [4:0] gp_rd_adr_0_o; reg [4:0] gp_rd_adr_0_o; output [4:0] gp_rd_adr_1_o; reg [4:0] gp_rd_adr_1_o; output [4:0] gp_wr_adr_0_o; reg [4:0] gp_wr_adr_0_o; output [4:0] gp_wr_adr_1_o; reg [4:0] gp_wr_adr_1_o; output gp_wr_en_0_o; reg gp_wr_en_0_o; output gp_wr_en_1_o; reg gp_wr_en_1_o; output [2:0] avr_cadr_sel_o; reg [2:0] avr_cadr_sel_o; output avr_code_rd_o; reg avr_code_rd_o; output avr_code_wr_o; reg avr_code_wr_o; output [2:0] avr_dadr_sel_o; reg [2:0] avr_dadr_sel_o; output [2:0] avr_ddat_sel_o; reg [2:0] avr_ddat_sel_o; output avr_data_rd_o; reg avr_data_rd_o; output avr_data_wr_o; reg avr_data_wr_o; output [15:0] address_o; reg [15:0] address_o; output interrupt_flag_o; reg interrupt_flag_o; output [2:0] flag_sel_o; reg [2:0] flag_sel_o; output [2:0] tmp_lo_sel_o; reg [2:0] tmp_lo_sel_o; output [2:0] tmp_hi_sel_o; reg [2:0] tmp_hi_sel_o; output [2:0] skip_sel_o; reg [2:0] skip_sel_o; output [7:0] const1_o; reg [7:0] const1_o; output [7:0] const2_o; reg [7:0] const2_o; output sleep_o; reg sleep_o; output wdr_o; reg wdr_o; output break_o; reg break_o; output irq_ack_o; reg irq_ack_o; output double_word_o; reg double_word_o; output illegal_op_o; reg illegal_op_o; output [1:0] cycle_o; reg [1:0] cycle_o; wire [12:0] irq_vect; wire [16:0] opcode; assign irq_vect = { 0, irq_vect_i }; assign opcode = irq_req_i ? { 5'b1_0000, irq_vect } : { 1'b0, opcode_i }; always @ ( opcode_i, irq_req_i, irq_vect_i ) begin // code name words cycles casex( opcode ) // 0001 11rd dddd rrrr adc w1 c1 17'b0_0001_11??_????_????, // 0000 11rd dddd rrrr add w1 c1 17'b0_0000_11??_????_????, // 0010 00rd dddd rrrr and w1 c1 17'b0_0010_00??_????_????, // 0010 01rd dddd rrrr eor w1 c1 17'b0_0010_01??_????_????, // 0010 11rd dddd rrrr mov w1 c1 17'b0_0010_11??_????_????, // 0010 10rd dddd rrrr or w1 c1 17'b0_0010_10??_????_????, // 0000 10rd dddd rrrr sbc w1 c1 17'b0_0000_10??_????_????, // 0001 10rd dddd rrrr sub w1 c1 17'b0_0001_10??_????_????: begin /* Rd = Rd Rr * * cycle 0: * Rd Rr -> Rd * set flags */ case( opcode[13:10] ) 4'b01_11: // adc alu_func <= `ALU_ADC; 4'b00_11: // add alu_func <= `ALU_ADD; 4'b10_00: // and alu_func <= `ALU_AND; 4'b10_01: // eor alu_func <= `ALU_EOR; 4'b10_11: // mov alu_func <= `ALU_NOP; 4'b10_10: // or alu_func <= `ALU_OR; 4'b00_10: // sbc alu_func <= `ALU_SBC; 4'b01_10: // sub alu_func <= `ALU_SUB; default: alu_func <= `ALU_NOP; endcase alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_REG1; gp_rd_adr_0_o <= opcode[8:4]; gp_rd_adr_1_o <= { opcode[9], opcode[3:0] }; gp_wr_adr_0_o <= opcode[8:4]; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_ALU; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 0001 01rd dddd rrrr cp w1 c1 17'b0_0001_01??_????_????, // 0000 01rd dddd rrrr cpc w1 c1 17'b0_0000_01??_????_????: begin /* Rd Rr * * cycle 0: * Rd Rr * set flags */ case( opcode[12] ) 1'b1: // cp alu_func <= `ALU_SUB; 1'b0: // cpc alu_func <= `ALU_SBC; endcase alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_REG1; gp_rd_adr_0_o <= opcode[8:4]; gp_rd_adr_1_o <= { opcode[9], opcode[3:0] }; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_ALU; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1001 010d dddd 0101 asr w1 c1 17'b0_1001_010?_????_0101, // 1001 010d dddd 1010 dec w1 c1 17'b0_1001_010?_????_1010, // 1001 010d dddd 0011 inc w1 c1 17'b0_1001_010?_????_0011, // 1001 010d dddd 0110 lsr w1 c1 17'b0_1001_010?_????_0110, // 1001 010d dddd 0111 ror w1 c1 17'b0_1001_010?_????_0111, // 1001 010d dddd 0010 swap w1 c1 17'b0_1001_010?_????_0010: begin /* Rd = Rr * * cycle 0: * Rd -> Rd * set flags */ casex( opcode ) 17'b0_1001_010?_????_0101: // asr alu_func <= `ALU_ASR; 17'b0_1001_010?_????_1010: // dec alu_func <= `ALU_DEC; 17'b0_1001_010?_????_0011: // inc alu_func <= `ALU_INC; 17'b0_1001_010?_????_0110: // lsr alu_func <= `ALU_LSR; 17'b0_1001_010?_????_0111: // ror alu_func <= `ALU_ROR; 17'b0_1001_010?_????_0010: // swap alu_func <= `ALU_SWAP; default: alu_func <= `ALU_NOP; endcase alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_CONST1; gp_rd_adr_0_o <= 0; gp_rd_adr_0_o <= opcode[8:4]; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_0_o <= opcode[8:4]; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_ALU; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; // must be 1 for dec/inc, ignored by the others const1_o <= 8'h01; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1001 010d dddd 0000 com w1 c1 17'b0_1001_010?_????_0000, // 1001 010d dddd 0001 neg w1 c1 17'b0_1001_010?_????_0001: begin /* Rd = Rr * * cycle 0: * Rd -> Rd * set flags */ casex( opcode[0] ) 1'b0: // com begin alu_func <= `ALU_COM; const1_o <= 8'hFF; end 1'b1: // neg begin alu_func <= `ALU_NEG; const1_o <= 8'h00; end endcase alu_i0_sel_o <= `ALU_I0_SEL_CONST1; alu_i1_sel_o <= `ALU_I1_SEL_REG1; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= opcode[8:4]; gp_wr_adr_0_o <= opcode[8:4]; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_ALU; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 0111 KKKK dddd KKKK andi w1 c1 17'b0_0111_????_????_????, // andi // 1110 KKKK dddd KKKK ldi w1 c1 17'b0_1110_????_????_????, // ldi // 0110 KKKK dddd KKKK ori w1 c1 17'b0_0110_????_????_????, // ori // 0100 KKKK dddd KKKK sbci w1 c1 17'b0_0100_????_????_????, // sbci // 0101 KKKK dddd KKKK subi w1 c1 17'b0_0101_????_????_????: // subi begin /* Rd = Rd constant * * cycle 0: * Rd constant -> Rd * set flags */ casex( opcode[15:12] ) 4'b0111: // andi alu_func <= `ALU_AND; 4'b1110: // ldi alu_func <= `ALU_NOP; 4'b0110: // ori alu_func <= `ALU_OR; 4'b0100: // sbci alu_func <= `ALU_SBC; 4'b0101: // subi alu_func <= `ALU_SUB; default: alu_func <= 0; endcase alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_CONST1; gp_rd_adr_0_o <= { 1'b1, opcode[7:4] }; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= { 1'b1, opcode[7:4] }; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_ALU; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= { opcode[11:8], opcode[3:0] }; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; cycle_o <= 2'b00; end // 0011 KKKK dddd KKKK cpi w1 c1 17'b0_0011_????_????_????: begin /* Rd - constant * * cycle 0: * Rd - constant * set flags */ // ++ alu_func_o <= `ALU_SUB; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= { 1'b1, opcode[7:4] }; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_ALU; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= { opcode[11:8], opcode[3:0] }; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1111 100d dddd 0bbb bld w1 c1 17'b0_1111_100?_????_0???, begin /* copy T flag to bit b in Rd * * cycle 0: * T -> Rd[b] */ alu_func <= `ALU_BITOP; alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_TFLAG; gp_rd_adr_0_o <= { opcode[8:4] }; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= { opcode[8:4] }; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= { 5'b0000_0, opcode[2:0] }; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1111 101d dddd 0bbb bst w1 c1 17'b0_1111_101?_????_0???: begin /* copy bit b in Rd to T flag * * cycle 0: * Rd[b] -> T */ alu_func <= `ALU_GETBIT; alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= { opcode[8:4] }; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_ALU; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= { 5'b0000_0, opcode[2:0] }; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1001 0100 1sss 1000 bclr w1 c1 17'b0_1001_0100_1???_1000, // 1001 0100 0sss 1000 bset w1 c1 17'b0_1001_0100_0???_1000: begin /* clear/set bit in SREG * * cycle 0: * 0/1 -> SREG[b] */ alu_func <= `ALU_BITOP; alu_i0_sel_o <= `ALU_I0_SEL_FLAGS; alu_i1_sel_o <= `ALU_I1_SEL_CONST1; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_O0; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= { 7'b0000_000, opcode[7] }; const2_o <= { opcode[6:4] }; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1001 0110 KKdd KKKK adiw w1 c2 17'b0_1001_0110_????_????, // 1001 0111 KKdd KKKK sbiw w1 c2 17'b0_1001_0111_????_????: begin /* add/subtract immediate from word * * cycle 0: * alu_i_0 <= reg[d*2+24] * alu_o_0 <= reg[d*2+24] * alu_i_1 <= reg[d*2+25] * alu_o_1 <= reg[d*2+25] * alu_i_2 <= const * * cycle2: * nop */ if( cycle_i == 2'b00 ) begin // cycle 0 gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 1'b1; if( opcode[8] == 1'b0 ) alu_func <= `ALU_ADDW; else alu_func <= `ALU_SUBW; endcase cycle_o <= 2'b01; end else begin // cycle 1 gp_wr_en_0_o <= 1'b0; gp_wr_en_1_o <= 1'b0; alu_func <= `ALU_NOP; cycle_o <= 2'b00; end alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_REG1; gp_rd_adr_0_o <= { 2'b11, opcode[5:4], 1'b0 }; gp_rd_adr_1_o <= { 2'b11, opcode[5:4], 1'b1 }; gp_wr_adr_0_o <= { 2'b11, opcode[5:4], 1'b0 }; gp_wr_adr_1_o <= { 2'b11, opcode[5:4], 1'b1 }; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_ALU; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= { 2'b00, opcode[7:6], opcode[3:0] }; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 0000 0001 dddd rrrr movw w1 c1 17'b0_0000_0001_????_????: begin /* copy register word * * alu_i_0 <= reg[r*2+0] * alu_i_1 <= reg[r*2+1] * alu_o_0 <= reg[d*2+0] * alu_o_1 <= reg[d*2+1] */ // ++ alu_func <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_REG1; gp_rd_adr_0_o <= { opcode[3:0], 1'b0 }; gp_rd_adr_1_o <= { opcode[3:0], 1'b1 }; gp_wr_adr_0_o <= { opcode[7:4], 1'b0 }; gp_wr_adr_1_o <= { opcode[7:4], 1'b1 }; gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 1'b1; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1001 1000 AAAA Abbb cbi w1 c2 17'b0_1001_1000_????_????, // 1001 1010 AAAA Abbb sbi w1 c2 17'b0_1001_1010_????_????: begin /* clear/set bit in I/O register * * cycle 0: * data[A+32] -> ALU -> tmp_lo * * cycle 1: * tmp_lo -> data[A+32] */ if( cycle_i == 2'b00 ) begin alu_func <= `ALU_BITOP; avr_data_rd_o <= 1'b1; avr_data_wr_o <= 1'b0; cycle_o <= 2'b01; end else begin alu_func <= `ALU_NOP; avr_data_rd_o <= 1'b0; avr_data_wr_o <= 1'b1; cycle_o <= 2'b00; end alu_i0_sel_o <= `ALU_I0_SEL_DATA; alu_i1_sel_o <= `ALU_I1_SEL_CONST1; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_OPCODE; avr_ddat_sel_o <= `DDAT_SEL_TMP_LO; address_o <= { 11'b0000_0000_001, opcode[7:3] }; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= { 7'b0000_000, opcode[9] }; const2_o <= { 5'b0000_0, opcode[2:0] }; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1011 0AAd dddd AAAA in w1 c1 17'b0_1011_0???_????_????: begin /* load an I/O location to register * * cycle 0: * data[A+32] -> Rd */ // ++ alu_func <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DATA; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= opcode[8:4]; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o = `DADR_SEL_OPCODE; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 1'b1; avr_data_wr_o <= 0; // addr = A + 32 address_o <= { 9'h000, opcode[10], ~opcode[10], opcode[9], opcode[3:0] }; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1011 1AAr rrrr AAAA out w1 c1 17'b0_1011_1???_????_????: begin /* store register to I/O location * * alu_i_0 <= reg[d] * alu_o_0 <= data_wr_i */ alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= opcode[8:4]; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_OPCODE; avr_ddat_sel_o <= `DDAT_SEL_REG0; avr_data_rd_o <= 0; avr_data_wr_o <= 1'b1; // addr = A + 32 address_o <= { 9'h000, opcode[10], ~opcode[10], opcode[9], opcode[3:0] }; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1001 000d dddd 1111 pop w1 c2 17'b0_1001_000?_????_1111: begin /* pop register from stack * * cycle 0: * SP + 1 -> SP * data[SP+1] -> Rr * * cycle 1: * nop */ if( cycle == 2'b00 ) begin gp_wr_en_0_o <= 1'b1; avr_dadr_sel_o <= `DADR_SEL_SP_INC; avr_data_rd_o <= 1'b1; cycle_o <= 2'b01; end else begin gp_wr_en_0_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_data_rd_o <= 0; cycle_o <= 2'b00; end alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DATA; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= opcode[8:4]; gp_wr_adr_1_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1001 001d dddd 1111 push w1 c2 17'b0_1001_001?_????_1111: begin /* push register onto stack * * cycle 0: * Rd -> data[SP] * SP - 1 -> SP * * cycle 1: * nop */ if( cycle == 2'b00 ) begin avr_dadr_sel_o <= `DADR_SEL_SP_DEC; avr_data_wr_o <= 1'b1; cycle_o <= 2'b01; end else begin avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_data_wr_o <= 1'b0; cycle_o <= 2'b00; end alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= opcode[8:4]; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_ddat_sel_o <= `DDAT_SEL_REG0; avr_data_rd_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 1001 000d dddd 1100 ld Rd,X w1 c2 17'b0_1001_000?_????_1100, // 1000 000d dddd 1000 ld Rd,Y w1 c2 17'b0_1000_000?_????_1000, // 1000 000d dddd 0000 ld Rd,Z w1 c2 17'b0_1000_000?_????_0000: begin /* load indirect to register * * cycle 0: * [XYZ] -> tmp_lo/tmp_hi * * cycle 1: * load Rr from addr in tmp_lo/tmp_hi */ if( cycle == 2'b00 ) begin alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_REG1; gp_rd_adr_0_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b0 }; gp_rd_adr_1_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b1 }; gp_wr_adr_0_o <= 0; gp_wr_en_0_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_data_rd_o <= 1'b0; tmp_lo_sel_o <= `TMP_LO_SEL_ALU_O0; tmp_hi_sel_o <= `TMP_HI_SEL_ALU_O1; cycle_o <= 2'b01; end else begin alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DATA; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= opcode[8:4]; gp_wr_en_0_o <= 1'b1; avr_dadr_sel_o <= `DADR_SEL_TMPREG; avr_data_rd_o <= 1'b1; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b00; end gp_wr_adr_1_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 1001 000d dddd 1101 ld Rd,X+ w1 c2 17'b0_1001_000?_????_1101, // 1001 000d dddd 1001 ld Rd,Y+ w1 c2 17'b0_1001_000?_????_1001, // 1001 000d dddd 0001 ld Rd,Z+ w1 c2 17'b0_1001_000?_????_0001, begin /* load indirect to register with postincrement * * cycle 0: * [XYZ] -> tmp_lo/tmp_hi * [XYZ]+1 -> [XYZ] * * cycle 1: * load Rr from addr in tmp_lo/tmp_hi */ if( cycle == 2'b00 ) begin alu_func_o <= `ALU_ADDW; alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_REG1; gp_rd_adr_0_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b0 }; gp_rd_adr_1_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b1 }; gp_wr_adr_0_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b0 }; gp_wr_adr_1_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b1 }; gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 1'b1; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_data_rd_o <= 1'b0; tmp_lo_sel_o <= `TMP_LO_SEL_REG0; tmp_hi_sel_o <= `TMP_HI_SEL_REG1; cycle_o <= 2'b01; end else begin alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DATA; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= opcode[8:4]; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_TMPREG; avr_data_rd_o <= 1'b1; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b00; end avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 8'h01; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 1001 000d dddd 1110 ld Rd,-X w1 c2 17'b0_1001_000?_????_1110, // 1001 000d dddd 1010 ld Rd,-Y w1 c2 17'b0_1001_000?_????_1010, // 1001 000d dddd 0010 ld Rd,-Z w1 c2 17'b0_1001_000?_????_0010: begin /* load indirect to register with predecrement * * cycle 0: * [XYZ]-1 -> tmp_lo/tmp_hi * [XYZ]-1 -> [XYZ] * * cycle 1: * load Rr from addr in tmp_lo/tmp_hi */ if( cycle == 2'b00 ) begin alu_func_o <= `ALU_SUBW; alu_i0_sel_o <= `ALU_I0_SEL_ALU_O0; alu_i1_sel_o <= `ALU_I1_SEL_ALU_O1; gp_rd_adr_0_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b0 }; gp_rd_adr_1_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b1 }; gp_wr_adr_0_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b0 }; gp_wr_adr_1_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b1 }; gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 1'b1; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_data_rd_o <= 1'b0; tmp_lo_sel_o <= `TMP_LO_SEL_REG0; tmp_hi_sel_o <= `TMP_HI_SEL_REG1; cycle_o <= 2'b01; end else begin alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DATA; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= opcode[8:4]; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_TMPREG; avr_data_rd_o <= 1'b1; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b00; end avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 8'h01; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 10q0 qq0d dddd 1qqq ldd Rd,Y+q w1 c2 17'b0_10?0_??0?_????_1???, // 10q0 qq0d dddd 0qqq ldd Rd,Z+q w1 c2 17'b0_10?0_??0?_????_0???: begin /* load indirect to register with offset * * cycle 0: * [YZ]+q -> tmp_lo/tmp_hi * * cycle 1: * load Rr from addr in tmp_lo/tmp_hi */ if( cycle == 2'b00 ) begin alu_func_o <= `ALU_ADDW; alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_REG1; gp_rd_adr_0_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b0 }; gp_rd_adr_1_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b1 }; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 1'b0; gp_wr_en_1_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_data_rd_o <= 1'b0; tmp_lo_sel_o <= `TMP_LO_SEL_REG0; tmp_hi_sel_o <= `TMP_HI_SEL_REG1; cycle_o <= 2'b01; end else begin alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DATA; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= opcode[8:4]; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_TMPREG; avr_data_rd_o <= 1'b1; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b00; end avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= { opcode[13], opcode[11:10], opcode[2:0] }; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 1001 001r rrrr 1100 st X,Rr w1 c2 17'b0_1001_001?_????_1100, // 1000 001r rrrr 1000 st Y,Rr w1 c2 17'b0_1000_001?_????_1000, // 1000 001r rrrr 0000 st Z,Rr w1 c2 17'b0_1000_001?_????_0000: begin /* store indirect from register * * cycle 0: * [XYZ] -> tmp_lo/tmp_hi * * cycle 1: * store Rr to addr in tmp_lo/tmp_hi */ if( cycle == 2'b00 ) begin alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_REG1; gp_rd_adr_0_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b0 }; gp_rd_adr_1_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b1 }; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 1'b0; tmp_lo_sel_o <= `TMP_LO_SEL_ALU_O0; tmp_hi_sel_o <= `TMP_HI_SEL_ALU_O1; cycle_o <= 2'b01; end else begin alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DATA; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= opcode[8:4]; gp_rd_adr_1_o <= 0; avr_dadr_sel_o <= `DADR_SEL_TMPREG; avr_ddat_sel_o <= `DDAT_SEL_REG0; avr_data_wr_o <= 1'b1; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b00; end gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_data_rd_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 1001 001r rrrr 1101 st X+,Rr w1 c2 17'b0_1001_001?_????_1101, // 1001 001r rrrr 1001 st Y+,Rr w1 c2 17'b0_1001_001?_????_1001, // 1001 001r rrrr 0001 st Z+,Rr w1 c2 17'b0_1001_001?_????_0001: begin /* store indirect from register with postincrement * * cycle 0: * [XYZ] -> tmp_lo/tmp_hi * [XYZ]+1 -> [XYZ] * * cycle 1: * store Rr to addr in tmp_lo/tmp_hi */ if( cycle == 2'b00 ) begin alu_func_o <= `ALU_ADDW; alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_REG1; gp_rd_adr_0_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b0 }; gp_rd_adr_1_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b1 }; gp_wr_adr_0_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b0 }; gp_wr_adr_1_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b1 }; gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 1'b1; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 1'b0; tmp_lo_sel_o <= `TMP_LO_SEL_REG0; tmp_hi_sel_o <= `TMP_HI_SEL_REG1; cycle_o <= 2'b01; end else begin alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DATA; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= opcode[8:4]; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 1'b0; gp_wr_en_1_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_TMPREG; avr_ddat_sel_o <= `DDAT_SEL_REG0; avr_data_wr_o <= 1'b1; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b00; end avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_data_rd_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 8'h01; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 1001 001r rrrr 1110 st -X,Rr w1 c2 17'b0_1001_001?_????_1110, // 1001 001r rrrr 1010 st -Y,Rr w1 c2 17'b0_1001_001?_????_1010, // 1001 001r rrrr 0010 st -Z,Rr w1 c2 17'b0_1001_001?_????_0010: begin /* store indirect from register with predecrement * * cycle 0: * [XYZ]-1 -> tmp_lo/tmp_hi * [XYZ]-1 -> [XYZ] * * cycle 1: * store Rr to addr in tmp_lo/tmp_hi */ if( cycle == 2'b00 ) begin alu_func_o <= `ALU_SUBW; alu_i0_sel_o <= `ALU_I0_SEL_ALU_O0; alu_i1_sel_o <= `ALU_I1_SEL_ALU_O1; gp_rd_adr_0_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b0 }; gp_rd_adr_1_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b1 }; gp_wr_adr_0_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b0 }; gp_wr_adr_1_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b1 }; gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 1'b1; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 1'b0; tmp_lo_sel_o <= `TMP_LO_SEL_REG0; tmp_hi_sel_o <= `TMP_HI_SEL_REG1; cycle_o <= 2'b01; end else begin alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DATA; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= opcode[8:4]; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 1'b0; gp_wr_en_1_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_TMPREG; avr_ddat_sel_o <= `DDAT_SEL_REG0; avr_data_wr_o <= 1'b1; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b00; end avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_data_rd_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 8'h01; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 10q0 qq1r rrrr 1qqq std Y+q,Rr w1 c2 17'b0_10?0_??1?_????_1???, // 10q0 qq1r rrrr 0qqq std Z+q,Rr w1 c2 17'b0_10?0_??1?_????_0???: begin /* store indirect from register with offset * * cycle 0: * [YZ]+q -> tmp_lo/tmp_hi * * cycle 1: * store Rr to addr in tmp_lo/tmp_hi */ if( cycle == 2'b00 ) begin alu_func_o <= `ALU_ADDW; alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_REG1; gp_rd_adr_0_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b0 }; gp_rd_adr_1_o <= { 2'b11, ~opcode[2], opcode[3] ^ ~opcode[2], 1'b1 }; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 1'b0; gp_wr_en_1_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 1'b0; tmp_lo_sel_o <= `TMP_LO_SEL_REG0; tmp_hi_sel_o <= `TMP_HI_SEL_REG1; cycle_o <= 2'b01; end else begin alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DATA; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= opcode[8:4]; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 1'b0; gp_wr_en_1_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_TMPREG; avr_ddat_sel_o <= `DDAT_SEL_REG0; avr_data_rd_o <= 1'b1; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b00; end avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= { opcode[13], opcode[11:10], opcode[2:0] }; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 1001 000d dddd 0000 lds +16'k w2 c2 17'b0_1001_000?_????_0000: begin /* load direct to register * * cycle 0: * word2 -> tmp_lo/tmp_hi * * cycle 1: * load Rr from addr in tmp_lo/tmp_hi */ if( cycle == 2'b00 ) begin gp_wr_en_0_o <= 1'b0; avr_code_rd_o <= 1'b1; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_data_rd_o <= 0; tmp_lo_sel_o <= `TMP_LO_SEL_CODE_RD; tmp_hi_sel_o <= `TMP_HI_SEL_CODE_RD; cycle_o <= 2'b01; end else begin gp_wr_en_0_o <= 1'b1; avr_code_rd_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_TMPREG; avr_data_rd_o <= 1; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b00; end alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DATA; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= opcode[8:4]; gp_wr_adr_1_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_wr_o <= 0; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 1; illegal_op_o <= 0; cycle_o <= 0; end // 1001 001d dddd 0000 sts +16'k w2 c2 17'b0_1001_001?_????_0000: begin /* store direct from register * * cycle 0: * word2 -> tmp_lo/tmp_hi * * cycle 1: * store Rr to addr in tmp_lo/tmp_hi */ if( cycle == 2'b00 ) begin avr_code_rd_o <= 1'b1; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 0; tmp_lo_sel_o <= `TMP_LO_SEL_CODE_RD; tmp_hi_sel_o <= `TMP_HI_SEL_CODE_RD; cycle_o <= 2'b01; end else begin avr_code_rd_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_TMPREG; avr_ddat_sel_o <= `DDAT_SEL_REG0; avr_data_wr_o <= 1; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b00; end alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= opcode[8:4]; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_data_rd_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 1; illegal_op_o <= 0; end // 1001 0101 1100 1000 lpm w1 c3 17'b0_1001_0101_1100_1000, // 1001 000d dddd 0100 lpm Rd,Z w1 c3 17'b0_1001_000?_????_0100, // 1001 000d dddd 0101 lpm Rd,Z+ w1 c3 17'b0_1001_000?_????_0101: begin /* load indirect from program memory, optional postinc * * cycle 0: * read code[Z] into Rr * * cycle 1: * optionally increase Z * * cycle 2: * nop */ if( cycle == 2'b00 ) begin alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; if( opcode[10] ) begin gp_wr_adr_1_o <= 0; end else begin gp_wr_adr_1_o <= opcode[8:4]; end gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 1'b1; avr_cadr_sel_o <= `CADR_SEL_GPREG; avr_code_rd_o <= 1'b1; cycle_o <= 2'b01; end else if( cycle == 2'b01 ) begin alu_func_o <= `ALU_ADDW; alu_i0_sel_o <= `ALU_I1_SEL_REG1; gp_rd_adr_0_o <= 5'b11110; gp_rd_adr_1_o <= 5'b11111; gp_wr_adr_0_o <= 5'b11110; gp_wr_adr_1_o <= 5'b11111; gp_wr_en_0_o <= opcode[0]; gp_wr_en_1_o <= opcode[0]; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; cycle_o <= 2'b10; end else begin alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; cycle_o <= 2'b00; end alu_i1_sel_o <= `ALU_I1_SEL_REG1; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 8'h01; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 0001 00rd dddd rrrr cpse w1 c1/2/3 17'b0_0001_00??_????_???? cpse w1 c1/2/3 begin /* compare, skip if equal * * cycle 0: * Rd - Rr * Z -> skip */ alu_func_o <= `ALU_SUB; alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_REG1; gp_rd_adr_0_o <= opcode[8:4]; gp_rd_adr_1_o <= { opcode[9], opcode[3:0] }; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_Z_SET; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1001 1001 AAAA Abbb sbic w1 c1/2/3 17'b0_1001_1001_AAAA_Abbb sbic w1 c1/2/3 // 1001 1011 AAAA Abbb sbis w1 c1/2/3 17'b0_1001_1011_AAAA_Abbb sbis w1 c1/2/3 begin /* skip if bit in I/O register cleared/set * * cycle 0: * data[A] bit b * T/~T -> skip */ alu_func_o <= `ALU_BITOP; alu_i0_sel_o <= `ALU_I0_SEL_DATA; alu_i1_sel_o <= `ALU_I1_SEL_CONST1; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 1'b1; avr_data_wr_o <= 0; // addr = A + 32 address_o <= { 11'b0000_0000_001, opcode[8:4] }; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= opcode[9] ? `SKIP_SEL_T_SET : `SKIP_SEL_T_CLR; const1_o <= 0; const2_o <= opcode[2:0]; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1111 110r rrrr 0bbb sbrc w1 c1/2/3 17'b0_1111_110?_????_0??? sbrc w1 c1/2/3 // 1111 111r rrrr 0bbb sbrs w1 c1/2/3 17'b0_1111_111?_????_0??? sbrs w1 c1/2/3 begin /* skip if bit in register cleared/set * * cycle 0: * Rr bit b * T/~T -> skip */ alu_func_o <= `ALU_BITOP; alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_CONST1; gp_rd_adr_0_o <= opcode[8:4]; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= opcode[9] ? `SKIP_SEL_T_SET : `SKIP_SEL_T_CLR; const1_o <= 0; const2_o <= opcode[2:0]; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1111 01kk kkkk ksss brbc w1 c1/2 17'b0_1111_01??_????_???? brbc w1 c1/2 // 1111 00kk kkkk ksss brbs w1 c1/2 17'b0_1111_00??_????_???? brbs w1 c1/2 begin /* branch if bit in SREG cleared/set * * cycle 0: * * cycle 1: * nop (fetch instr) */ if( cycle == 2'b00 ) begin alu_func_o <= `ALU_BITOP; pc_sel_o <= PC_SEL_BRANCH_T_SET; cycle_o <= 2'b01; end else begin alu_func_o <= `ALU_BITOP; pc_sel_o <= PC_SEL_NONE; cycle_o <= 2'b00; end alu_i0_sel_o <= `ALU_I0_SEL_FLAGS; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= { opcode[9] ? 10'h3FF : 10'h000, opcode[8:3] }; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= { 5'b0000_0, opcode[2:0] }; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1001 010k kkkk 111k call +16'k w2 c4/5 17'b0_1001_010?_????_111? call +16'k w2 c4/5 begin /* long call to a subroutine * * cycle 0: * PClo -> data[SP] * SP-- * * cycle 1: * PChi -> data[SP] * SP-- * word2 -> PC * * cycle 2: * nop * * cycle 3: * nop (fetch instr) */ if( cycle_i == 2'b00 ) begin avr_code_rd_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_SP_DEC; avr_ddat_sel_o <= `DDAT_SEL_PC_LO; avr_data_wr_o <= 1'b1; pc_sel_o <= `PC_SEL_PREV; cycle_o <= 2'b01; end else if( cycle_i == 2'b01 ) begin avr_code_rd_o <= 1'b1; avr_dadr_sel_o <= `DADR_SEL_SP_DEC; avr_ddat_sel_o <= `DDAT_SEL_PC_HI; avr_data_wr_o <= 1'b1; pc_sel_o <= `PC_SEL_CODE; cycle_o <= 2'b10; end else if( cycle_i == 2'b10 ) begin avr_code_rd_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 1'b0; cycle_o <= 2'b11; end else begin avr_code_rd_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 1'b0; pc_sel_o <= `PC_SEL_PREV; cycle_o <= 2'b00; end alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_wr_o <= 0; avr_data_rd_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 1001 010k kkkk 110k jmp +16'k w2 c3 17'b0_1001_010?_????_110? jmp +16'k w2 c3 begin /* long jump * * cycle 0: * word2 -> PC * * cycle 1: * nop * * cycle 2: * nop (fetch instr) */ if( cycle_i == 2'b00 ) begin avr_code_rd_o <= 1'b1; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 1'b1; pc_sel_o <= `PC_SEL_CODE; cycle_o <= 2'b11; end else if( cycle_i == 2'b01 ) begin avr_code_rd_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 1'b1; pc_sel_o <= `PC_SEL_PREV; cycle_o <= 2'b00; end else begin avr_code_rd_o <= 1'b0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 1'b1; pc_sel_o <= `PC_SEL_PREV; cycle_o <= 2'b00; end alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_wr_o <= 0; avr_data_rd_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 1001 0101 0000 1001 icall w1 c3/4 17'b0_1001_0101_0000_1001 icall w1 c3/4 begin /* indirect call to a subroutine (using Z) * * cycle 0: * PClo -> data[SP] * SP-- * * cycle 1: * PChi -> data[SP] * SP-- * Z -> PC * * cycle 2: * nop (fetch instr) */ if( cycle_i == 2'b00 ) begin avr_dadr_sel_o <= `DADR_SEL_SP_DEC; avr_ddat_sel_o <= `DDAT_SEL_PC_LO; avr_data_wr_o <= 1'b1; pc_sel_o <= `PC_SEL_PREV; cycle_o <= 2'b01; end else if( cycle_i == 2'b01 ) begin avr_dadr_sel_o <= `DADR_SEL_SP_DEC; avr_ddat_sel_o <= `DDAT_SEL_PC_HI; avr_data_wr_o <= 1'b1; pc_sel_o <= `PC_SEL_REG; cycle_o <= 2'b10; end else begin avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 1'b0; pc_sel_o <= `PC_SEL_PREV; cycle_o <= 2'b00; end alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 5'b1_1110; gp_rd_adr_1_o <= 5'b1_1111; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_wr_o <= 0; avr_data_rd_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 1001 0100 0000 1001 ijmp w1 c2 17'b0_1001_0100_0000_1001 ijmp w1 c2 begin /* indirect jump * * cycle 0: * Z -> PC * * cycle 1: * nop (fetch instr) */ if( cycle_i == 2'b00 ) begin avr_dadr_sel_o <= `DADR_SEL_SP_DEC; avr_ddat_sel_o <= `DDAT_SEL_PC_HI; avr_data_wr_o <= 1'b1; pc_sel_o <= `PC_SEL_REG; cycle_o <= 2'b10; end else begin avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 1'b0; pc_sel_o <= `PC_SEL_PREV; cycle_o <= 2'b00; end alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 5'b1_1110; gp_rd_adr_1_o <= 5'b1_1111; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_data_rd_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 1101 kkkk kkkk kkkk rcall w1 c3/4 17'b0_1101_????_????_???? rcall w1 c3/4 begin /* relative call to subroutine * * cycle 0: * PClo -> data[SP] * SP-- * * cycle 1: * PChi -> data[SP] * SP-- * PC+k -> PC * * cycle 2: * nop (fetch instr) */ if( cycle_i == 2'b00 ) begin avr_dadr_sel_o <= `DADR_SEL_SP_DEC; avr_ddat_sel_o <= `DDAT_SEL_PC_LO; avr_data_wr_o <= 1'b1; pc_sel_o <= `PC_SEL_PREV; cycle_o <= 2'b01; end else if( cycle_i == 2'b01 ) begin avr_dadr_sel_o <= `DADR_SEL_SP_DEC; avr_ddat_sel_o <= `DDAT_SEL_PC_HI; avr_data_wr_o <= 1'b1; pc_sel_o <= `PC_SEL_RELADDR; cycle_o <= 2'b10; end else begin avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 1'b0; pc_sel_o <= `PC_SEL_PREV; cycle_o <= 2'b00; end alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_data_rd_o <= 0; address_o <= { opcode[11] ? 4'hF, 4'h0, opcode[11:0] }; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 1100 kkkk kkkk kkkk rjmp w1 c2 17'b0_1100_????_????_???? rjmp w1 c2 begin /* relative jump * * cycle 0: * * cycle 1: */ if( cycle_i == 2'b00 ) begin avr_dadr_sel_o <= `DADR_SEL_SP_DEC; avr_ddat_sel_o <= `DDAT_SEL_PC_HI; avr_data_wr_o <= 1'b1; pc_sel_o <= `PC_SEL_RELADDR; cycle_o <= 2'b10; end else begin avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 1'b0; pc_sel_o <= `PC_SEL_PREV; cycle_o <= 2'b00; end alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_data_rd_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 1001 0101 0000 1000 ret w1 c4/5 17'b0_1001_0101_0000_1000 ret w1 c4/5 begin /* return from subroutine * * cycle 0: * SP + 1 -> SP * data[SP+1] -> tmp_hi * * cycle 1: * SP + 1 -> SP * tmp_hi/data[SP+1] -> SP * * cycle 2: * nop * * cycle 3: * nop */ if( cycle == 2'b00 ) begin avr_dadr_sel_o <= `DADR_SEL_SP_INC; pc_sel_o <= `PC_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_DATA_RD; cycle_o <= 2'b01; end else if( cycle == 2'b01 ) begin avr_dadr_sel_o <= `DADR_SEL_SP_INC; pc_sel_o <= `PC_SEL_THI_DLO; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b10; end else if( cycle == 2'b10 ) begin avr_dadr_sel_o <= `DADR_SEL_DEFAULT; pc_sel_o <= `PC_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b11; end else begin avr_dadr_sel_o <= `DADR_SEL_DEFAULT; pc_sel_o <= `PC_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b00; end alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 1001 0101 0001 1000 reti w1 c4/5 17'b0_1001_0101_0001_1000 reti w1 c4/5 begin /* return from interrupt * * cycle 0: * SP + 1 -> SP * data[SP+1] -> tmp_hi * 1 -> I flag * * cycle 1: * SP + 1 -> SP * tmp_hi/data[SP+1] -> PC * * cycle 2: * nop * * cycle 3: * nop */ if( cycle == 2'b00 ) begin avr_dadr_sel_o <= `DADR_SEL_SP_INC; flag_sel_o <= `FLAG_SEL_CHG_I; pc_sel_o <= `PC_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_DATA_RD; cycle_o <= 2'b01; end else if( cycle == 2'b01 ) begin avr_dadr_sel_o <= `DADR_SEL_SP_INC; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_THI_DLO; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b10; end else if( cycle == 2'b10 ) begin avr_dadr_sel_o <= `DADR_SEL_DEFAULT; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b11; end else begin avr_dadr_sel_o <= `DADR_SEL_DEFAULT; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b00; end alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 1; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 1001 11rd dddd rrrr mul w1 c2 17'b0_1001_11??_????_???? mul w1 c2 /* multiply unsigned * * cycle 0: * Rd * Rr -> R1/R0 * * cycle 1: * nop */ if( cycle == 2'b00 ) begin alu_func_o <= `ALU_MUL; gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 1'b1; flag_sel_o <= `FLAG_SEL_ALU; end else begin alu_func_o <= `ALU_NOP; gp_wr_en_0_o <= 1'b0; gp_wr_en_1_o <= 1'b0; flag_sel_o <= `FLAG_SEL_PREV; end alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_REG1; gp_rd_adr_0_o <= opcode[8:4]; gp_rd_adr_1_o <= { opcode[9], opcode[3:0] }; gp_wr_adr_0_o <= 5'b0_0000; gp_wr_adr_1_o <= 5'b0_0001; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 0000 0010 dddd rrrr muls w1 c2 17'b0_0000_0010_????_???? muls w1 c2 /* multiply signed * * cycle 0: * Rd * Rr -> R1/R0 * * cycle 1: * nop */ if( cycle == 2'b00 ) begin alu_func_o <= `ALU_MULS; gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 1'b1; flag_sel_o <= `FLAG_SEL_ALU; end else begin alu_func_o <= `ALU_NOP; gp_wr_en_0_o <= 1'b0; gp_wr_en_1_o <= 1'b0; flag_sel_o <= `FLAG_SEL_PREV; end alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_REG1; // 16 <= Rd/Rr <= 31 gp_rd_adr_0_o <= { 1'b1, opcode[7:4] }; gp_rd_adr_1_o <= { 1'b1, opcode[3:0] }; gp_wr_adr_0_o <= 5'b0_0000; gp_wr_adr_1_o <= 5'b0_0001; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 0000 0011 0ddd 0rrr mulsu w1 c2 17'b0_0000_0011_0???_0??? mulsu w1 c2 // 0000 0011 0ddd 1rrr fmul w1 c2 17'b0_0000_0011_0???_1??? fmul w1 c2 // 0000 0011 1ddd 0rrr fmuls w1 c2 17'b0_0000_0011_1???_0??? fmuls w1 c2 // 0000 0011 1ddd 1rrr fmulsu w1 c2 17'b0_0000_0011_1???_1??? fmulsu w1 c2 begin /* multiply * * cycle 0: * Rd * Rr -> R1/R0 * * cycle 1: * nop */ if( cycle == 2'b00 ) begin case( { opcode[7], opcode[3] } ) 1'b00: alu_func_o <= `ALU_MULSU; 1'b01: alu_func_o <= `ALU_FMUL; 1'b10: alu_func_o <= `ALU_FMULS; 1'b11: alu_func_o <= `ALU_FMULSU; endcase gp_wr_en_0_o <= 1'b1; gp_wr_en_1_o <= 1'b1; flag_sel_o <= `FLAG_SEL_ALU; end else begin alu_func_o <= `ALU_NOP; gp_wr_en_0_o <= 1'b0; gp_wr_en_1_o <= 1'b0; flag_sel_o <= `FLAG_SEL_PREV; end alu_i0_sel_o <= `ALU_I0_SEL_REG0; alu_i1_sel_o <= `ALU_I1_SEL_REG1; // 16 <= Rd/Rr <= 23 gp_rd_adr_0_o <= { 2'b10, opcode[6:4] }; gp_rd_adr_1_o <= { 2'b10, opcode[2:0] }; gp_wr_adr_0_o <= 5'b0_0000; gp_wr_adr_1_o <= 5'b0_0001; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 0000 0000 0000 0000 nop w1 c1 17'b0_0000_0000_0000_0000, // 1001 0101 1000 1000 sleep w1 c1 17'b0_1001_0101_1000_1000, // 1001 0101 1010 1000 wdr w1 c1 17'b0_1001_0101_1010_1000, // 1001 0101 1001 1000 brk w1 c1 17'b0_1001_0101_1001_1000: begin /* no operation, sleep, watchdog reset, break * * cycle 0: * */ alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= &{ opcode[3], ~|{ opcode[5:4] } }; wdr_o <= opcode[5]; break_o <= opcode[4]; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; cycle_o <= 0; end // 1001 0101 1110 1000 spm w1 cN 17'b0_1001_0101_1110_1000: begin /* store prgram memory * * cycle 0: * Z -> tmp_lo/tmp_hi * * cycle 1: * R0/R1 -> code[tmp_lo/tmp_hi] * * cycle 2: * nop (fetch instr) */ if( cycle == 2'b00 ) begin gp_rd_adr_0_o <= 5'b1_1110; gp_rd_adr_1_o <= 5'b1_1111; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_wr_o <= 0; tmp_lo_sel_o <= `TMP_LO_SEL_ALU_O0; tmp_hi_sel_o <= `TMP_HI_SEL_ALU_O1; cycle_o <= 2'b01; end else if( cycle == 2'b01 ) begin gp_rd_adr_0_o <= 5'b0_0000; gp_rd_adr_1_o <= 5'b0_0001; avr_cadr_sel_o <= `CADR_SEL_TMPREG; avr_code_wr_o <= 1'b1; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b10; end else begin gp_rd_adr_0_o <= 5'b0_0000; gp_rd_adr_1_o <= 5'b0_0001; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_wr_o <= 0; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; cycle_o <= 2'b00; end alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_code_rd_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end // 0000 vvvv vvvv vvvv interrupt request 17'b1_0000_????_????_????: begin /* interrupt * * cycle 0: * PClo -> data[SP] * SP-- * * cycle 1: * PChi -> data[SP] * SP-- * irq_vect -> PC * * cycle 2: * nop * * cycle 3: * nop */ if( cycle_i == 2'b00 ) begin avr_dadr_sel_o <= `DADR_SEL_SP_DEC; avr_ddat_sel_o <= `DDAT_SEL_PC_LO; avr_data_wr_o <= 1'b1; flag_sel_o <= `FLAG_SEL_CHG_I; pc_sel_o <= `PC_SEL_PREV; cycle_o <= 2'b01; end else if( cycle_i == 2'b01 ) begin avr_dadr_sel_o <= `DADR_SEL_SP_DEC; avr_ddat_sel_o <= `DDAT_SEL_PC_HI; avr_data_wr_o <= 1'b1; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_ABSADDR; cycle_o <= 2'b10; end else if( cycle_i == 2'b10 ) begin avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 1'b0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; cycle_o <= 2'b11; end else begin avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_wr_o <= 1'b0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; cycle_o <= 2'b00; end alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_data_rd_o <= 0; address_o <= 0; interrupt_flag_o <= 0; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 0; end /* extended address space instructions for code memory between 32/64k and 24M words needs EIND and RAMPZ register // 1001 0101 0001 1001 eicall w1 c4 // 1001 0100 0001 1001 eijmp w1 c2 // 1001 0101 1101 1000 elpm w1 c3 // 1001 000d dddd 0110 elpm Rd,Z w1 c3 // 1001 000d dddd 0111 elpm Rd,Z+ w1 c3 */ // illegal instruction default: begin alu_func_o <= `ALU_NOP; alu_i0_sel_o <= `ALU_I0_SEL_DEFAULT; alu_i1_sel_o <= `ALU_I1_SEL_DEFAULT; gp_rd_adr_0_o <= 0; gp_rd_adr_1_o <= 0; gp_wr_adr_0_o <= 0; gp_wr_adr_1_o <= 0; gp_wr_en_0_o <= 0; gp_wr_en_1_o <= 0; avr_cadr_sel_o <= `CADR_SEL_PC; avr_code_rd_o <= 0; avr_code_wr_o <= 0; avr_dadr_sel_o <= `DADR_SEL_DEFAULT; avr_ddat_sel_o <= `DDAT_SEL_DEFAULT; avr_data_rd_o <= 0; avr_data_wr_o <= 0; address_o <= 0; interrupt_flag_o <= 0; flag_sel_o <= `FLAG_SEL_PREV; pc_sel_o <= `PC_SEL_PREV; tmp_lo_sel_o <= `TMP_LO_SEL_PREV; tmp_hi_sel_o <= `TMP_HI_SEL_PREV; skip_sel_o <= `SKIP_SEL_NONE; const1_o <= 0; const2_o <= 0; sleep_o <= 0; wdr_o <= 0; break_o <= 0; irq_ack_o <= 0; double_word_o <= 0; illegal_op_o <= 1; cycle_o <= 0; end endcase end endmodule