[读书日志]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;
算术操作指令只有单字节和双字节,没有三字节。
单字节指令分为length1
和length2r1
,length2r1
表示它虽然是单字节指令,但要当成两字节处理,但指令存储区没有存放单字节的第二虚拟字节,在处理器读到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_dp
和movc_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