📄 ac51_serial.v
字号:
//// ac51_serial.v//// ac51 microcontroller core//// Version 0.6//// Copyright 2008, Hideyuki Abe. All rights reserved.// Distributed under the terms of the MIT License.//module ac51_serial( clk, rst, ioaddr, iowdata, iordata, iowen, sck1, sck2, rclk, tclk, smod, rxd_i, rxd_o, txd, sint_req);input clk;input rst;input [6:0] ioaddr;input [7:0] iowdata;output [7:0] iordata;input iowen;input sck1;input sck2;input rclk;input tclk;input smod;input rxd_i;output rxd_o;output txd;output sint_req;reg [6:0] ioaddr_d;wire scon_enb;wire sbuf_enb;wire scon_wen;wire sbuf_wen;wire [7:0] scon;reg [7:0] sbuf;// smode[0] : SM2, smode[1] : SM1, smode[2] : SM0reg [2:0] smode;reg ren;reg tb8;reg rb8;reg ti;reg ri;reg ri_set;reg [8:0] tbuf;reg [8:0] rbuf;reg half_clk;reg sck1_i;reg sck1_en;reg spresc_upd;reg rpresc_upd;reg [5:0] snd_presc;reg [5:0] rcv_presc;reg [5:0] presc_rld;reg sending;reg receiving;reg snd_start;reg snd_stop;reg [7:0] rxd_seq;reg rcv_start;reg rcv_stop;reg [3:0] snd_cnt;reg [3:0] rcv_cnt;wire snd_cnt_upd;wire rcv_cnt_upd;reg snd_shift;reg rcv_shift;reg [1:0] rxd_one_cnt;reg rxd_f;wire rxd_rdy;reg rxd_o;reg txd;always @(posedge clk or negedge rst) begin if(~rst) ioaddr_d <= 7'h00; else ioaddr_d <= ioaddr;end // alwaysassign scon_enb = (ioaddr_d == 7'h18); // SCON @8'h98assign sbuf_enb = (ioaddr_d == 7'h19); // SBUF @8'h99assign scon = {smode, ren, tb8, rb8, ti, ri};always @(posedge clk or negedge rst) begin if(~rst) sbuf = 8'h00; else if(ri_set) sbuf = rbuf[7:0];end // alwaysassign iordata = ({8{scon_enb}} & scon) | ({8{sbuf_enb}} & sbuf);assign scon_wen = ((ioaddr == 7'h18) & iowen); // SCON @8'h98assign sbuf_wen = ((ioaddr == 7'h19) & iowen); // SBUF @8'h99always @(posedge clk or negedge rst) begin if(~rst) begin smode <= 3'b000; ren <= 1'b0; tb8 <= 1'b0; end else if(scon_wen) begin smode <= iowdata[7:5]; ren <= iowdata[4]; tb8 <= iowdata[3]; endend // alwaysalways @(posedge clk or negedge rst) begin if(~rst) rb8 <= 1'b0; else if(ri_set) rb8 <= rbuf[8];/* controlled by hardware */// else if(scon_wen)// rb8 <= iowdata[2];end // alwaysalways @(posedge clk or negedge rst) begin if(~rst) ti <= 1'b0; else if(snd_stop) ti <= 1'b1; else if(scon_wen)// ti <= ti & iowdata[1]; // clear ti <= iowdata[1]; // set & clearend // alwaysalways @(posedge clk or negedge rst) begin if(~rst) ri <= 1'b0; else if(ri_set) ri <= 1'b1; else if(scon_wen)// ri <= ri & iowdata[0]; // clear ri <= iowdata[0]; // set & clearend // alwaysalways @(smode or rcv_stop or rbuf) begin case(smode[2:1]) 2'b00: // mode0 ri_set = rcv_stop; 2'b01, // mode1 2'b10, // mode2 2'b11: // mode3 if(smode[0]) // if SM2 = 1 ri_set = rcv_stop & rbuf[8]; else ri_set = rcv_stop; endcaseend // always combassign sint_req = ti | ri;// prescaleralways @(posedge clk or negedge rst) begin if(~rst) snd_presc <= 6'h00; else if(sending) begin if(spresc_upd) begin if(snd_presc == 6'h00) snd_presc <= presc_rld; else snd_presc <= snd_presc - 6'h01; end end else snd_presc <= presc_rld;end // alwaysalways @(posedge clk or negedge rst) begin if(~rst) rcv_presc <= 6'h00; else if(receiving) begin if(rpresc_upd) begin if(rcv_presc == 6'h00) rcv_presc <= presc_rld; else rcv_presc <= rcv_presc - 6'h01; end end else rcv_presc <= presc_rld;end // alwaysalways @( smode or smod or sck1_i or sck1_en or sck2 or tclk) begin case(smode[2:1]) 2'b00: // mode0 spresc_upd = sck1_i; 2'b10: // mode2 if(smod) spresc_upd = sck1_i; else spresc_upd = sck1_i & sck1_en; 2'b01, // mode1 2'b11: // mode3 if(tclk) spresc_upd = sck2; else if(smod) spresc_upd = sck1_i; else spresc_upd = sck1_i & sck1_en; endcaseend // always combalways @( smode or smod or sck1_i or sck1_en or sck2 or rclk) begin case(smode[2:1]) 2'b00: // mode0 rpresc_upd = sck1_i; 2'b10: // mode2 if(smod) rpresc_upd = sck1_i; else rpresc_upd = sck1_i & sck1_en; 2'b01, // mode1 2'b11: // mode3 if(rclk) rpresc_upd = sck2; else if(smod) rpresc_upd = sck1_i; else rpresc_upd = sck1_i & sck1_en; endcaseend // always combalways @(posedge clk or negedge rst) begin if(~rst) half_clk <= 1'b0; else half_clk <= ~half_clk;end // alwaysalways @(smode or sck1 or half_clk or smod) begin case(smode[2:1]) 2'b00: // mode0 sck1_i = 1'b1; // count every cycle 2'b01: // mode1 sck1_i = sck1; // count when tmr1 overflow 2'b10: // mode2 sck1_i = half_clk; // count every other cycle 2'b11: // mode3 sck1_i = sck1; // count when tmr1 overflow endcaseend // always combalways @(posedge clk or negedge rst) begin if(~rst) sck1_en <= 1'b0; else if(sck1_i) sck1_en <= ~sck1_en;end // alwaysalways @(smode or smod) begin presc_rld = 6'h00; case(smode[2:1]) 2'b00: // mode0 presc_rld = 6'd11; 2'b01, // mode1 2'b10, // mode2 2'b11: // mode3 presc_rld = 6'd15; endcaseend // always combalways @(posedge clk or negedge rst) begin if(~rst) sending <= 1'b0; else if(snd_start) sending <= 1'b1; else if(snd_stop) sending <= 1'b0;end // alwaysalways @(sbuf_wen) begin snd_start = sbuf_wen;end // always combalways @(smode or snd_cnt or snd_cnt_upd) begin snd_stop = 1'b0; case(smode[2:1]) 2'b00: // mode0 snd_stop = ((snd_cnt == 4'h8) & snd_cnt_upd); 2'b01: // mode1 snd_stop = ((snd_cnt == 4'h9) & snd_cnt_upd); 2'b10, // mode2 2'b11: // mode3 snd_stop = ((snd_cnt == 4'ha) & snd_cnt_upd); endcaseend // always combalways @(posedge clk or negedge rst) begin if(~rst) receiving <= 1'b0; else if(rcv_start) receiving <= 1'b1; else if(rcv_stop) receiving <= 1'b0;end // always// detect falling edge of rxdalways @(posedge clk or negedge rst) begin if(~rst) rxd_seq <= 8'hff; else rxd_seq <= {rxd_seq[6:0], rxd_i};end // always//always @(smode or ren or ri or receiving or rxd_seq) beginalways @(smode or ren or ri or receiving or rcv_stop or rxd_seq) begin rcv_start = 1'b0; case(smode[2:1]) 2'b00: // mode0 rcv_start = ren & ~ri & ~receiving; 2'b01, // mode1 2'b10, // mode2 2'b11: // mode3 rcv_start = ren & (rxd_seq == 8'h80) & (~receiving | rcv_stop); endcaseend // always combalways @(smode or rcv_cnt or rcv_cnt_upd or rxd_rdy or rxd_f) begin rcv_stop = 1'b0; case(smode[2:1]) 2'b00: // mode0 rcv_stop = ((rcv_cnt == 4'h8) & rcv_cnt_upd); 2'b01: // mode1 rcv_stop = ((rcv_cnt == 4'h0) & rxd_rdy & rxd_f) // spurious start bit | ((rcv_cnt == 4'h9) & rcv_cnt_upd); 2'b10, // mode2 2'b11: // mode3 rcv_stop = ((rcv_cnt == 4'h0) & rxd_rdy & rxd_f) // spurious start bit | ((rcv_cnt == 4'ha) & rcv_cnt_upd); endcaseend // always combalways @(posedge clk or negedge rst) begin if(~rst) snd_cnt <= 4'h0; else if(snd_stop) snd_cnt <= 4'h0; else if(snd_cnt_upd) snd_cnt <= snd_cnt + 4'h1;end // alwaysassign snd_cnt_upd = sending & (snd_presc == 6'd0) & spresc_upd;always @(smode or snd_cnt_upd or snd_cnt) begin snd_shift = 1'b0; case(smode[2:1]) 2'b00: // mode0 snd_shift = snd_cnt_upd; 2'b01: // mode1 snd_shift = snd_cnt_upd & ((snd_cnt >= 4'h1) & (snd_cnt < 4'h8)); 2'b10, // mode2 2'b11: // mode3 snd_shift = snd_cnt_upd & ((snd_cnt >= 4'h1) & (snd_cnt < 4'h9)); endcaseend // always combalways @(posedge clk or negedge rst) begin if(~rst) rcv_cnt <= 4'h0; else if(rcv_stop) rcv_cnt <= 4'h0; else if(rcv_cnt_upd) rcv_cnt <= rcv_cnt + 4'h1;end // alwaysassign rcv_cnt_upd = receiving & (rcv_presc == 6'd0) & rpresc_upd;always @(smode or rxd_rdy or rcv_cnt) begin rcv_shift = 1'b0; case(smode[2:1]) 2'b00: // mode0 rcv_shift = rxd_rdy; 2'b01, // mode1 2'b10, // mode2 2'b11: // mode3 rcv_shift = rxd_rdy & ((rcv_cnt >= 4'h1) & (rcv_cnt < 4'ha)); endcaseend // always combalways @(posedge clk or negedge rst) begin if(~rst) tbuf <= 9'h000; else if(sbuf_wen) tbuf <= {tb8, iowdata}; else if(snd_shift) tbuf <= {1'b0, tbuf[8:1]};end // alwaysalways @(posedge clk or negedge rst) begin if(~rst) rbuf <= 9'h000; else if(rcv_shift) begin if(smode[2:1] == 2'b00) // mode0 rbuf <= {rxd_i, rbuf[8:1]}; else rbuf <= {rxd_f, rbuf[8:1]}; endend // always// rxd noise rejectionalways @(posedge clk or negedge rst) begin if(~rst) begin rxd_one_cnt <= 2'b00; end else if(receiving & rpresc_upd) begin if(rcv_presc == 6'd10) begin rxd_one_cnt <= 2'b00; end else if(rcv_presc == 6'd9 | rcv_presc == 6'd8 | rcv_presc == 6'd7) begin if(rxd_i) rxd_one_cnt <= rxd_one_cnt + 2'b01; end endend // alwaysalways @(posedge clk or negedge rst) begin if(~rst) begin rxd_f <= 1'b1; end else if(receiving & rpresc_upd) begin if(rcv_presc == 6'd6) rxd_f <= rxd_one_cnt[1]; endend // alwaysassign rxd_rdy = receiving & (rcv_presc == 6'd2) & rpresc_upd;always @(smode or sending or tbuf) begin rxd_o = 1'b1; case(smode[2:1]) 2'b00: // mode0 if(sending) rxd_o = tbuf[0]; endcaseend // always combalways @( smode or sending or snd_presc or receiving or rcv_presc or snd_cnt or sending or tbuf) begin txd = 1'b1; case(smode[2:1]) 2'b00: // mode0 if(sending) begin if((snd_presc < 6'd8) & (snd_presc >= 6'd2)) txd = 1'b0; end else if(receiving) begin if((rcv_presc < 6'd8) & (rcv_presc >= 6'd2)) txd = 1'b0; end 2'b01: // mode1 if(sending) begin if(snd_cnt == 4'h0) txd = 1'b0; // start bit else if(snd_cnt == 4'h9) txd = 1'b1; // stop bit else txd = tbuf[0]; end 2'b10, // mode2 2'b11: // mode3 if(sending) begin if(snd_cnt == 4'h0) txd = 1'b0; // start bit else if(snd_cnt == 4'ha) txd = 1'b1; // stop bit else txd = tbuf[0]; end endcaseend // always combendmodule// End of ac51_serial.v
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -