日曜日にデコーダが動いてたのだけど、動画をとるのがめんどくてブログかいてなかった。
とりあえず、ここで書いた、デコード後の内部命令がLCDに表示される。
ぼくのかんがえたさいきょうのCPU 〜 仕様確定
はっきりいって、命令にバイト数をつかえてきれいなコード体系にできれば、こんな面倒なことをしなくていいんだけど、メモリが少ない前提なので、やっぱこういう部分でがんばらないといけない。
あと、8080/Z80の命令体系に従わない部分をつくるなら、もうめんどうなところは全部命令体系を変更したほうが実装が楽だし回路も小さくなったなーとか思ったり。
これを実装するときは、まずJavaでコードを書いて、それなりに動くことを確認してから、手作業ではあるけど機械的にVerilogのコードに置き換えてます。
手続き的な処理を書くときには、このように書いたほうがよさげ。
このJavaコードは、そのまま逆アセンブラやエミュレータのデコード部として使えます。ただ、エミュレータにするのであれば、デコード部と実行部をわける必要はないので、そのまま使うわけではないけど。
まだこのままでは使えないけど、デコーダ部のコードだけ、ぺろっと貼っておきます。
`define OP_STORE 4'd0 `define OP_LOAD 4'd1 `define OP_IN 4'd2 `define OP_OUT 4'd3 `define OP_MOVE 4'd4 `define OP_JR 4'd5 `define OP_RLA 4'd6 `define OP_RRA 4'd7 `define OP_ADD 4'd8 `define OP_SUB 4'd9 `define OP_AND 4'd10 `define OP_XOR 4'd11 `define OP_OR 4'd12 `define OP_MUL 4'd13 `define OP_DIV 4'd14 `define OP_MOD 4'd15 `define COND_NONE 3'd0 `define COND_NZ 3'd1 `define COND_Z 3'd2 `define COND_NC 3'd3 `define COND_C 3'd4 `define REG_BC 4'd0 `define REG_DE 4'd1 `define REG_HL 4'd2 `define REG_SP 4'd3 `define REG_AF 4'd4 `define REG_VW 4'd5 `define REG_PC 4'd6 `define REG_II 4'd7 `define REG_B 4'd0 `define REG_C 4'd1 `define REG_D 4'd2 `define REG_E 4'd3 `define REG_H 4'd4 `define REG_L 4'd5 `define REG_SPh 4'd6 `define REG_SPl 4'd7 `define REG_A 4'd8 `define REG_F 4'd9 `define REG_V 4'd10 `define REG_W 4'd11 `define REG_PCh 4'd12 `define REG_PCl 4'd13 `define REG_I 4'd14 `define REG_NONE 4'd15 `define TRUE 1'b1; `define FALSE 1'b0; module decoder( input [7:0] code, input [7:0] param, output reg[3:0] op_code ); //reg[3:0] op_code; reg op_dw; reg[1:0] op_byte; reg[2:0] op_cond; reg[15:0] op_param1; reg[15:0] op_param2; reg[3:0] op_outreg; reg[7:0] regs[15]; wire [7:0] reg8_A = regs[`REG_A]; wire [7:0] reg8_F = regs[`REG_F]; wire [7:0] reg8_V = regs[`REG_V]; wire [7:0] reg8_I = regs[`REG_I]; wire [15:0] reg_BC = {regs[`REG_B], regs[`REG_C]}; wire [15:0] reg_DE = {regs[`REG_D], regs[`REG_E]}; wire [15:0] reg_HL = {regs[`REG_H], regs[`REG_L]}; wire [15:0] reg_SP = {regs[`REG_SPh], regs[`REG_SPl]}; wire [15:0] reg_AF = {regs[`REG_A], regs[`REG_F]}; wire [15:0] reg_VW = {regs[`REG_V], regs[`REG_W]}; wire [15:0] reg_PC = {regs[`REG_PCh], regs[`REG_PCl]}; wire[1:0] sect = code[7:6]; wire[2:0] src = code[2:0]; wire[2:0] dest = code[5:3]; wire[3:0] subop = code[3:0]; wire[1:0] reg16 = code[5:4]; wire[3:0] destReg = (dest == `REG_SPh) ? `REG_V : (dest == `REG_SPl) ? `REG_A : {1'b0, dest}; wire[3:0] srcReg = (src == `REG_SPh) ? `REG_V : (src == `REG_SPl) ? `REG_A : {1'b0, src}; wire[7:0] reg8_src = regs[srcReg]; wire[7:0] reg8_dest = regs[destReg]; wire[7:0] reg8_reg16 = regs[reg16]; wire[15:0] reg16_reg = {regs[{1'd0, reg16, 1'd0}], regs[{1'd0, reg16, 1'd1}]}; always @(code) begin case(sect) 2'b00: begin case(src) 3'b000: begin case(dest) 3'b000: begin //NOP(内部的にはLD A,Aを行う) op_param2 <= reg8_A; op_outreg <= `REG_A; op_dw <= `FALSE; op_code <= `OP_MOVE; end 3'b001: begin //LD V,A op_param2 <= reg8_A; op_outreg <= `REG_V; op_dw <= `FALSE; op_code <= `OP_MOVE; end 3'b010: begin // HALT(内部的にはJR nn) op_param1 <= reg_PC; op_param2 <= 16'hffff; op_code <= `OP_JR; op_outreg <= `REG_PC; op_dw <= `TRUE; end default: begin // JR cond, e op_cond <= dest - 4'b0011; op_code <= `OP_JR; op_param1 <= reg_PC; op_param2 <= param; op_outreg <= `REG_PC; op_dw <= `TRUE; end endcase end 4'b0001: begin // LD r, nn op_param2 <= param; op_code <= `OP_MOVE; op_outreg <= reg16; op_dw <= `TRUE; end 4'b1001: begin // ADD HL, r op_param1 <= reg_HL; op_param2 <= reg16_reg; op_code <= `OP_ADD; op_outreg <= `REG_HL; op_dw <= `TRUE; end 4'b0010: begin op_code <= `OP_STORE; case(reg16) 2'b00: begin //LD (BC), A; op_param2 <= reg_BC; op_param1 <= reg8_A; op_outreg <= `REG_NONE; op_dw <= `FALSE; end 2'b01: begin //LD (DE), A; op_param2 <= reg_DE; op_param1 <= reg8_A; op_outreg <= `REG_NONE; op_dw <= `FALSE; end 2'b10: begin //LD(nn), HL op_param2 <= param; op_param1 <= reg_HL; op_dw <= `TRUE; op_outreg <= `REG_NONE; end 2'b11: begin //LD(nn), A op_param2 <= param; op_param1 <= reg8_A; op_dw <= `FALSE; op_outreg <= `REG_NONE; end endcase end 4'b1010: begin op_code <= `OP_LOAD; case(reg16) 2'b00: begin //LD A, (BC); op_outreg <= `REG_A; op_dw <= `FALSE; op_param2 <= reg_BC; op_code <= `OP_STORE; end 2'b01: begin //LD A, (DE); op_outreg <= `REG_A; op_dw <= `FALSE; op_param2 <= reg_DE; op_code <= `OP_STORE; end 2'b10: begin //LD HL, (nn) op_outreg <= `REG_HL; op_param2 <= param; op_dw <= `TRUE; end 2'b11: begin //LD A, (nn) op_outreg <= `REG_A; op_dw <= `FALSE; op_param2 <= param; end endcase end 4'b0011: begin //INC rr op_outreg <= reg16; op_param1 <= reg16_reg; op_param2 <= 1; op_code <= `OP_ADD; op_dw <= `TRUE; end 4'b1011: begin //DEC rr op_outreg <= reg16; op_param1 <= reg16_reg; op_param2 <= 1; op_code <= `OP_SUB; op_dw <= `TRUE; end 3'b100: begin //INC r op_param1 <= reg8_dest; op_outreg <= destReg; op_dw <= `FALSE; op_code <= `OP_ADD; op_param2 <= 1; end 3'b101: begin //DEC r op_param1 <= reg8_dest; op_outreg <= destReg; op_dw <= `FALSE; op_code <= `OP_SUB; op_param2 <= 1; end 3'b110: begin op_dw <= `FALSE; case(dest) `REG_SPh: begin // LD (HL), n op_outreg <= `REG_NONE; op_param1 <= param; op_param2 <= reg_HL; op_code <= `OP_STORE; end default: begin // LD r, n op_param2 <= param; op_outreg <= destReg; op_code <= `OP_MOVE; end endcase end 3'b111: begin op_dw <= `FALSE; case(dest) 3'b000: begin // RLCA op_param1 <= reg8_A; op_param2 <= reg8_F; op_outreg <= `REG_A; op_code <= `OP_RLA; end 3'b001: begin // RRCA op_param1 <= reg8_A; op_param2 <= reg8_F; op_code <= `OP_RRA; op_outreg <= `REG_A; end 3'b010: begin // RLA op_param1 <= reg8_A; op_param2 <= 0; op_code <= `OP_RLA; op_outreg <= `REG_A; end 3'b011: begin // RRA op_param1 <= reg8_A; op_param2 <= 0; op_outreg <= `REG_A; op_code <= `OP_RRA; end 3'b100: begin // LD A, (HL) op_param2 <= reg_HL; op_code <= `OP_LOAD; op_outreg <= `REG_A; end 3'b101: begin // CPL op_param1 <= reg8_A; op_param2 <= 8'hff; op_code <= `OP_XOR; op_outreg <= `REG_A; end 3'b110: begin // SCF op_param1 <= reg8_F; op_param2 <= 1; op_code <= `OP_OR; op_outreg <= `REG_F; end 3'b111: begin // CCF op_param1 <= reg8_F; op_param2 <= 1; op_code <= `OP_XOR; op_outreg <= `REG_F; end endcase end endcase end 2'b01: begin // LD r1, r2 op_dw <= `FALSE; if(dest == `REG_SPh) begin // LD (HL), r op_code <= `OP_STORE; op_param2 <= reg_HL; op_param1 <= reg8_src; op_outreg <= `REG_NONE; end else if(src == `REG_SPh) begin if(dest == `REG_SPl) begin // LD A, V op_code <= `OP_MOVE; op_outreg <= `REG_A; op_param2 <= reg8_V; end else begin // LD r, (HL) op_outreg <= destReg; op_code <= `OP_LOAD; op_param2 <= reg_HL; end end else begin // LD r1, r2 op_code <= `OP_MOVE; op_outreg <= destReg; op_param2 <= reg8_src; end end 2'b10: begin op_outreg <= (dest == 3'b111) ? `REG_NONE : `REG_A; op_dw <= `FALSE; op_param1 <= reg8_A; op_param2 <= reg8_src; case(dest) 3'b000: begin // ADD op_code <= `OP_ADD; op_cond <= 0; end 3'b001: begin // ADC op_code <= `OP_ADD; op_cond <= reg8_F[0]; end 3'b010: begin // SUB op_code <= `OP_SUB; op_cond <= 0; end 3'b011: begin // SBC op_code <= `OP_SUB; op_cond <= reg8_F[0]; end 3'b100: begin // AND op_code <= `OP_AND; end 3'b101: begin // XOR op_code <= `OP_XOR; end 3'b110: begin // OR op_code <= `OP_OR; end 3'b111: begin // CP op_code <= `OP_SUB; end endcase end 2'b11: begin case(subop) 4'b0110, 4'b1110: begin //op A,n op_outreg <= (dest == 3'b111) ? `REG_NONE : `REG_A; op_dw <= `FALSE; case(dest) 3'b000: begin // ADD op_code <= `OP_ADD; op_cond <= 0; end 3'b001: begin // ADC op_code <= `OP_ADD; op_cond <= reg8_F[0]; end 3'b010: begin // SUB op_code <= `OP_SUB; op_cond <= 0; end 3'b011: begin // SBC op_code <= `OP_SUB; op_cond <= reg8_F[0]; end 3'b100: begin // AND op_code <= `OP_AND; end 3'b101: begin // XOR op_code <= `OP_XOR; end 3'b110: begin // OR op_code <= `OP_OR; end 3'b111: begin // CP op_code <= `OP_SUB; end endcase op_param1 <= reg8_A; op_param2 <= param; end 4'b0010, 4'b1010: begin op_dw <= `TRUE; if(!dest[2]) begin // JP f, nn op_param2 <= param; op_outreg <= `REG_PC; op_cond <= {1'b0, dest[1:0]} + 3'd1; op_code <= `OP_MOVE; end else begin case(dest) 3'b100: begin //INCW HL op_outreg <= `REG_HL; op_param1 <= reg_HL; op_param2 <= 2; op_code <= `OP_ADD; end 3'b101: begin // OUT (BC), HL op_code <= `OP_OUT; op_param1 <= reg_HL; op_param2 <= reg_BC; op_outreg <= `REG_NONE; end 3'b110: begin //INCW SP op_outreg <= `REG_SP; op_param1 <= reg_SP; op_param2 <= 2; op_code <= `OP_ADD; end 3'b111: begin // IN HL, (BC) op_code <= `OP_IN; op_param2 <= reg_BC; op_outreg <= `REG_HL; end endcase end end 4'b0000: begin op_dw <= `TRUE; case(reg16) 2'b00: begin // LD (HL), BC op_param1 <= reg_BC; op_param2 <= reg_HL; op_code <= `OP_STORE; op_outreg <= `REG_NONE; end 2'b01: begin // LD (HL), DE op_param1 <= reg_DE; op_param2 <= reg_HL; op_code <= `OP_STORE; op_outreg <= `REG_NONE; end 2'b10: begin // LD BC, (HL) op_param2 <= reg_HL; op_outreg <= `REG_BC; op_code <= `OP_LOAD; end 2'b11: begin // LD DE, (HL) op_param2 <= reg_HL; op_outreg <= `REG_DE; op_code <= `OP_LOAD; end endcase end 4'b0001: begin // LD (SP), rr op_code <= `OP_STORE; op_outreg <= `REG_NONE; op_param1 <= (reg16 == `REG_SP) ? reg_AF : reg16_reg; op_param2 <= reg_SP; op_dw <= `TRUE; end 4'b0011: begin case(reg16) 2'b00: begin // JP nn op_outreg <= `REG_PC; op_param2 <= param; op_code <= `OP_MOVE; op_dw <= `TRUE; end 2'b01: begin // OUT (n), A op_param1 <= reg8_A; op_param2 <= param; op_code <= `OP_OUT; op_outreg <= `REG_NONE; op_dw <= `FALSE; end 2'b10: begin // OUT (BC), A op_param1 <= reg8_A; op_param2 <= reg_BC; op_code <= `OP_OUT; op_outreg <= `REG_NONE; op_dw <= `FALSE; end 2'b11: begin // DI op_param2 <= 1; op_outreg <= `REG_I; op_dw <= `FALSE; op_code <= `OP_MOVE; end endcase end 4'b0100: begin op_dw <= `TRUE; case(reg16) 2'b00: begin // LD VW, (SP) op_param2 <= reg_SP; op_outreg <= `REG_VW; op_code <= `OP_LOAD; end 2'b01: begin // LD (SP), VW op_param1 <= reg_VW; op_param2 <= reg_SP; op_outreg <= `REG_VW; op_code <= `OP_STORE; end 2'b10: begin // DECW HL op_outreg <= `REG_HL; op_param1 <= reg_HL; op_param2 <= 2; op_code <= `OP_SUB; end 2'b11: begin // DECW SP op_outreg <= `REG_SP; op_param1 <= reg_SP; op_param2 <= 2; op_code <= `OP_SUB; end endcase end 4'b0101: begin // LD rr, (SP) op_code <= `OP_LOAD; op_dw <= `TRUE; op_outreg <= reg16 == `REG_SP ? `REG_AF : reg16; op_param2 <= reg_SP; end 4'b0111: begin // MUL A, r op_param1 <= reg8_A; op_param2 <= reg8_reg16; op_outreg <= `REG_HL; op_dw <= `TRUE; op_code <= `OP_MUL; end 4'b1000: begin op_dw <= `TRUE; case(reg16) 2'b00: begin // JP Z, (VW) op_cond <= `COND_Z; op_code <= `OP_MOVE; op_outreg <= `REG_PC; op_param2 <= reg_VW; end 2'b01: begin // JP C, (VW) op_cond <= `COND_C; op_code <= `OP_MOVE; op_outreg <= `REG_PC; op_param2 <= reg_VW; end 2'b10: begin // SUB HL, BC op_code <= `OP_SUB; op_param1 <= reg_HL; op_param2 <= reg_BC; op_outreg <= `REG_HL; end 2'b11: begin // SUB HL, DE op_code <= `OP_SUB; op_param1 <= reg_HL; op_param2 <= reg_DE; op_outreg <= `REG_HL; end endcase end 4'b1001: begin op_dw <= `TRUE; case(reg16) 2'b00: begin //JP (VW) op_code <= `OP_MOVE; op_param2 <= reg_VW; op_outreg <= `REG_PC; end 2'b01: begin //MUL BC, DE op_code <= `OP_MUL; op_param1 <= reg_BC; op_param2 <= reg_DE; op_outreg <= `REG_HL; end 2'b10: begin //JP (HL) op_code <= `OP_MOVE; op_param2 <= reg_HL; op_outreg <= `REG_PC; end 2'b11: begin //LD SP, HL op_code <= `OP_MOVE; op_param2 <= reg_HL; op_outreg <= `REG_SP; end endcase end 4'b1011: begin op_dw <= `FALSE; case(reg16) 2'b00: begin // LD V, (HL) op_code <= `OP_LOAD; op_param2 <= reg_HL; op_outreg <= `REG_V; end 2'b01: begin // IN A, (n) op_code <= `OP_IN; op_outreg <= `REG_A; op_param2 <= param; end 2'b10: begin // IN A, (BC) op_code <= `OP_IN; op_outreg <= `REG_A; op_param2 <= reg_BC; end 2'b11: begin // EI op_code <= `OP_MOVE; op_param2 <= 0; op_outreg <= `REG_I; end endcase end 4'b1100: begin op_dw <= `TRUE; if(reg16 == 2'b11) begin // DIV BC, DE op_param1 <= reg_BC; op_param2 <= reg_DE; op_code <= `OP_DIV; op_outreg <= `REG_HL; end else begin // LD rr, VW op_param2 <= reg_VW; op_outreg <= reg16; op_code <= `OP_MOVE; end end 4'b1101: begin op_dw <= `TRUE; if(reg16 == 2'b11) begin // MOD BC, DE op_param1 <= reg_BC; op_param2 <= reg_DE; op_code <= `OP_MOD; op_outreg <= `REG_HL; end else begin // LD VW, rr op_param2 <= reg16_reg; op_outreg <= `REG_VW; op_code <= `OP_MOVE; end end 4'b1111: begin // DIV A, r op_dw <= `FALSE; op_param1 <= reg8_A; op_param2 <= reg8_reg16; op_outreg <= `REG_A; op_code <= `OP_DIV; end endcase end endcase end endmodule