当前位置: 首页 > article >正文

[读书日志]8051软核处理器设计实战(基于FPGA)第六篇:8051软核处理器指令支持添加(verilog)

5.4 为主体程序添加指令

接下来我们来为主体程序添加指令。在开始之前,我们有必要先把目前的代码展示出来:

//`define TYPE8052
module r8051 (

input  wire        clk,
input  wire        rst,
input  wire        cpu_en,
input  wire        cpu_restart,
	
output reg         rom_en,
output reg  [15:0] rom_addr,
input  wire [7:0]  rom_byte,
input  wire        rom_vld,
	
output wire        ram_rd_en_data,
output wire        ram_rd_en_sfr,
`ifdef TYPE8052
output wire        ram_rd_en_idata,
`endif
output wire        ram_rd_en_xdata,
output wire [15:0] ram_rd_addr,
input  wire [7:0]  ram_rd_byte,
input  wire        ram_rd_vld,
	
output wire        ram_wr_en_data,
output wire        ram_wr_en_sfr,
`ifdef TYPE8052
output wire        ram_wr_en_idata,
`endif
output wire        ram_wr_en_xdata,
output wire [15:0] ram_wr_addr,
output wire [7:0]  ram_wr_byte

);

`include "instruction.v"

/*********************************************************/
//register definition

reg                rd_wait;
reg      [7:0]     cmd1;
reg      [7:0]     cmd2;
reg      [2:0]     cmd_flag;
reg      [15:0]    pc;
reg      [7:0]     acc;
reg                psw_ov;
reg                psw_ac;
reg                psw_c;
reg      [3:0]     psw_other;
reg      [15:0]    dp;
reg      [7:0]     sp;
reg      [7:0]     b;
reg                same_flag;
reg      [7:0]     same_byte;
reg      [7:0]     data1;


/*********************************************************/
//wire definition

wire               work_en;
wire     [7:0]     cmd0;
wire     [7:0]     cmda;
wire     [7:0]     cmdb;
wire     [7:0]     cmdc;
reg                pc_en;
wire     [15:0]    pc_add1;
wire     [15:0]    code_base;
wire     [15:0]    code_rel;
wire     [15:0]    code_addr;
wire               length1;
wire               length2r1;
wire               length2;
wire               length3;
wire               rd_en_data_sfr;
wire               rd_en_data_idata;
wire               rd_en_xdata;
wire               rd_en_data;
wire               rd_en_sfr;
`ifdef TYPE8052
wire               rd_en_idata;
`endif
wire               same_flag_data;
wire               same_flag_sfr;
`ifdef TYPE8052
wire               same_flag_idata;
`endif
wire               same_flag_xdata;
wire               read_internal;
reg      [15:0]    rd_addr;
wire               use_psw_rs;
wire               use_dp;
wire               use_acc;
wire               use_sp;
wire               wait_en;
wire               wr_en_data_sfr;
wire               wr_en_data_idata;
wire               wr_en_xdata;
wire               wr_en_data;
wire               wr_en_sfr;
`ifdef TYPE8052
wire               wr_en_idata;
`endif 
wire               write_internal;
reg      [15:0]    wr_addr;
reg      [7:0]     wr_bit_byte;
reg      [7:0]     wr_byte;
reg      [7:0]     add_a;
reg      [7:0]     add_b;
reg                add_c;
reg                sub_flag;
wire               bit_ac;
wire     [3:0]     low;
wire     [3:0]     high;
wire               bit_c;
wire               bit_high; 
wire               bit_ov; 
wire     [7:0]     add_byte;
wire     [15:0]    mult;
wire     [7:0]     and_out;
wire     [7:0]     or_out; 
wire     [7:0]     xor_out;
wire               wr_acc;
wire               psw_p;
wire     [1:0]     psw_rs;
wire               wr_psw_rs; 
wire     [7:0]     psw;
wire               wr_dp;
wire     [7:0]     sp_sub1;
wire     [7:0]     sp_add1;
wire               wr_sp;
wire     [7:0]     div_ans;
wire     [7:0]     div_rem;
reg      [7:0]     data0;


/*********************************************************/


/*********************************************************/
//work_en

always @ ( posedge clk or posedge rst )
if ( rst )
    rd_wait <= 1'b0;
else if ( cpu_restart )
    rd_wait <= 1'b0;	
`ifdef TYPE8052
else if ( ram_rd_en_data|ram_rd_en_sfr|ram_rd_en_idata|ram_rd_en_xdata )
`else
else if ( ram_rd_en_data|ram_rd_en_sfr|ram_rd_en_xdata ) 
`endif	
    rd_wait <= 1'b1;
else if ( ram_rd_vld )
    rd_wait <= 1'b0;	
else;

reg rom_wait;
always @ ( posedge clk or posedge rst )
if ( rst )
    rom_wait <= 1'b0;
else if ( cpu_restart )
    rom_wait <= 1'b0;	
else if ( rom_en )
	rom_wait <= 1'b1;
else if ( rom_vld )
    rom_wait <= 1'b0;
else;


assign work_en = ( ( rd_wait & ~ram_rd_vld )|( rom_wait & ~rom_vld ) ) ? 1'b0 : cpu_en;

/*********************************************************/

/*********************************************************/
//cmd0/cmd1/cmd2  cmda/cmdb/cmdc

assign cmd0 = rom_byte;

always @ ( posedge clk or posedge rst )
if ( rst )
    cmd1 <= 8'b0;
else if ( work_en )
    cmd1 <= cmd0;
else;

always @ ( posedge clk or posedge rst )
if ( rst )
    cmd2 <= 8'b0;
else if ( work_en )
    cmd2 <= cmdb;
else;

always @ ( posedge clk or posedge rst )
if ( rst )
    cmd_flag <= 3'b1;
else if ( cpu_restart )
    cmd_flag <= 3'b1;
else if ( work_en )
    if ( wait_en )
	    cmd_flag <= {1'b0,cmd_flag[1:0]};
    else if ( length2|length2r1 )
	    cmd_flag <= 3'b101;
	else if ( length3 )
	    cmd_flag <= 3'b100;
	else
        cmd_flag <= { cmd_flag[1:0],1'b1};
else;

assign cmda = cmd_flag[1] ? cmd0 : 8'b0;

assign cmdb = cmd_flag[2] ? cmd1 : 8'b0;

assign cmdc = cmd2;


/*********************************************************/


/*********************************************************/
//rom_en rom_addr

always @*
if ( ~work_en )
    pc_en = 1'b0;
else if ( wait_en|length2r1 )
    pc_en = 1'b0;
else
    pc_en = 1'b1;

always @ ( posedge clk or posedge rst )
if ( rst )
    pc <= 16'd0;
else if ( cpu_restart )
    pc <= 16'd0;
else if ( work_en )
    if ( pc_en )
        pc <= pc_add1;
	else;
else;

assign pc_add1 = rom_addr + 1'b1;

always @*
if ( ~work_en )
    rom_en = 1'b0;
else if ( wait_en )
    rom_en = 1'b0;
else if ( length2r1 )
    rom_en = 1‘b0;
else
    rom_en = 1'b1;

assign code_base = 1'b0 ? dp : pc;

assign code_rel = 1'b0 ? {{8{cmd0[7]}},cmd0} : {{8{acc[7]}},acc};	
	
assign code_addr = code_base + code_rel;	

always @*
    rom_addr = 1'b0 ? code_addr : pc;
/*********************************************************/

/*********************************************************/
//command length

assign  length1 = 1'b0;

assign  length2r1 = 1'b0;

assign  length2 = 1'b0;

assign  length3 = 1'b0;


/*********************************************************/


/*********************************************************/
//ram_rd_en ram_rd_addr 

assign rd_en_data_sfr = 1'b0;

assign rd_en_data_idata = 1'b0;

assign rd_en_xdata = 1'b0;

assign rd_en_data = (rd_en_data_sfr|rd_en_data_idata) & ~rd_addr[7];
`ifdef TYPE8052
assign rd_en_sfr = rd_en_data_sfr & rd_addr[7];
assign rd_en_idata = rd_en_data_idata & rd_addr[7];
`else
assign rd_en_sfr = (rd_en_data_sfr|rd_en_data_idata) & rd_addr[7];
`endif
assign same_flag_data = rd_en_data & wr_en_data & (rd_addr[7:0]==wr_addr[7:0]);
assign same_flag_sfr = rd_en_sfr & wr_en_sfr & (rd_addr[7:0]==wr_addr[7:0]);
`ifdef TYPE8052
assign same_flag_idata = rd_en_idata & wr_en_idata & (rd_addr[7:0]==wr_addr[7:0]);
`endif
assign same_flag_xdata = rd_en_xdata & wr_en_xdata & (rd_addr[15:0]==wr_addr[15:0]);
assign read_internal = rd_en_sfr & ( (rd_addr[7:0]==8'he0)|(rd_addr[7:0]==8'hd0)|(rd_addr[7:0]==8'h83)|(rd_addr[7:0]==8'h82)|(rd_addr[7:0]==8'h81)|(rd_addr[7:0]==8'hf0) );
assign ram_rd_en_data = work_en & rd_en_data & ~same_flag_data & ~wait_en;
assign ram_rd_en_sfr = work_en & rd_en_sfr & ~same_flag_sfr & ~read_internal & ~wait_en;
`ifdef TYPE8052
assign ram_rd_en_idata = work_en & rd_en_idata & ~same_flag_idata & ~wait_en;
`endif 
assign ram_rd_en_xdata = work_en & rd_en_xdata & ~same_flag_xdata & ~wait_en;


always @*
    rd_addr = 16'd0;
	
assign ram_rd_addr = rd_addr;	

assign use_psw_rs = 1'b0;

assign use_dp = 1'b0;

assign use_acc = 1'b0;

assign use_sp = 1'b0;

assign wait_en = 1'b0;

/*********************************************************/

/*********************************************************/
//ram_wr_en ram_wr_addr  

assign wr_en_data_sfr = 1'b0;

assign wr_en_data_idata = 1'b0;

assign wr_en_xdata = 1'b0;

assign wr_en_data = (wr_en_data_sfr|wr_en_data_idata) & ~wr_addr[7];
`ifdef TYPE8052
assign wr_en_sfr = wr_en_data_sfr & wr_addr[7];
assign wr_en_idata = wr_en_data_idata & wr_addr[7];
`else
assign wr_en_sfr = (wr_en_data_sfr|wr_en_data_idata) & wr_addr[7];
`endif
assign write_internal = wr_en_sfr & ( (wr_addr[7:0]==8'he0)|(wr_addr[7:0]==8'hd0)|(wr_addr[7:0]==8'h83)|(wr_addr[7:0]==8'h82)|(wr_addr[7:0]==8'h81)|(wr_addr[7:0]==8'hf0) );
assign ram_wr_en_data = work_en & wr_en_data;
assign ram_wr_en_sfr = work_en & wr_en_sfr & ~write_internal;
`ifdef TYPE8052
assign ram_wr_en_idata = work_en & wr_en_idata;
`endif
assign ram_wr_en_xdata = work_en & wr_en_xdata;

always @*
    wr_addr = 16'd0;

assign ram_wr_addr = wr_addr;	

/*********************************************************/


/*********************************************************/
//ram_wr_byte

always @* begin
wr_bit_byte = data0;
end

always @*
    wr_byte = 8'd0;

assign ram_wr_byte = wr_byte;

/*********************************************************/


/*********************************************************/
//acc register

always @*
    add_a = 8'b0;


always @*
    add_b = 8'b0;


always @*
    add_c = 1'b0;	


always @*
    sub_flag = 1'b0;


assign {bit_ac,low} = sub_flag ? (add_a[3:0]-add_b[3:0]-add_c) : (add_a[3:0]+add_b[3:0]+add_c);
assign high = sub_flag ? (add_a[6:4]-add_b[6:4]-bit_ac) : (add_a[6:4]+add_b[6:4]+bit_ac);
assign {bit_c,bit_high} = sub_flag ? (add_a[7]-add_b[7]-high[3]) : (add_a[7]+add_b[7]+high[3]);
assign bit_ov = bit_c ^ high[3];
assign add_byte = {bit_high,high[2:0],low};

assign mult = acc * b;
assign {div_rem,div_ans} = divide(acc,b);
assign and_out = acc & data0;
assign or_out  = acc | data0;
assign xor_out = acc ^ data0;

wire [3:0] da_low  = ( psw_ac|(acc[3:0]>4'h9) ) ? (acc[3:0]+4'd6) : acc[3:0];
wire [3:0] da_high = ( ( psw_c|(acc[7:4]>4'h9)|((acc[7:4]==4'h9)&(psw_ac|(acc[3:0]>4'h9))) ) ? ( acc[7:4]+4'h6 ) : acc[7:4] ) + ( psw_ac|(acc[3:0]>4'h9) );
	
always @ ( posedge clk or posedge rst )
if ( rst )
    acc <= 8'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'he0 ) )
	    acc <= wr_byte;
	else;
else;

assign wr_acc = wr_en_sfr & (wr_addr[7:0]==8'he0);

/*********************************************************/


/*********************************************************/
//psw register

assign psw_p = ^acc;

always @ ( posedge clk or posedge rst )
if ( rst )
    psw_ov <= 1'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'hd0 ) )
	    psw_ov <= wr_byte[2];
	else;
else;

always @ ( posedge clk or posedge rst )
if ( rst )
    psw_ac <= 1'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'hd0 ) )
	    psw_ac <= wr_byte[6];
	else;
else;

always @ ( posedge clk or posedge rst )
if ( rst )
    psw_c <= 1'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'hd0 ) )
	    psw_c <= wr_byte[7];
	else;
else;

always @ ( posedge clk or posedge rst )
if ( rst )
    psw_other <= 4'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'hd0 ) )
	    psw_other <= {wr_byte[5:3],wr_byte[1]};
	else;
else;

assign psw_rs = psw_other[2:1];

assign wr_psw_rs = wr_en_sfr & (wr_addr[7:0]==8'hd0);

assign psw = {psw_c,psw_ac,psw_other[3:1],psw_ov,psw_other[0],psw_p};

/*********************************************************/

/*********************************************************/
//dp  sp registers

always @ ( posedge clk or posedge rst )
if ( rst )
    dp <= 16'b0;
else if ( work_en )
    if  ( wr_en_sfr & (wr_addr[7:0]==8'h82 ) )
	    dp[7:0] <= wr_byte;
	else if  ( wr_en_sfr & (wr_addr[7:0]==8'h83 ) )
	    dp[15:8] <= wr_byte;
	else;
else;

assign wr_dp = (wr_en_sfr & ((wr_addr[7:0]==8'h82)|(wr_addr[7:0]==8'h83)))|inc_dp(cmdb);

always @ ( posedge clk or posedge rst )
if ( rst )
    sp <= 8'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'h81) )
	    sp <= wr_byte;
	else;
else;

assign sp_sub1 = sp - 1'b1;

assign sp_add1 = sp + 1'b1;

assign wr_sp = (wr_en_sfr & (wr_addr[7:0]==8'h81));

always @ ( posedge clk or posedge rst )
if ( rst )
    b <= 8'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'hf0) )
	    b <= wr_byte;
	else;
else;

/*********************************************************/


/*********************************************************/
//ram output

always @*
if ( same_flag )
    data0 = same_byte;
else if ( same_byte[7] )
    data0 = acc;
else if ( same_byte[6] )
    data0 = psw;
else if ( same_byte[5] )
    data0 = dp[15:8];
else if ( same_byte[4] )
    data0 = dp[7:0];
else if ( same_byte[3] )
    data0 = sp;
else if ( same_byte[2] )
    data0 = b;
else
    data0 = ram_rd_byte;

always @ ( posedge clk or posedge rst )
if ( rst )
    data1 <= 8'b0;
else if ( work_en )
    data1 <= data0;
else;
    
always @ ( posedge clk or posedge rst )
if ( rst )
    same_flag <= 1'b0;
else if ( work_en )
`ifdef TYPE8052
    if ( same_flag_data|same_flag_sfr|same_flag_idata|same_flag_xdata )
`else 
    if ( same_flag_data|same_flag_sfr|same_flag_xdata )
`endif	
	    same_flag <= 1'b1;
	else
	    same_flag <= 1'b0;
else;

always @ ( posedge clk or posedge rst )
if ( rst )
    same_byte <= 8'd0;
else if ( work_en )
`ifdef TYPE8052
    if ( same_flag_data|same_flag_sfr|same_flag_idata|same_flag_xdata )
`else
    if ( same_flag_data|same_flag_sfr|same_flag_xdata )
`endif	
	    same_byte <= wr_byte;
	else if ( rd_en_sfr & (rd_addr[7:0]==8'he0) ) //acc
	    same_byte <= 1'b1<<7;
	else if ( rd_en_sfr & (rd_addr[7:0]==8'hd0) ) //psw
	    same_byte <= 1'b1<<6;
	else if ( rd_en_sfr & (rd_addr[7:0]==8'h83) ) //dph
	    same_byte <= 1'b1<<5;	
	else if ( rd_en_sfr & (rd_addr[7:0]==8'h82) ) //dpl
	    same_byte <= 1'b1<<4;	
	else if ( rd_en_sfr & (rd_addr[7:0]==8'h81) ) //sp
	    same_byte <= 1'b1<<3;
	else if ( rd_en_sfr & (rd_addr[7:0]==8'hf0) ) //b
	    same_byte <= 1'b1<<2;		
	else
	    same_byte <= 8'b0;
else;
	
/*********************************************************/

endmodule

5.4.1 算数操作指令的添加

指令添加最方便的方法是一条一条添加,由于每一条单独的指令都很简单,只需要对某些地方修改,并让主体程序的读写过程满足该指令的要求,那么这条指令就完成了。

算术操作指令有24条,主要是完成数据的加减乘除等算术运算,一般流程是从数据存储区取得某个数据,让它和其他数据进行算术运算,将结果写入数据存储区的某个地址。

第一步,我们完善指令的字节长度判断,顺便把这些指令罗列出来:

//command length

assign  length1 = add_a_rn(cmda)|addc_a_rn(cmda)|subb_a_rn(cmda)|inc_a(cmda)|inc_rn(cmda)|inc_dp(cmda)|dec_a(cmda)|dec_rn(cmda)|mul(cmda)|div(cmda)|da(cmda);

assign  length2r1 = add_a_ri(cmda)|addc_a_ri(cmda)|subb_a_ri(cmda)|inc_ri(cmda)|dec_ri(cmda);

assign  length2 = add_a_di(cmda)|add_a_da(cmda)|addc_a_di(cmda)|addc_a_da(cmda)|subb_a_di(cmda)|subb_a_da(cmda)|inc_di(cmda)|dec_di(cmda);

assign  length3 = 1'b0;

算术操作指令只有单字节和双字节,没有三字节。

单字节指令分为length1length2r1length2r1表示它虽然是单字节指令,但要当成两字节处理,但指令存储区没有存放单字节的第二虚拟字节,在处理器读到length2r1的任何一条指令后,程序将停止一个周期再读下一条指令。

观察后可以发现,length2r1的指令都带有_ri字样,这表示寄存器间接寻址指令需要花费两个周期才能完成操作,在前面已经解释过了。

接着来看读使能和读地址的赋值部分,需要从外部RAM读取的指令,将读使能拉高。首先分析一下单字节的指令:

add_a_rn(cmda)|addc_a_rn(cmda)|subb_a_rn(cmda)|inc_a(cmda)|inc_rn(cmda)|inc_dp(cmda)|dec_a(cmda)|dec_rn(cmda)|mul(cmda)|div(cmda)|da(cmda)

单字节的指令在cmda执行读操作。rd_en信号分为三类,第一类rd_en_data_sfr是读取DATA区和SFR区,具体是哪个区由地址的位区分(低地址是DATA区,高地址是SFR区);第二类rd_en_data_idata是读取DATA区,IDATA区,具体是哪个区取决于处理器是否是8052类型,如果是那么取决于地址位(低地址是DATA区,高地址是SFR区),如果不是则全部是读取DATA区;第三类rd_en_xdata是对XDATA区读取。

以加法指令为例详细分析一下:

第一条加法指令ADD A,Rn,是单字节指令,使用寄存器寻址,指令标识是add_a_rn。它先从Rn中读取数据,将其与ACC中的数据相加,最后将结果写入ACC中。因此,它需要读取SFR区(读取ACC)和DATA区(读取Rn)。由于我们将ACC寄存器单独设置,所以这里只需要读取DATA区以取出Rn中的操作数。DATA区的寄存器组区中的寄存器分为4组,特殊寄存器PSW的RS[1:0]决定了是这四组中的哪一组,而指令中的后三位决定了是这一组中的R0到R7的哪一个。因此究竟读取的地址是什么,要通过拼接算出来,实际上由于DATA区是地址的低部分,所以只需要低5位使用{RS[1:0],cmd0[2:0]}即可。

因此,体现在读使能上是rd_en_data_sfr拉高,并且将读地址rd_addr赋值。如下所示:

assign rd_en_data_sfr = add_a_rn(cmda);

always @*
	if(add_a_rn(cmda))
		rd_addr = {psw_rs, cmd0[2:0]};
	else
    	rd_addr = 16'd0;

第二条加法指令ADD A, Direct,是双字节指令,采用直接寻址,指令标识是add_a_di,指令的第二个字节存放的是操作数的地址,根据它的地址可以知道是从SFR区还是DATA区取出数据。体现在读使能上是rd_en_data_sfr拉高(添加后面的指令都应使用或逻辑连接多条指令),并且将读地址rd_addr直接赋值为双字节指令的第二个字节。注意这里双字节指令在cmdb发起读操作,这时cmd0存放了这条指令的第二个字节,直接把它赋值给rd_addr即可。

assign rd_en_data_sfr = add_a_rn(cmda)|add_a_di(cmdb);

always @*
	if(add_a_rn(cmda))
		rd_addr = {psw_rs, cmd0[2:0]};
	else if(add_a_di(cmdb))
		rd_addr = cmd0;
	else
    	rd_addr = 16'd0;

第三条加法指令ADD A,@Ri,是单字节指令,指令标识是add_a_ri,由于使用寄存器间接寻址,所以将其扩展为虚拟双字节指令。通过指令的[0]位可以知道该地址是放在R0还是R1中,从寄存器R0或R1内获取地址,并按照这个地址再从DATA区或SFR区(对于8052来说是从DATA区或IDATA区)取出数据,将其和ACC中的数据相加,最后将结果写入寄存器ACC中。虚拟双字节指令将会使能两次读操作,第一次在cmda时读取Ri中的地址,第二次使用Ri中的地址读出真正的数据。

assign rd_en_data_sfr = add_a_rn(cmda)|add_a_di(cmdb)|add_a_ri(cmda);
assign rd_en_data_idata = add_a_ri(cmdb);

always @*
	if(add_a_rn(cmda))//使用寄存器寻址,读地址使用PSW_RS[1:0]和cmd0[2:0]拼接
        rd_addr = {psw_rs, cmd0[2:0]};
	else if(add_a_di(cmdb))//使用直接寻址,读地址使用cmd0
        rd_addr = cmd0;
	else if(add_a_ri(cmda))//使用寄存器间接寻址,读取Ri的地址使用PSW_RS[1:0]和cmd0[0]拼接
        rd_addr = {psw_rs,2'b0,cmd0[0]}
	else if(add_a_ri(cmdb))//使用寄存器间接寻址,读取到Ri的数据作为地址
        rd_addr = data0;
	else
        rd_addr = 16'd0;

第四条加法指令ADD A,#DATA,双字节指令,指令标识add_a_da,采用立即寻址,第二个字节保存的是一个立即数,即直接参与运算的数据。直接将其与ACC中的数据相加,最后将结果写入寄存器ACC中即可。由于它不涉及到对于RAM的读取,因此它不占用读使能和读地址。

其他的算术指令与这四条加法指令类似,在此不作赘述,直接给出添加算术指令后的完整读使能和读地址:

assign rd_en_data_sfr = add_a_rn(cmda)|add_a_di(cmdb)|add_a_ri(cmda)|addc_a_rn(cmda)|addc_a_di(cmdb)|addc_a_ri(cmda)|subb_a_rn(cmda)|subb_a_di(cmdb)|subb_a_ri(cmda)|inc_rn(cmda)|inc_di(cmdb)|inc_ri(cmda)|dec_rn(cmda)|dec_di(cmdb)|dec_ri(cmda);

assign rd_en_data_idata = add_a_ri(cmdb)|addc_a_ri(cmdb)|subb_a_ri(cmdb)|inc_ri(cmdb)|dec_ri(cmdb);

assign rd_en_xdata = 1'b0;

assign rd_en_data = (rd_en_data_sfr|rd_en_data_idata) & ~rd_addr[7];

always @*
if ( add_a_rn(cmda)|addc_a_rn(cmda)|subb_a_rn(cmda)|inc_rn(cmda)|dec_rn(cmda))//使用寄存器寻址,读地址使用PSW_RS[1:0]和cmd0[2:0]拼接
    rd_addr = { psw_rs,cmd0[2:0] };
else if ( add_a_di(cmdb)|addc_a_di(cmdb)|subb_a_di(cmdb)|inc_di(cmdb)|dec_di(cmdb))//使用直接寻址,读地址使用cmd0
    rd_addr = cmd0;
else if ( add_a_ri(cmda)|addc_a_ri(cmda)|subb_a_ri(cmda)|inc_ri(cmda)|dec_ri(cmda))//使用寄存器间接寻址,读取Ri的地址使用PSW_RS[1:0]和cmd0[0]拼接
    rd_addr = { psw_rs,2'b0,cmd0[0] };
else if ( add_a_ri(cmdb)|addc_a_ri(cmdb)|subb_a_ri(cmdb)|inc_ri(cmdb)|dec_ri(cmdb))//使用寄存器间接寻址,读取到Ri的数据作为地址
    rd_addr = data0;
else
    rd_addr = 16'd0;

分析读地址时,发现进行读操作需要用到PSW寄存器的RS段作为读地址的一部分,这会引起读地址与上一级的写数据冲突,因此必须用下面描述声明:凡用到psw_rs的读地址都要列出。如果上一条指令正好是写PSW寄存器的话,我们的主体程序会进行判别,并主动避开这种情况。

大部分指令将结果写入ACC寄存器,但也有部分指令需要写入存储器,它们需要进行写操作。对写使能和写地址赋值,同时需要确定写数据:

assign use_psw_rs = add_a_rn(cmda)|add_a_ri(cmda)|addc_a_rn(cmda)|addc_a_ri(cmda)|subb_a_rn(cmda)|subb_a_ri(cmda)|inc_rn(cmda)|inc_ri(cmda)|dec_rn(cmda)|dec_ri(cmda);

//ram_wr_en ram_wr_addr  

assign wr_en_data_sfr = inc_rn(cmdb)|inc_di(cmdc)|dec_rn(cmdb)|dec_di(cmdc)

assign wr_en_data_idata = inc_ri(cmdc)|dec_ri(cmdc)

assign wr_en_xdata = 1'b0;

always @*
    if ( inc_rn(cmdb)|dec_rn(cmdb) )//写入Rn
    wr_addr = { psw_rs,cmd1[2:0] };
else if ( inc_di(cmdc)|dec_di(cmdc) )//直接地址作为写地址
    wr_addr = cmd1;
else if ( inc_ri(cmdc)|dec_ri(cmdc) )//以Ri作为写地址
    wr_addr = data1;
else
    wr_addr = 16'd0;

//wr_byte

always @*
else if ( mov_rn_a(cmdb)|mov_di_a(cmdb)|mov_ri_a(cmdb)|movx_ri_a(cmdb)|movx_dp_a(cmdb)|xch_a_rn(cmdb)|xch_a_di(cmdc)|xch_a_ri(cmdc) )
    wr_byte = acc;
else if ( mov_rn_di(cmdc)|mov_di_rn(cmdb)|mov_di_di(cmdc)|mov_di_ri(cmdc)|mov_ri_di(cmdc)|push(cmdc)|pop(cmdb) )
    wr_byte = data0;
else
    wr_byte = 8'd0;

接下来需要控制通用加减器。通用加减器输入有4项,分别是add_a,add_b,add_c和sub_flag。它们分别控制加数(被减数),加数(减数),额外的一个比特位和加减选择。上面的指令只需改变这四项即可实现不同的指令选择,如ADD,ADDC,SUBB,DEC,INC等。

always @*
if ( add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb)|inc_a(cmdb)|dec_a(cmdb) )
    add_a = acc;
else if ( inc_rn(cmdb)|inc_di(cmdc)|inc_ri(cmdc)|dec_rn(cmdb)|dec_di(cmdc)|dec_ri(cmdc))
    add_a = data0;
else
    add_a = 8'b0;


always @*
if ( add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc) )
    add_b = data0;
else if ( add_a_da(cmdb)|addc_a_da(cmdb)|subb_a_da(cmdb) )
    add_b = cmd0;
else if ( inc_a(cmdb)|dec_a(cmdb)|inc_rn(cmdb)|inc_di(cmdc)|inc_ri(cmdc)|dec_rn(cmdb)|dec_di(cmdc)|dec_ri(cmdc))
    add_b = 8'b0;
else
    add_b = 8'b0;


always @*
if ( add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb) )
    add_c = 1'b0;
else if (addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb) )
    add_c = psw_c;
else if (inc_a(cmdb)|inc_rn(cmdb)|inc_di(cmdc)|inc_ri(cmdc)|dec_a(cmdb)|dec_rn(cmdb)|dec_di(cmdc)|dec_ri(cmdc))
    add_c = 1'b1;	
else
    add_c = 1'b0;	


always @*
if (add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|inc_a(cmdb)|inc_rn(cmdb)|inc_di(cmdc)|inc_ri(cmdc) )
    sub_flag = 1'b0;
else if (subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb)|dec_a(cmdb)|dec_rn(cmdb)|dec_di(cmdc)|dec_ri(cmdc))
    sub_flag = 1'b1;
else
    sub_flag = 1'b0;

之后需要写入寄存器,主要包括ACC寄存器和状态寄存器。

ACC寄存器的修改逻辑:

wire [3:0] da_low  = ( psw_ac|(acc[3:0]>4'h9) ) ? (acc[3:0]+4'd6) : acc[3:0];
wire [3:0] da_high = ( ( psw_c|(acc[7:4]>4'h9)|((acc[7:4]==4'h9)&(psw_ac|(acc[3:0]>4'h9))) ) ? ( acc[7:4]+4'h6 ) : acc[7:4] ) + ( psw_ac|(acc[3:0]>4'h9) );
	
always @ ( posedge clk or posedge rst )
if ( rst )
    acc <= 8'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'he0 ) )
	    acc <= wr_byte;
	else if ( add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb)|inc_a(cmdb)|dec_a(cmdb) )
	    acc <= add_byte;
	else if ( mul(cmdb) )
	    acc <= mult[7:0];
	else if ( div(cmdb) )
	    acc <= div_ans;
	else if ( da(cmdb) )
	    acc <= {da_high,da_low};	
	else;
else;

由于ACC寄存器也用作读地址,为了组织wait_en,我们也需要声明是否要读ACC寄存器的写操作:

assign wr_acc = (wr_en_sfr & (wr_addr[7:0]==8'he0))|add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb)|inc_a(cmdb)|dec_a(cmdb)|mul(cmdb)|div(cmdb)|da(cmdb);

之后需要修改PSW寄存器的特殊位:

always @ ( posedge clk or posedge rst )
if ( rst )
    psw_ov <= 1'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'hd0 ) )
	    psw_ov <= wr_byte[2];
	else if ( add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb) )
	    psw_ov <= bit_ov;
	else if ( mul(cmdb) )
	    psw_ov <= (mult[15:8]!=8'b0);
	else if ( div(cmdb) )
	    psw_ov <= (b==8'b0);
	else;
else;

always @ ( posedge clk or posedge rst )
if ( rst )
    psw_ac <= 1'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'hd0 ) )
	    psw_ac <= wr_byte[6];
	else if ( add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb) )
	    psw_ac <= bit_ac;
	else;
else;

always @ ( posedge clk or posedge rst )
if ( rst )
    psw_c <= 1'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'hd0 ) )
	    psw_c <= wr_byte[7];
	else if ( add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb) )
	    psw_c <= bit_c;
	else if ( mul(cmdb)|div(cmdb) )
	    psw_c <= 1'b0;
	else if ( da(cmdb) )
	    psw_c <= ( psw_c|(acc[7:4]>4'h9)|((acc[7:4]==4'h9)&(psw_ac|(acc[3:0]>4'h9))) ) ? 1'b1 : psw_c;
	else;
else;

always @ ( posedge clk or posedge rst )
if ( rst )
    psw_other <= 4'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'hd0 ) )
	    psw_other <= {wr_byte[5:3],wr_byte[1]};
	else;
else;

最后在进行乘除运算时需要修改B寄存器:

always @ ( posedge clk or posedge rst )
if ( rst )
    b <= 8'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'hf0) )
	    b <= wr_byte;
	else if ( mul(cmdb) )
	    b <= mult[15:8];
	else if ( div(cmdb) )
	    b <= div_rem;
	else;
else;

这样,我们就完全实现了算术运算指令。之后的其他指令我们不再详细叙述,其修改的方式和添加算术指令类似,我们只针对一些特殊的地方进行说明。

5.4.2 逻辑操作指令的添加

逻辑操作指令几乎与算术操作指令完全类似,除了计算结果的地方有所区别。结果的计算如下:

assign and_out = ( anl_di_da(cmdc) ? cmd0 : acc ) & ( anl_a_da(cmdb) ? cmd0 : data0 );
assign or_out  = ( orl_di_da(cmdc) ? cmd0 : acc ) | ( orl_a_da(cmdb) ? cmd0 : data0 );
assign xor_out = ( xrl_di_da(cmdc) ? cmd0 : acc ) ^ ( xrl_a_da(cmdb) ? cmd0 : data0 );

只需要将这些结果按照对应的指令要求写入ACC寄存器即可。

5.4.3 数据转移指令的添加

这里有两条特殊指令movc_a_dpmovc_a_pc,它们涉及到把指令存储区CODE区某地址的数据搬移到ACC寄存器上,对CODE区的访问是通过信号rom_en和rom_addr[15:0]完成的。

always @*
if ( ~work_en )
    rom_en = 1'b0;
else if ( wait_en )
    rom_en = 1'b0;
else if ( length2r1 )
    rom_en = movc_a_dp(cmda)|movc_a_pc(cmda);
else if ( acall(cmdb)|ret(cmda)|ret(cmdb)|reti(cmda)|reti(cmdb) )
    rom_en = 1'b0;	
else
    rom_en = 1'b1;

assign code_base = ( movc_a_dp(cmda)|jmp(cmda) ) ? dp : pc;

assign code_rel = ( jc(cmdb)||jnc(cmdb)|jb(cmdc)|jnb(cmdc)|jbc(cmdc)|sjmp(cmdb)|jz(cmdb)|jnz(cmdb)|cjne_a_di_rel(cmdc)|cjne_a_da_rel(cmdc)|cjne_rn_da_rel(cmdc)|cjne_ri_da_rel(cmdc)|djnz_rn_rel(cmdb)|djnz_di_rel(cmdc) ) ? {{8{cmd0[7]}},cmd0} : {{8{acc[7]}},acc};	
	
assign code_addr = code_base + code_rel;	

rom_addr = (movc_a_dp(cmda) | movc_a_pc(cmda)) ? code_addr : pc;

code_addr由两部分组成,一是基地址,要么是DP,要么是PC;二是变地址,由ACC寄存器或cmd0直接寻址的第二个字节来表示。

在读地址的赋值部分和前面两类差不多,需要注意的是这里使用到了DPTR和SP作为读地址,在内部需要标注内部寄存器的占用信号:

assign use_psw_rs = add_a_rn(cmda)|add_a_ri(cmda)|addc_a_rn(cmda)|addc_a_ri(cmda)|subb_a_rn(cmda)|subb_a_ri(cmda)|inc_rn(cmda)|inc_ri(cmda)|dec_rn(cmda)|dec_ri(cmda)|anl_a_rn(cmda)|anl_a_ri(cmda)|orl_a_rn(cmda)|orl_a_ri(cmda)|xrl_a_rn(cmda)|xrl_a_ri(cmda)|mov_a_rn(cmda)|mov_a_ri(cmda)|mov_di_rn(cmda)|mov_di_ri(cmda)|mov_ri_a(cmda)|mov_ri_di(cmda)|mov_ri_da(cmda)|movx_a_ri(cmda)|movx_ri_a(cmda)|xch_a_rn(cmda)|xch_a_ri(cmda);

assign use_dp = movc_a_dp(cmda)|movx_a_dp(cmda);

assign use_acc = movc_a_dp(cmda)|movc_a_pc(cmda);

assign use_sp = pop(cmda)|ret(cmda)|reti(cmda);

对SP寄存器的修改:

always @ ( posedge clk or posedge rst )
if ( rst )
    sp <= 8'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'h81) )
	    sp <= wr_byte;
	else if ( push(cmdb) )
	    sp <= sp_add1;
    else if ( pop(cmdb) )
        sp <= sp_sub1;	
	else;
else;

assign sp_sub1 = sp - 1'b1;

assign sp_add1 = sp + 1'b1;
5.4.4 布尔变量操作指令的添加

这类指令主要是涉及到位操作,读地址只有一种,就是读可位操作区。可位操作区分为两类,一类是以8’h20为开始地址的DATA区的专门位操作区,另一类是SFR区的某些特殊寄存器。它们不会只读出需要的一个位,而还是读出了整个字节。在写入时,也只需要操作一个位,因此使用wr_bit_byte,只需修改需要修改的位,把它和其他无需修改的位一起写回即可。

always @* begin
wr_bit_byte = data0;
if ( clr_bit(cmdc)|jbc(cmdc) )
    wr_bit_byte[cmd1[2:0]] = 1'b0;
else if ( setb_bit(cmdc) )
    wr_bit_byte[cmd1[2:0]] = 1'b1;
else if ( cpl_bit(cmdc)	)
    wr_bit_byte[cmd1[2:0]] = ~wr_bit_byte[cmd1[2:0]];
else if ( mov_bit_c(cmdc) )	
    wr_bit_byte[cmd1[2:0]] = psw_c;
else;
end
5.5.5 程序跳转指令的添加

这类指令需要更改它们取出的地址,需要对一些特殊的指令进行特殊化处理。第一个特殊指令是ACALL指令,它有两次写操作,并且必须写入PC寄存器在取出第二个字节后的地址。所以我们把它扩展成三字节指令,取出第二个指令后,PC不再增加,那么在第二个字节和虚拟的第三个字节出现时把PC压入栈内。

因此增加了PC_en信号,用于控制PC在acall(cmdb)时不能增加。

always @*
if ( ~work_en )
    pc_en = 1'b0;
else if ( wait_en|length2r1 )
    pc_en = 1'b0;
else if ( acall(cmdb)|ret(cmda)|ret(cmdb)|reti(cmda)|reti(cmdb) )
    pc_en = 1'b0;
else
    pc_en = 1'b1;

其中的ret和reti都是单字节指令,需要扩展成三字节,使其不再增加。

rom_en和rom_addr都需要进行相关的修改,还有一些压栈,出栈涉及到的数据操作,还有DJNZ类指令需要进行递减操作,通用加减器需要打开。片内的PSW的CY位也需要对应修改,压栈出栈的SP寄存器需要递增或递减。具体的修改不再赘述,在此处贴出完整的全部代码,供进行详细研究:

/
//
//Copyright 2018  Li Xinbing
//
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//
/

//`define TYPE8052
module r8051 (

input  wire        clk,
input  wire        rst,
input  wire        cpu_en,
input  wire        cpu_restart,
	
output reg         rom_en,
output reg  [15:0] rom_addr,
input  wire [7:0]  rom_byte,
input  wire        rom_vld,
	
output wire        ram_rd_en_data,
output wire        ram_rd_en_sfr,
`ifdef TYPE8052
output wire        ram_rd_en_idata,
`endif
output wire        ram_rd_en_xdata,
output wire [15:0] ram_rd_addr,
input  wire [7:0]  ram_rd_byte,
input  wire        ram_rd_vld,
	
output wire        ram_wr_en_data,
output wire        ram_wr_en_sfr,
`ifdef TYPE8052
output wire        ram_wr_en_idata,
`endif
output wire        ram_wr_en_xdata,
output wire [15:0] ram_wr_addr,
output wire [7:0]  ram_wr_byte

);

`include "instruction.v"

/*********************************************************/
//register definition

reg                rd_wait;
reg      [7:0]     cmd1;
reg      [7:0]     cmd2;
reg      [2:0]     cmd_flag;
reg      [15:0]    pc;
reg      [7:0]     acc;
reg                psw_ov;
reg                psw_ac;
reg                psw_c;
reg      [3:0]     psw_other;
reg      [15:0]    dp;
reg      [7:0]     sp;
reg      [7:0]     b;
reg                same_flag;
reg      [7:0]     same_byte;
reg      [7:0]     data1;


/*********************************************************/
//wire definition

wire               work_en;
wire     [7:0]     cmd0;
wire     [7:0]     cmda;
wire     [7:0]     cmdb;
wire     [7:0]     cmdc;
reg                pc_en;
wire     [15:0]    pc_add1;
wire     [15:0]    code_base;
wire     [15:0]    code_rel;
wire     [15:0]    code_addr;
wire               length1;
wire               length2r1;
wire               length2;
wire               length3;
wire               rd_en_data_sfr;
wire               rd_en_data_idata;
wire               rd_en_xdata;
wire               rd_en_data;
wire               rd_en_sfr;
`ifdef TYPE8052
wire               rd_en_idata;
`endif
wire               same_flag_data;
wire               same_flag_sfr;
`ifdef TYPE8052
wire               same_flag_idata;
`endif
wire               same_flag_xdata;
wire               read_internal;
reg      [15:0]    rd_addr;
wire               use_psw_rs;
wire               use_dp;
wire               use_acc;
wire               use_sp;
wire               wait_en;
wire               wr_en_data_sfr;
wire               wr_en_data_idata;
wire               wr_en_xdata;
wire               wr_en_data;
wire               wr_en_sfr;
`ifdef TYPE8052
wire               wr_en_idata;
`endif 
wire               write_internal;
reg      [15:0]    wr_addr;
reg      [7:0]     wr_bit_byte;
reg      [7:0]     wr_byte;
reg      [7:0]     add_a;
reg      [7:0]     add_b;
reg                add_c;
reg                sub_flag;
wire               bit_ac;
wire     [3:0]     low;
wire     [3:0]     high;
wire               bit_c;
wire               bit_high; 
wire               bit_ov; 
wire     [7:0]     add_byte;
wire     [15:0]    mult;
wire     [7:0]     and_out;
wire     [7:0]     or_out; 
wire     [7:0]     xor_out;
wire               wr_acc;
wire               psw_p;
wire     [1:0]     psw_rs;
wire               wr_psw_rs; 
wire     [7:0]     psw;
wire               wr_dp;
wire     [7:0]     sp_sub1;
wire     [7:0]     sp_add1;
wire               wr_sp;
wire     [7:0]     div_ans;
wire     [7:0]     div_rem;
reg      [7:0]     data0;


/*********************************************************/


/*********************************************************/
//work_en

always @ ( posedge clk or posedge rst )
if ( rst )
    rd_wait <= 1'b0;
else if ( cpu_restart )
    rd_wait <= 1'b0;	
`ifdef TYPE8052
else if ( ram_rd_en_data|ram_rd_en_sfr|ram_rd_en_idata|ram_rd_en_xdata )
`else
else if ( ram_rd_en_data|ram_rd_en_sfr|ram_rd_en_xdata ) 
`endif	
    rd_wait <= 1'b1;
else if ( ram_rd_vld )
    rd_wait <= 1'b0;	
else;

reg rom_wait;
always @ ( posedge clk or posedge rst )
if ( rst )
    rom_wait <= 1'b0;
else if ( cpu_restart )
    rom_wait <= 1'b0;	
else if ( rom_en )
	rom_wait <= 1'b1;
else if ( rom_vld )
    rom_wait <= 1'b0;
else;


assign work_en = ( ( rd_wait & ~ram_rd_vld )|( rom_wait & ~rom_vld ) ) ? 1'b0 : cpu_en;

/*********************************************************/

/*********************************************************/
//cmd0/cmd1/cmd2  cmda/cmdb/cmdc

assign cmd0 = rom_byte;

always @ ( posedge clk or posedge rst )
if ( rst )
    cmd1 <= 8'b0;
else if ( work_en )
    cmd1 <= cmd0;
else;

always @ ( posedge clk or posedge rst )
if ( rst )
    cmd2 <= 8'b0;
else if ( work_en )
    cmd2 <= cmdb;
else;

always @ ( posedge clk or posedge rst )
if ( rst )
    cmd_flag <= 3'b1;
else if ( cpu_restart )
    cmd_flag <= 3'b1;
else if ( work_en )
    if ( wait_en )
	    cmd_flag <= {1'b0,cmd_flag[1:0]};
    else if ( length2|length2r1 )
	    cmd_flag <= 3'b101;
	else if ( length3 )
	    cmd_flag <= 3'b100;
	else
        cmd_flag <= { cmd_flag[1:0],1'b1};
else;

assign cmda = cmd_flag[1] ? cmd0 : 8'b0;

assign cmdb = cmd_flag[2] ? cmd1 : 8'b0;

assign cmdc = cmd2;


/*********************************************************/


/*********************************************************/
//rom_en rom_addr

always @*
if ( ~work_en )
    pc_en = 1'b0;
else if ( wait_en|length2r1 )
    pc_en = 1'b0;
else if ( acall(cmdb)|ret(cmda)|ret(cmdb)|reti(cmda)|reti(cmdb) )
    pc_en = 1'b0;
else
    pc_en = 1'b1;

always @ ( posedge clk or posedge rst )
if ( rst )
    pc <= 16'd0;
else if ( cpu_restart )
    pc <= 16'd0;
else if ( work_en )
    if ( pc_en )
        pc <= pc_add1;
	else;
else;

assign pc_add1 = rom_addr + 1'b1;

always @*
if ( ~work_en )
    rom_en = 1'b0;
else if ( wait_en )
    rom_en = 1'b0;
else if ( length2r1 )
    rom_en = movc_a_dp(cmda)|movc_a_pc(cmda);
else if ( acall(cmdb)|ret(cmda)|ret(cmdb)|reti(cmda)|reti(cmdb) )
    rom_en = 1'b0;	
else
    rom_en = 1'b1;

assign code_base = ( movc_a_dp(cmda)|jmp(cmda) ) ? dp : pc;

assign code_rel = ( jc(cmdb)||jnc(cmdb)|jb(cmdc)|jnb(cmdc)|jbc(cmdc)|sjmp(cmdb)|jz(cmdb)|jnz(cmdb)|cjne_a_di_rel(cmdc)|cjne_a_da_rel(cmdc)|cjne_rn_da_rel(cmdc)|cjne_ri_da_rel(cmdc)|djnz_rn_rel(cmdb)|djnz_di_rel(cmdc) ) ? {{8{cmd0[7]}},cmd0} : {{8{acc[7]}},acc};	
	
assign code_addr = code_base + code_rel;	

always @*
if ( acall(cmdc) )
    rom_addr = {pc[15:11],cmd2[7:5],cmd1};
else if ( lcall(cmdc)|ljmp(cmdc) )
    rom_addr = {cmd1,cmd0};	
else if ( ret(cmdc)|reti(cmdc) )
    rom_addr = {data1,data0};
else if ( ajmp(cmdb) )
    rom_addr = {pc[15:11],cmd1[7:5],cmd0};	
else if ( movc_a_dp(cmda)|movc_a_pc(cmda)|(jc(cmdb) & psw_c)|(jnc(cmdb) & ~psw_c)|((jb(cmdc)|jbc(cmdc)) & data0[cmd1[2:0]])|(jnb(cmdc) & ~data0[cmd1[2:0]])|sjmp(cmdb)|jmp(cmda)|(jz(cmdb) & (acc==8'b0))|(jnz(cmdb) & (acc!=8'b0))|(cjne_a_di_rel(cmdc) & (acc!=data0))|(cjne_a_da_rel(cmdc) & (acc!=cmd1))|(cjne_rn_da_rel(cmdc) & (data1!=cmd1))|(cjne_ri_da_rel(cmdc) & (data0!=cmd1))|((djnz_rn_rel(cmdb)||djnz_di_rel(cmdc)) & (data0!=8'h1)) ) 
    rom_addr = code_addr; 
else
    rom_addr = pc;


/*********************************************************/

/*********************************************************/
//command length

assign  length1 = add_a_rn(cmda)|addc_a_rn(cmda)|subb_a_rn(cmda)|inc_a(cmda)|inc_rn(cmda)|inc_dp(cmda)|dec_a(cmda)|dec_rn(cmda)|mul(cmda)|div(cmda)|da(cmda)|anl_a_rn(cmda)|orl_a_rn(cmda)|xrl_a_rn(cmda)|clr_a(cmda)|cpl_a(cmda)|rl(cmda)|rlc(cmda)|rr(cmda)|rrc(cmda)|swap(cmda)|mov_a_rn(cmda)|mov_rn_a(cmda)|mov_ri_a(cmda)|movx_a_dp(cmda)|movx_ri_a(cmda)|movx_dp_a(cmda)|xch_a_rn(cmda)|clr_c(cmda)|setb_c(cmda)|cpl_c(cmda)|jmp(cmda);

assign  length2r1 = add_a_ri(cmda)|addc_a_ri(cmda)|subb_a_ri(cmda)|inc_ri(cmda)|dec_ri(cmda)|anl_a_ri(cmda)|orl_a_ri(cmda)|xrl_a_ri(cmda)|mov_a_ri(cmda)|movc_a_dp(cmda)|movc_a_pc(cmda)|movx_a_ri(cmda)|xch_a_ri(cmda)|xchd(cmda);

assign  length2 = add_a_di(cmda)|add_a_da(cmda)|addc_a_di(cmda)|addc_a_da(cmda)|subb_a_di(cmda)|subb_a_da(cmda)|inc_di(cmda)|dec_di(cmda)|anl_a_di(cmda)|anl_a_da(cmda)|anl_di_a(cmda)|orl_a_di(cmda)|orl_a_da(cmda)|orl_di_a(cmda)|xrl_a_di(cmda)|xrl_a_da(cmda)|xrl_di_a(cmda)|mov_a_di(cmda)|mov_a_da(cmda)|mov_rn_di(cmda)|mov_rn_da(cmda)|mov_di_a(cmda)|mov_di_rn(cmda)|mov_di_ri(cmda)|mov_ri_di(cmda)|mov_ri_da(cmda)|push(cmda)|pop(cmda)|xch_a_di(cmda)|clr_bit(cmda)|setb_bit(cmda)|cpl_bit(cmda)|anl_c_bit(cmda)|anl_c_nbit(cmda)|orl_c_bit(cmda)|orl_c_nbit(cmda)|mov_c_bit(cmda)|mov_bit_c(cmda)|jc(cmda)|jnc(cmda)|ajmp(cmda)|sjmp(cmda)|jz(cmda)|jnz(cmda)|djnz_rn_rel(cmda);

assign  length3 = anl_di_da(cmda)|orl_di_da(cmda)|xrl_di_da(cmda)|mov_di_di(cmda)|mov_di_da(cmda)|mov_dp_da(cmda)|jb(cmda)|jnb(cmda)|jbc(cmda)|acall(cmda)|lcall(cmda)|ret(cmda)|reti(cmda)|ljmp(cmda)|cjne_a_di_rel(cmda)|cjne_a_da_rel(cmda)|cjne_rn_da_rel(cmda)|cjne_ri_da_rel(cmda)|djnz_di_rel(cmda);


/*********************************************************/


/*********************************************************/
//ram_rd_en ram_rd_addr 

assign rd_en_data_sfr = add_a_rn(cmda)|add_a_di(cmdb)|add_a_ri(cmda)|addc_a_rn(cmda)|addc_a_di(cmdb)|addc_a_ri(cmda)|subb_a_rn(cmda)|subb_a_di(cmdb)|subb_a_ri(cmda)|inc_rn(cmda)|inc_di(cmdb)|inc_ri(cmda)|dec_rn(cmda)|dec_di(cmdb)|dec_ri(cmda)|anl_a_rn(cmda)|anl_a_di(cmdb)|anl_a_ri(cmda)|anl_di_a(cmdb)|anl_di_da(cmdb)|orl_a_rn(cmda)|orl_a_di(cmdb)|orl_a_ri(cmda)|orl_di_a(cmdb)|orl_di_da(cmdb)|xrl_a_rn(cmda)|xrl_a_di(cmdb)|xrl_a_ri(cmda)|xrl_di_a(cmdb)|xrl_di_da(cmdb)|mov_a_rn(cmda)|mov_a_di(cmdb)|mov_a_ri(cmda)|mov_rn_di(cmdb)|mov_di_rn(cmda)|mov_di_di(cmdb)|mov_di_ri(cmda)|mov_ri_a(cmda)|mov_ri_di(cmda)|mov_ri_di(cmdb)|mov_ri_da(cmda)|movx_a_ri(cmda)|movx_ri_a(cmda)|push(cmdb)|xch_a_rn(cmda)|xch_a_di(cmdb)|xch_a_ri(cmda)|xchd(cmda)|clr_bit(cmdb)|setb_bit(cmdb)|cpl_bit(cmdb)|anl_c_bit(cmdb)|anl_c_nbit(cmdb)|orl_c_bit(cmdb)|orl_c_nbit(cmdb)|mov_c_bit(cmdb)|mov_bit_c(cmdb)|jb(cmdb)|jnb(cmdb)|jbc(cmdb)|cjne_a_di_rel(cmdb)|cjne_rn_da_rel(cmda)|cjne_ri_da_rel(cmda)|djnz_rn_rel(cmda)|djnz_di_rel(cmdb);

assign rd_en_data_idata = add_a_ri(cmdb)|addc_a_ri(cmdb)|subb_a_ri(cmdb)|inc_ri(cmdb)|dec_ri(cmdb)|anl_a_ri(cmdb)|orl_a_ri(cmdb)|xrl_a_ri(cmdb)|mov_a_ri(cmdb)|mov_di_ri(cmdb)|xch_a_ri(cmdb)|xchd(cmdb)|cjne_ri_da_rel(cmdb)|ret(cmda)|ret(cmdb)|reti(cmda)|reti(cmdb)|pop(cmda);

assign rd_en_xdata = movx_a_ri(cmdb)|movx_a_dp(cmda);

assign rd_en_data = (rd_en_data_sfr|rd_en_data_idata) & ~rd_addr[7];
`ifdef TYPE8052
assign rd_en_sfr = rd_en_data_sfr & rd_addr[7];
assign rd_en_idata = rd_en_data_idata & rd_addr[7];
`else
assign rd_en_sfr = (rd_en_data_sfr|rd_en_data_idata) & rd_addr[7];
`endif
assign same_flag_data = rd_en_data & wr_en_data & (rd_addr[7:0]==wr_addr[7:0]);
assign same_flag_sfr = rd_en_sfr & wr_en_sfr & (rd_addr[7:0]==wr_addr[7:0]);
`ifdef TYPE8052
assign same_flag_idata = rd_en_idata & wr_en_idata & (rd_addr[7:0]==wr_addr[7:0]);
`endif
assign same_flag_xdata = rd_en_xdata & wr_en_xdata & (rd_addr[15:0]==wr_addr[15:0]);
assign read_internal = rd_en_sfr & ( (rd_addr[7:0]==8'he0)|(rd_addr[7:0]==8'hd0)|(rd_addr[7:0]==8'h83)|(rd_addr[7:0]==8'h82)|(rd_addr[7:0]==8'h81)|(rd_addr[7:0]==8'hf0) );
assign ram_rd_en_data = work_en & rd_en_data & ~same_flag_data & ~wait_en;
assign ram_rd_en_sfr = work_en & rd_en_sfr & ~same_flag_sfr & ~read_internal & ~wait_en;
`ifdef TYPE8052
assign ram_rd_en_idata = work_en & rd_en_idata & ~same_flag_idata & ~wait_en;
`endif 
assign ram_rd_en_xdata = work_en & rd_en_xdata & ~same_flag_xdata & ~wait_en;


always @*
if ( add_a_rn(cmda)|addc_a_rn(cmda)|subb_a_rn(cmda)|inc_rn(cmda)|dec_rn(cmda)|anl_a_rn(cmda)|orl_a_rn(cmda)|xrl_a_rn(cmda)|mov_a_rn(cmda)|mov_di_rn(cmda)|xch_a_rn(cmda)|cjne_rn_da_rel(cmda)|djnz_rn_rel(cmda) )
    rd_addr = { psw_rs,cmd0[2:0] };
else if ( add_a_di(cmdb)|addc_a_di(cmdb)|subb_a_di(cmdb)|inc_di(cmdb)|dec_di(cmdb)|anl_a_di(cmdb)|anl_di_a(cmdb)|anl_di_da(cmdb)|orl_a_di(cmdb)|orl_di_a(cmdb)|orl_di_da(cmdb)|xrl_a_di(cmdb)|xrl_di_a(cmdb)|xrl_di_da(cmdb)|mov_a_di(cmdb)|mov_rn_di(cmdb)|mov_di_di(cmdb)|mov_ri_di(cmdb)|push(cmdb)|xch_a_di(cmdb)|cjne_a_di_rel(cmdb)|djnz_di_rel(cmdb) )
    rd_addr = cmd0;
else if ( add_a_ri(cmda)|addc_a_ri(cmda)|subb_a_ri(cmda)|inc_ri(cmda)|dec_ri(cmda)|anl_a_ri(cmda)|orl_a_ri(cmda)|xrl_a_ri(cmda)|mov_a_ri(cmda)|mov_di_ri(cmda)|mov_ri_a(cmda)|mov_ri_di(cmda)|mov_ri_da(cmda)|movx_a_ri(cmda)|movx_ri_a(cmda)|xch_a_ri(cmda)|xchd(cmda)|cjne_ri_da_rel(cmda) )
    rd_addr = { psw_rs,2'b0,cmd0[0] };
else if ( add_a_ri(cmdb)|addc_a_ri(cmdb)|subb_a_ri(cmdb)|inc_ri(cmdb)|dec_ri(cmdb)|anl_a_ri(cmdb)|orl_a_ri(cmdb)|xrl_a_ri(cmdb)|mov_a_ri(cmdb)|mov_di_ri(cmdb)|movx_a_ri(cmdb)|xch_a_ri(cmdb)|xchd(cmdb)|cjne_ri_da_rel(cmdb) )
    rd_addr = data0;
else if ( movx_a_dp(cmda) )
    rd_addr = dp;
else if ( pop(cmda)|ret(cmda)|reti(cmda) )
    rd_addr = sp;
else if ( clr_bit(cmdb)|setb_bit(cmdb)|cpl_bit(cmdb)|anl_c_bit(cmdb)|anl_c_nbit(cmdb)|orl_c_bit(cmdb)|orl_c_nbit(cmdb)|mov_c_bit(cmdb)|mov_bit_c(cmdb)|jb(cmdb)|jnb(cmdb)|jbc(cmdb) )
    rd_addr = cmd0[7] ? {cmd0[7:3],3'b0} : {3'b001,cmd0[7:3]};    
else if ( ret(cmdb)|reti(cmdb) )
    rd_addr = sp_sub1;	
else
    rd_addr = 16'd0;
	
assign ram_rd_addr = rd_addr;	

assign use_psw_rs = add_a_rn(cmda)|add_a_ri(cmda)|addc_a_rn(cmda)|addc_a_ri(cmda)|subb_a_rn(cmda)|subb_a_ri(cmda)|inc_rn(cmda)|inc_ri(cmda)|dec_rn(cmda)|dec_ri(cmda)|anl_a_rn(cmda)|anl_a_ri(cmda)|orl_a_rn(cmda)|orl_a_ri(cmda)|xrl_a_rn(cmda)|xrl_a_ri(cmda)|mov_a_rn(cmda)|mov_a_ri(cmda)|mov_di_rn(cmda)|mov_di_ri(cmda)|mov_ri_a(cmda)|mov_ri_di(cmda)|mov_ri_da(cmda)|movx_a_ri(cmda)|movx_ri_a(cmda)|xch_a_rn(cmda)|xch_a_ri(cmda)|xchd(cmda)|cjne_rn_da_rel(cmda)|cjne_ri_da_rel(cmda)|djnz_rn_rel(cmda);

assign use_dp = movc_a_dp(cmda)|movx_a_dp(cmda)|jmp(cmda);

assign use_acc = movc_a_dp(cmda)|movc_a_pc(cmda)|jmp(cmda);

assign use_sp = pop(cmda)|ret(cmda)|reti(cmda);

assign wait_en = (use_psw_rs&wr_psw_rs)|(use_dp&wr_dp)|(use_acc&wr_acc)|(use_sp&wr_sp);

/*********************************************************/

/*********************************************************/
//ram_wr_en ram_wr_addr  

assign wr_en_data_sfr = inc_rn(cmdb)|inc_di(cmdc)|dec_rn(cmdb)|dec_di(cmdc)|anl_di_a(cmdc)|anl_di_da(cmdc)|orl_di_a(cmdc)|orl_di_da(cmdc)|xrl_di_a(cmdc)|xrl_di_da(cmdc)|mov_rn_a(cmdb)|mov_rn_di(cmdc)|mov_rn_da(cmdb)|mov_di_a(cmdb)|mov_di_rn(cmdb)|mov_di_di(cmdc)|mov_di_ri(cmdc)|mov_di_da(cmdc)|pop(cmdb)|xch_a_rn(cmdb)|xch_a_di(cmdc)|clr_bit(cmdc)|setb_bit(cmdc)|cpl_bit(cmdc)|mov_bit_c(cmdc)|(jbc(cmdc)&data0[cmd1[2:0]])|djnz_rn_rel(cmdb)|djnz_di_rel(cmdc);

assign wr_en_data_idata = inc_ri(cmdc)|dec_ri(cmdc)|mov_ri_a(cmdb)|mov_ri_di(cmdc)|mov_ri_da(cmdb)|xch_a_ri(cmdc)|xchd(cmdc)|acall(cmdb)|acall(cmdc)|lcall(cmdb)|lcall(cmdc)|push(cmdc);

assign wr_en_xdata = movx_ri_a(cmdb)|movx_dp_a(cmdb);

assign wr_en_data = (wr_en_data_sfr|wr_en_data_idata) & ~wr_addr[7];
`ifdef TYPE8052
assign wr_en_sfr = wr_en_data_sfr & wr_addr[7];
assign wr_en_idata = wr_en_data_idata & wr_addr[7];
`else
assign wr_en_sfr = (wr_en_data_sfr|wr_en_data_idata) & wr_addr[7];
`endif
assign write_internal = wr_en_sfr & ( (wr_addr[7:0]==8'he0)|(wr_addr[7:0]==8'hd0)|(wr_addr[7:0]==8'h83)|(wr_addr[7:0]==8'h82)|(wr_addr[7:0]==8'h81)|(wr_addr[7:0]==8'hf0) );
assign ram_wr_en_data = work_en & wr_en_data;
assign ram_wr_en_sfr = work_en & wr_en_sfr & ~write_internal;
`ifdef TYPE8052
assign ram_wr_en_idata = work_en & wr_en_idata;
`endif
assign ram_wr_en_xdata = work_en & wr_en_xdata;

always @*
if ( inc_rn(cmdb)|dec_rn(cmdb)|mov_rn_a(cmdb)|mov_rn_da(cmdb)|xch_a_rn(cmdb)|djnz_rn_rel(cmdb) )
    wr_addr = { psw_rs,cmd1[2:0] };
else if ( inc_di(cmdc)|dec_di(cmdc)|anl_di_a(cmdc)|anl_di_da(cmdc)|orl_di_a(cmdc)|orl_di_da(cmdc)|xrl_di_a(cmdc)|xrl_di_da(cmdc)|mov_di_ri(cmdc)|mov_di_da(cmdc)|xch_a_di(cmdc)|djnz_di_rel(cmdc) )
    wr_addr = cmd1;
else if ( inc_ri(cmdc)|dec_ri(cmdc)|mov_ri_di(cmdc)|xch_a_ri(cmdc)|xchd(cmdc) )
    wr_addr = data1;
else if ( mov_rn_di(cmdc) )
    wr_addr = { psw_rs,cmd2[2:0] };
else if ( mov_di_a(cmdb)|mov_di_rn(cmdb)|mov_di_di(cmdc)|pop(cmdb) )
    wr_addr = cmd0;
else if ( mov_ri_a(cmdb)|mov_ri_da(cmdb)|movx_ri_a(cmdb) )
    wr_addr = data0;
else if ( movx_dp_a(cmdb) )
    wr_addr = dp;
else if ( push(cmdc) )
    wr_addr = sp;
else if ( clr_bit(cmdc)|setb_bit(cmdc)|cpl_bit(cmdc)|mov_bit_c(cmdc)|jbc(cmdc) )
    wr_addr = cmd1[7] ? {cmd1[7:3],3'b0} : {3'b001,cmd1[7:3]};
else if ( acall(cmdb)|acall(cmdc)|lcall(cmdb)|lcall(cmdc) )
    wr_addr = sp_add1;	
else
    wr_addr = 16'd0;

assign ram_wr_addr = wr_addr;	

/*********************************************************/


/*********************************************************/
//ram_wr_byte

always @* begin
wr_bit_byte = data0;
if ( clr_bit(cmdc)|jbc(cmdc) )
    wr_bit_byte[cmd1[2:0]] = 1'b0;
else if ( setb_bit(cmdc) )
    wr_bit_byte[cmd1[2:0]] = 1'b1;
else if ( cpl_bit(cmdc)	)
    wr_bit_byte[cmd1[2:0]] = ~wr_bit_byte[cmd1[2:0]];
else if ( mov_bit_c(cmdc) )	
    wr_bit_byte[cmd1[2:0]] = psw_c;
else;
end

always @*
if ( inc_rn(cmdb)|inc_di(cmdc)|inc_ri(cmdc)|dec_rn(cmdb)|dec_di(cmdc)|dec_ri(cmdc)|djnz_rn_rel(cmdb)|djnz_di_rel(cmdc) )
    wr_byte = add_byte;
else if ( anl_di_a(cmdc)|anl_di_da(cmdc) )
    wr_byte = and_out;
else if ( orl_di_a(cmdc)|orl_di_da(cmdc) )
    wr_byte = or_out;
else if ( xrl_di_a(cmdc)|xrl_di_da(cmdc) )
    wr_byte = xor_out;
else if ( mov_rn_a(cmdb)|mov_di_a(cmdb)|mov_ri_a(cmdb)|movx_ri_a(cmdb)|movx_dp_a(cmdb)|xch_a_rn(cmdb)|xch_a_di(cmdc)|xch_a_ri(cmdc) )
    wr_byte = acc;
else if ( mov_rn_di(cmdc)|mov_di_rn(cmdb)|mov_di_di(cmdc)|mov_di_ri(cmdc)|mov_ri_di(cmdc)|push(cmdc)|pop(cmdb) )
    wr_byte = data0;
else if ( mov_rn_da(cmdb)|mov_di_da(cmdc)|mov_ri_da(cmdb) )
    wr_byte = cmd0;
else if ( xchd(cmdc) )
    wr_byte = {data0[7:4],acc[3:0]};
else if ( clr_bit(cmdc)|setb_bit(cmdc)|cpl_bit(cmdc)|mov_bit_c(cmdc)|jbc(cmdc) )
    wr_byte = wr_bit_byte;
else if ( acall(cmdb) )
    wr_byte = pc[7:0];
else if ( acall(cmdc)|lcall(cmdc) )
    wr_byte = pc[15:8];	
else if ( lcall(cmdb) )
    wr_byte = pc_add1[7:0];
else
    wr_byte = 8'd0;

assign ram_wr_byte = wr_byte;

/*********************************************************/


/*********************************************************/
//acc register

always @*
if ( add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb)|inc_a(cmdb)|dec_a(cmdb) )
    add_a = acc;
else if ( inc_rn(cmdb)|inc_di(cmdc)|inc_ri(cmdc)|dec_rn(cmdb)|dec_di(cmdc)|dec_ri(cmdc)|djnz_rn_rel(cmdb)|djnz_di_rel(cmdc) )
    add_a = data0;
else
    add_a = 8'b0;


always @*
if ( add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc) )
    add_b = data0;
else if ( add_a_da(cmdb)|addc_a_da(cmdb)|subb_a_da(cmdb) )
    add_b = cmd0;
else if ( inc_a(cmdb)|dec_a(cmdb)|inc_rn(cmdb)|inc_di(cmdc)|inc_ri(cmdc)|dec_rn(cmdb)|dec_di(cmdc)|dec_ri(cmdc)|djnz_rn_rel(cmdb)|djnz_di_rel(cmdc) )
    add_b = 8'b0;
else
    add_b = 8'b0;


always @*
if ( add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb) )
    add_c = 1'b0;
else if ( addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb) )
    add_c = psw_c;
else if ( inc_a(cmdb)|inc_rn(cmdb)|inc_di(cmdc)|inc_ri(cmdc)|dec_a(cmdb)|dec_rn(cmdb)|dec_di(cmdc)|dec_ri(cmdc)|djnz_rn_rel(cmdb)|djnz_di_rel(cmdc) )
    add_c = 1'b1;	
else
    add_c = 1'b0;	


always @*
if ( add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|inc_a(cmdb)|inc_rn(cmdb)|inc_di(cmdc)|inc_ri(cmdc) )
    sub_flag = 1'b0;
else if ( subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb)|dec_a(cmdb)|dec_rn(cmdb)|dec_di(cmdc)|dec_ri(cmdc)|djnz_rn_rel(cmdb)|djnz_di_rel(cmdc) )
    sub_flag = 1'b1;
else
    sub_flag = 1'b0;


assign {bit_ac,low} = sub_flag ? (add_a[3:0]-add_b[3:0]-add_c) : (add_a[3:0]+add_b[3:0]+add_c);
assign high = sub_flag ? (add_a[6:4]-add_b[6:4]-bit_ac) : (add_a[6:4]+add_b[6:4]+bit_ac);
assign {bit_c,bit_high} = sub_flag ? (add_a[7]-add_b[7]-high[3]) : (add_a[7]+add_b[7]+high[3]);
assign bit_ov = bit_c ^ high[3];
assign add_byte = {bit_high,high[2:0],low};

assign mult = acc * b;
assign {div_rem,div_ans} = divide(acc,b);
assign and_out = ( anl_di_da(cmdc) ? cmd0 : acc ) & ( anl_a_da(cmdb) ? cmd0 : data0 );
assign or_out  = ( orl_di_da(cmdc) ? cmd0 : acc ) | ( orl_a_da(cmdb) ? cmd0 : data0 );
assign xor_out = ( xrl_di_da(cmdc) ? cmd0 : acc ) ^ ( xrl_a_da(cmdb) ? cmd0 : data0 );

wire [3:0] da_low  = ( psw_ac|(acc[3:0]>4'h9) ) ? (acc[3:0]+4'd6) : acc[3:0];
wire [3:0] da_high = ( ( psw_c|(acc[7:4]>4'h9)|((acc[7:4]==4'h9)&(psw_ac|(acc[3:0]>4'h9))) ) ? ( acc[7:4]+4'h6 ) : acc[7:4] ) + ( psw_ac|(acc[3:0]>4'h9) );
	
always @ ( posedge clk or posedge rst )
if ( rst )
    acc <= 8'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'he0 ) )
	    acc <= wr_byte;
	else if ( add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb)|inc_a(cmdb)|dec_a(cmdb) )
	    acc <= add_byte;
	else if ( mul(cmdb) )
	    acc <= mult[7:0];
	else if ( div(cmdb) )
	    acc <= div_ans;
	else if ( da(cmdb) )
	    acc <= {da_high,da_low};	
    else if ( anl_a_rn(cmdb)|anl_a_di(cmdc)|anl_a_ri(cmdc)|anl_a_da(cmdb) )
        acc <= and_out;	
	else if ( orl_a_rn(cmdb)|orl_a_di(cmdc)|orl_a_ri(cmdc)|orl_a_da(cmdb) )
	    acc <= or_out;
	else if ( xrl_a_rn(cmdb)|xrl_a_di(cmdc)|xrl_a_ri(cmdc)|xrl_a_da(cmdb) )
	    acc <= xor_out;
	else if ( clr_a(cmdb) )
	    acc <= 8'b0;
	else if ( cpl_a(cmdb) )
	    acc <= ~acc;
	else if ( rl(cmdb) )
	    acc <= {acc[6:0],acc[7]};
	else if ( rlc(cmdb) )
	    acc <= {acc[6:0],psw_c};	
	else if ( rr(cmdb) )
	    acc <= {acc[0],acc[7:1]};	
	else if ( rrc(cmdb) )
	    acc <= {psw_c,acc[7:1]};	
	else if ( swap(cmdb) )
	    acc <= {acc[3:0],acc[7:4]};	
    else if ( mov_a_rn(cmdb)|mov_a_di(cmdc)|mov_a_ri(cmdc)|movx_a_ri(cmdc)|movx_a_dp(cmdb)|xch_a_rn(cmdb)|xch_a_di(cmdc)|xch_a_ri(cmdc) )
        acc <= data0;	
	else if ( mov_a_da(cmdb)|movc_a_dp(cmdb)|movc_a_pc(cmdb) )
	    acc <= cmd0;
	else if ( xchd(cmdc) )
	    acc[3:0] <= data0[3:0];
	else;
else;

assign wr_acc = (wr_en_sfr & (wr_addr[7:0]==8'he0))|add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb)|inc_a(cmdb)|dec_a(cmdb)|mul(cmdb)|div(cmdb)|da(cmdb)|anl_a_rn(cmdb)|anl_a_di(cmdc)|anl_a_ri(cmdc)|anl_a_da(cmdb)|orl_a_rn(cmdb)|orl_a_di(cmdc)|orl_a_ri(cmdc)|orl_a_da(cmdb)|xrl_a_rn(cmdb)|xrl_a_di(cmdc)|xrl_a_ri(cmdc)|xrl_a_da(cmdb)|clr_a(cmdb)|cpl_a(cmdb)|rl(cmdb)|rlc(cmdb)|rr(cmdb)|rrc(cmdb)|swap(cmdb)|mov_a_rn(cmdb)|mov_a_di(cmdc)|mov_a_ri(cmdc)|mov_a_da(cmdb)|movx_a_ri(cmdc)|movx_a_dp(cmdb)|xch_a_rn(cmdb)|xch_a_di(cmdc)|xch_a_ri(cmdc)|xchd(cmdc);

/*********************************************************/


/*********************************************************/
//psw register

assign psw_p = ^acc;

always @ ( posedge clk or posedge rst )
if ( rst )
    psw_ov <= 1'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'hd0 ) )
	    psw_ov <= wr_byte[2];
	else if ( add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb) )
	    psw_ov <= bit_ov;
	else if ( mul(cmdb) )
	    psw_ov <= (mult[15:8]!=8'b0);
	else if ( div(cmdb) )
	    psw_ov <= (b==8'b0);
	else;
else;

always @ ( posedge clk or posedge rst )
if ( rst )
    psw_ac <= 1'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'hd0 ) )
	    psw_ac <= wr_byte[6];
	else if ( add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb) )
	    psw_ac <= bit_ac;
	else;
else;

always @ ( posedge clk or posedge rst )
if ( rst )
    psw_c <= 1'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'hd0 ) )
	    psw_c <= wr_byte[7];
	else if ( add_a_rn(cmdb)|add_a_di(cmdc)|add_a_ri(cmdc)|add_a_da(cmdb)|addc_a_rn(cmdb)|addc_a_di(cmdc)|addc_a_ri(cmdc)|addc_a_da(cmdb)|subb_a_rn(cmdb)|subb_a_di(cmdc)|subb_a_ri(cmdc)|subb_a_da(cmdb) )
	    psw_c <= bit_c;
	else if ( mul(cmdb)|div(cmdb) )
	    psw_c <= 1'b0;
	else if ( da(cmdb) )
	    psw_c <= ( psw_c|(acc[7:4]>4'h9)|((acc[7:4]==4'h9)&(psw_ac|(acc[3:0]>4'h9))) ) ? 1'b1 : psw_c;
	else if ( rlc(cmdb) )
	    psw_c <= acc[7];	
	else if ( rrc(cmdb) )
	    psw_c <= acc[0];	
    else if ( clr_c(cmdb) )
        psw_c <= 1'b0;	
	else if ( setb_c(cmdb) )
        psw_c <= 1'b1;	
	else if ( cpl_c(cmdb) )
        psw_c <= ~psw_c;	
	else if ( anl_c_bit(cmdc) )
        psw_c <= psw_c & data0[cmd1[2:0]];	
	else if ( anl_c_nbit(cmdc) )
        psw_c <= psw_c & ~data0[cmd1[2:0]];
	else if ( orl_c_bit(cmdc) )
        psw_c <= psw_c | data0[cmd1[2:0]];	
	else if ( orl_c_nbit(cmdc) )
        psw_c <= psw_c | ~data0[cmd1[2:0]];	
	else if ( mov_c_bit(cmdc) )
        psw_c <=data0[cmd1[2:0]];
	else if ( cjne_a_di_rel(cmdc) )
        psw_c <= acc<data0;
    else if ( cjne_a_da_rel(cmdc) )
        psw_c <= acc<cmd1;
	else if ( cjne_rn_da_rel(cmdc) )
        psw_c <= data1<cmd1;	
	else if ( cjne_ri_da_rel(cmdc) )
	    psw_c <= data0<cmd1;
	else;
else;

always @ ( posedge clk or posedge rst )
if ( rst )
    psw_other <= 4'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'hd0 ) )
	    psw_other <= {wr_byte[5:3],wr_byte[1]};
	else;
else;

assign psw_rs = psw_other[2:1];

assign wr_psw_rs = wr_en_sfr & (wr_addr[7:0]==8'hd0);

assign psw = {psw_c,psw_ac,psw_other[3:1],psw_ov,psw_other[0],psw_p};

/*********************************************************/

/*********************************************************/
//dp  sp registers

always @ ( posedge clk or posedge rst )
if ( rst )
    dp <= 16'b0;
else if ( work_en )
    if  ( wr_en_sfr & (wr_addr[7:0]==8'h82 ) )
	    dp[7:0] <= wr_byte;
	else if  ( wr_en_sfr & (wr_addr[7:0]==8'h83 ) )
	    dp[15:8] <= wr_byte;
	else if ( inc_dp(cmdb) )
	    dp <= dp + 1'b1;
	else if ( mov_dp_da(cmdc) )
	    dp <= {cmd1,cmd0};
	else;
else;

assign wr_dp = (wr_en_sfr & ((wr_addr[7:0]==8'h82)|(wr_addr[7:0]==8'h83)))|inc_dp(cmdb);

always @ ( posedge clk or posedge rst )
if ( rst )
    sp <= 8'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'h81) )
	    sp <= wr_byte;
	else if ( push(cmdb)|acall(cmdb)|acall(cmdc)|lcall(cmdb)|lcall(cmdc) )
	    sp <= sp_add1;
    else if ( pop(cmdb)|ret(cmdb)|ret(cmdc)|reti(cmdb)|reti(cmdc) )
        sp <= sp_sub1;	
	else;
else;

assign sp_sub1 = sp - 1'b1;

assign sp_add1 = sp + 1'b1;

assign wr_sp = (wr_en_sfr & (wr_addr[7:0]==8'h81));

always @ ( posedge clk or posedge rst )
if ( rst )
    b <= 8'b0;
else if ( work_en )
    if ( wr_en_sfr & (wr_addr[7:0]==8'hf0) )
	    b <= wr_byte;
	else if ( mul(cmdb) )
	    b <= mult[15:8];
	else if ( div(cmdb) )
	    b <= div_rem;
	else;
else;

/*********************************************************/


/*********************************************************/
//ram output

always @*
if ( same_flag )
    data0 = same_byte;
else if ( same_byte[7] )
    data0 = acc;
else if ( same_byte[6] )
    data0 = psw;
else if ( same_byte[5] )
    data0 = dp[15:8];
else if ( same_byte[4] )
    data0 = dp[7:0];
else if ( same_byte[3] )
    data0 = sp;
else if ( same_byte[2] )
    data0 = b;
else
    data0 = ram_rd_byte;

always @ ( posedge clk or posedge rst )
if ( rst )
    data1 <= 8'b0;
else if ( work_en )
    data1 <= data0;
else;
    
always @ ( posedge clk or posedge rst )
if ( rst )
    same_flag <= 1'b0;
else if ( work_en )
`ifdef TYPE8052
    if ( same_flag_data|same_flag_sfr|same_flag_idata|same_flag_xdata )
`else 
    if ( same_flag_data|same_flag_sfr|same_flag_xdata )
`endif	
	    same_flag <= 1'b1;
	else
	    same_flag <= 1'b0;
else;

always @ ( posedge clk or posedge rst )
if ( rst )
    same_byte <= 8'd0;
else if ( work_en )
`ifdef TYPE8052
    if ( same_flag_data|same_flag_sfr|same_flag_idata|same_flag_xdata )
`else
    if ( same_flag_data|same_flag_sfr|same_flag_xdata )
`endif	
	    same_byte <= wr_byte;
	else if ( rd_en_sfr & (rd_addr[7:0]==8'he0) ) //acc
	    same_byte <= 1'b1<<7;
	else if ( rd_en_sfr & (rd_addr[7:0]==8'hd0) ) //psw
	    same_byte <= 1'b1<<6;
	else if ( rd_en_sfr & (rd_addr[7:0]==8'h83) ) //dph
	    same_byte <= 1'b1<<5;	
	else if ( rd_en_sfr & (rd_addr[7:0]==8'h82) ) //dpl
	    same_byte <= 1'b1<<4;	
	else if ( rd_en_sfr & (rd_addr[7:0]==8'h81) ) //sp
	    same_byte <= 1'b1<<3;
	else if ( rd_en_sfr & (rd_addr[7:0]==8'hf0) ) //b
	    same_byte <= 1'b1<<2;		
	else
	    same_byte <= 8'b0;
else;
	
/*********************************************************/

endmodule


http://www.kler.cn/a/504806.html

相关文章:

  • 微信小程序原生与 H5 交互方式
  • 【Sql递归查询】Mysql、Oracle、SQL Server、PostgreSQL 实现递归查询的区别与案例(详解)
  • 开发指南091-延迟退休算法
  • 【AIGC-ChatGPT进阶提示词指令】智慧母婴:打造基于成长树的儿童发展引导系统
  • Vue 3前端与Python(Django)后端接口简单示例
  • 使用WebdriverIO和Appium测试App
  • 大数据学习(35)- spark- action算子
  • 六种主流虚拟化技术全解析:OpenStack、KVM、Hyper-V、VMware、Xen及Docker
  • 网络安全 | 定期安全审计与漏洞扫描:企业网络健康检查
  • Java爬虫中,怎样设置请求重试次数?
  • jupyter notebook练手项目:线性回归——学习时间与成绩的关系
  • 有哪些基于web的3d设计软件
  • 【C语言】_字符串拷贝函数strcpy
  • BERT的中文问答系统62
  • postgresql分区表相关问题处理
  • Ansys Material Designer 简介
  • 【Leetcode 热题 100】739. 每日温度
  • 学习华为熵减:激发组织活力(系列之三)
  • Mac 删除ABC 输入法
  • candb++ windows11运行报错,找不到mfc140.dll
  • vscode离线安装插件--终极解决方案
  • 批量为视频生成字幕
  • 测试模型安全的手段
  • 突破跨境电商瓶颈:亚矩阵云手机应用全解析
  • RabbitMQ---消息确认和持久化
  • lanqiaoOJ 3333:肖恩的排序 ← 双指针+排序(从大到小)