URL
https://opencores.org/ocsvn/via6522/via6522/trunk
Subversion Repositories via6522
[/] [via6522/] [trunk/] [rtl/] [via6522_x12.sv] - Rev 2
Compare with Previous | Blame | View Log
// ============================================================================// __// \\__/ o\ (C) 2004-2022 Robert Finch, Waterloo// \ __ / All rights reserved.// \/_// robfinch<remove>@finitron.ca// ||//// via6522_x12.sv//// This source file is free software: you can redistribute it and/or modify// it under the terms of the GNU Lesser General Public License as published// by the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// This source file is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program. If not, see <http://www.gnu.org/licenses/>.//// ============================================================================`define PB 5'd0`define PA 5'd1`define DDRB 5'd2`define DDRA 5'd3`define T1CL 5'd4`define T1CH 5'd5`define T1LL 5'd6`define T1LH 5'd7`define T2CL 5'd8`define T2CH 5'd9`define SR 5'd10`define ACR 5'd11`define PCR 5'd12`define IFR 5'd13`define IER 5'd14`define ORA 5'd15`define T3CL 5'd16`define T3CH 5'd17`define T3LL 5'd18`define T3LH 5'd19`define T3CMPL 5'd20`define T3CMPH 5'd21module via6522_x12 (rst_i, clk_i, wc_clk_i, irq_o, cs_i,cyc_i, stb_i, ack_o, we_i, adr_i, dat_i, dat_o,ca1, ca2_i, ca2_o, ca2_t, cb1_i, cb1_o, cb1_t, cb2_i, cb2_o, cb2_t,pa_i, pb_i, pa_o, pb_o, pa_t, pb_t,t1_if, t2_if, t3_if);parameter pBitsPerByte=12;input rst_i;input clk_i;input wc_clk_i;output reg irq_o;input cs_i;input cyc_i;input stb_i;output ack_o;input we_i;input [4:0] adr_i;input [pBitsPerByte-1:0] dat_i;output reg [pBitsPerByte-1:0] dat_o;input ca1;input ca2_i;output ca2_o;output ca2_t;input cb1_i;output cb1_o;output cb1_t;input cb2_i;output cb2_o;output cb2_t;input [pBitsPerByte-1:0] pa_i;input [pBitsPerByte-1:0] pb_i;output [pBitsPerByte-1:0] pa_o;output [pBitsPerByte-1:0] pb_o;output reg [pBitsPerByte-1:0] pa_t;output reg [pBitsPerByte-1:0] pb_t;output reg t1_if; // timer 1 interrupt flagoutput reg t2_if; // timer 2 interrupt flagoutput reg t3_if; // timer 3 interrupt flaginteger n;wire cs = cs_i & cyc_i & stb_i;ack_gen #(.READ_STAGES(2),.WRITE_STAGES(0),.REGISTER_OUTPUT(1)) uag1(.rst_i(rst_i),.clk_i(clk_i),.ce_i(1'b1),.i(cs),.we_i(cs & we_i),.o(ack_o),.rid_i(0),.wid_i(0),.rid_o(),.wid_o());reg [5:0] ie_delay;reg [8:0] ier, ierd; // interrupt enable register / delayed interrupt enable registerreg [pBitsPerByte-1:0] pai, pbi; // input registersreg [pBitsPerByte-1:0] pao, pbo; // output latchesreg [pBitsPerByte-1:0] pal, pbl; // input latchesreg pa_le, pb_le; // latching enablereg [pBitsPerByte-1:0] ddra, ddrb; // data direction registersreg cb1o, cb2o, ca2o;reg [1:0] t1_mode;reg t2_mode;reg t3_mode;reg [pBitsPerByte*2-1:0] t1, t2, t3; // 24 bit timersreg [pBitsPerByte*2-1:0] t3cmp;reg t3_access;reg t1_64, t2_64;reg [pBitsPerByte*2-1:0] t1l;reg [pBitsPerByte*2-1:0] t2l;reg [pBitsPerByte*2-1:0] t3l;wire ca1_trans, ca2_trans; // active transitionswire cb1_trans, cb2_trans;reg ca1_mode;reg cb1_mode;reg [2:0] ca2_mode;reg [2:0] cb2_mode;reg [4:0] sr_cnt; // shift register counterreg [pBitsPerByte-1:0] sr; // shift registerreg sr_32; // shift register 32 bit modereg [2:0] sr_mode; // shift register modereg sr_if;wire ca1_pe, ca1_ne, ca1_ee;wire ca2_pe, ca2_ne, ca2_ee;wire cb1_pe, cb1_ne, cb1_ee;reg ca1_if, cb1_if;reg ca2_if, cb2_if;wire pb6_ne;reg ca1_irq, ca2_irq;reg cb1_irq, cb2_irq;reg t1_irq, t2_irq, t3_irq;reg sr_irq;wire pe_t1z, pe_t2z, pe_t3z;edge_det ued1 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(ca1), .pe(ca1_pe), .ne(ca1_ne), .ee(ca1_ee));edge_det ued2 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(ca2_i), .pe(ca2_pe), .ne(ca2_ne), .ee(ca2_ee));edge_det ued3 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(cb1_i), .pe(cb1_pe), .ne(cb1_ne), .ee(cb1_ee));edge_det ued4 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(cb2_i), .pe(cb2_pe), .ne(cb2_ne), .ee(cb2_ee));edge_det ued5 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(pb_i[10]), .pe(), .ne(pb6_ne), .ee());edge_det ued6 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(t3=={pBitsPerByte*2{1'd0}}), .pe(pe_t3z), .ne(), .ee());edge_det ued7 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(t2=={pBitsPerByte*2{1'd0}}), .pe(pe_t2z), .ne(), .ee());edge_det ued8 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(t1=={pBitsPerByte*2{1'd0}}), .pe(pe_t1z), .ne(), .ee());assign ca1_trans = (ca1_mode & ca1_pe) | (~ca1_mode & ca1_ne);assign ca2_trans = (ca2_mode[2:1]==2'b00&&ca2_ne)||(ca2_mode[2:1]==2'b01&&ca2_pe);assign cb1_trans = (cb1_mode & cb1_pe) | (~cb1_mode & cb1_ne);assign cb2_trans = (cb2_mode[2:1]==2'b00&&cb2_ne)||(cb2_mode[2:1]==2'b01&&cb2_pe);reg wr_t3;always @(posedge wc_clk_i)if (rst_i)t3 <= {pBitsPerByte*2{1'd1}};else begint3 <= t3 + 2'd1;if (wr_t3)t3 <= t3l;endalways @(posedge clk_i)if (rst_i) beginddra <= {pBitsPerByte{1'd0}};ddrb <= {pBitsPerByte{1'd0}};ca1_irq <= 1'b0;ca2_irq <= 1'b0;cb1_irq <= 1'b0;cb2_irq <= 1'b0;ca2o <= 1'b0;cb1o <= 1'b0;cb2o <= 1'b0;t1_64 <= 1'b0;t2_64 <= 1'b0;sr_mode <= 3'b000;sr_32 <= 1'b0;sr_if <= 1'b0;t1 <= {pBitsPerByte*2{1'd1}};t1_if <= 1'b0;t2 <= {pBitsPerByte*2{1'd1}};t2_if <= 1'b0;t3_if <= 1'b0;t3_access <= 1'b0;wr_t3 <= 1'b0;ier <= 9'h00;ie_delay <= 6'h00;endelse beginif (ie_delay!=6'h00)ie_delay <= ie_delay - 2'd1;if (ie_delay==6'h01)ier <= ierd;// Port A,B input latching// Port A input latches always reflect the input pins.if (pa_le) beginif (ca1_trans)pai <= pa_i;endelsepai <= pa_i;// Port B input latches reflect the contents of the output register if the// port pin direction is an output.if (pb_le) beginif (cb1_trans)for (n = 0; n < 12; n = n + 1)pbi <= ddrb[n] ? pbo[n] : pb_i[n];endelse beginfor (n = 0; n < 12; n = n + 1)pbi <= ddrb[n] ? pbo[n] : pb_i[n];end// Bring ca2 back high on pulse output modeif (ca2_mode==3'b100 && ca1_trans)ca2o <= 1'b1;else if (ca2_mode==3'b101)ca2o <= 1'b1;t1 <= t1 - 2'd1;if (pe_t1z) begint1_if <= 1'b1;case(t1_mode)2'd1: t1 <= t1l;2'd2:beginpbo[pBitsPerByte-1] <= 1'b1;ier[5] <= 1'b0;end2'd3:beginpbo[pBitsPerByte-1] <= ~pbo[pBitsPerByte-1];t1 <= t1l;enddefault: ;endcaseendcase(t2_mode)1'd0: t2 <= t2 - 2'd1;1'd1: if (pb6_ne) t2 <= t2 - 2'd1;endcaseif (pe_t2z) begint2_if <= 1'b1;if (t2_mode==1'b0)ier[6] <= 1'b0;end// If counting up interrupt on count greater than or equal to compare// register.if (t3cmp <= t3) beginif (t3_mode==1'b0 && pBitsPerByte > 8)ier[7] <= 1'b0;t3_if <= 1'b1;endelset3_if <= 1'b0;if (wr_t3) beginif (t3==t3l)wr_t3 <= 1'b0;endcase(sr_mode)3'b000: ;3'b001:beginif (cb1_ne) beginsr_cnt <= sr_cnt - 2'd1;sr <= {sr[pBitsPerByte-2:0],cb2_i};if (sr_cnt==5'd0)sr_if <= 1'b1;endend3'b010:beginif (cb1_ne) beginsr_cnt <= sr_cnt - 2'd1;sr <= {sr[pBitsPerByte-2:0],cb2_i};if (sr_cnt==5'd0)sr_if <= 1'b1;endend3'b011:beginif (cb1_ne) beginsr_cnt <= sr_cnt - 2'd1;sr <= {sr[pBitsPerByte-2:0],cb2_i};if (sr_cnt==5'd0)sr_if <= 1'b1;endend3'b100:if (t2[11:0]==12'h00) beginif (cb1_ne) beginsr <= {sr[pBitsPerByte-2:0],sr[pBitsPerByte-1]};endend3'b101:if (t2[11:0]==12'h00) beginif (sr_cnt != 5'd0) beginif (cb1_ne) beginsr_cnt <= sr_cnt - 2'd1;sr <= {sr[pBitsPerByte-2:0],sr[pBitsPerByte-1]};if (sr_cnt==5'd1)sr_if <= 1'b1;endendend3'b110:if (sr_cnt != 5'd0) beginif (cb1_ne) beginsr_cnt <= sr_cnt - 2'd1;sr <= {sr[pBitsPerByte-2:0],sr[pBitsPerByte-1]};if (sr_cnt==5'd1)sr_if <= 1'b1;endend3'b111:if (cb1_ne) beginsr_cnt <= sr_cnt - 2'd1;sr <= {sr[pBitsPerByte-2:0],sr[pBitsPerByte-1]};if (sr_cnt==5'd1)sr_if <= 1'b1;endendcase// CB1 outputcase(sr_mode)3'b000: ;3'b001:if (t2[pBitsPerByte-1:0]=={pBitsPerByte{1'b0}})cb1o <= ~cb1o;3'b010: cb1o <= ~cb1o;3'b011: ; // used as input3'b100:if (t2[pBitsPerByte-1:0]=={pBitsPerByte{1'b0}})cb1o <= ~cb1o;3'b101:if (t2[pBitsPerByte-1:0]=={pBitsPerByte{1'b0}}) beginif (sr_cnt != 5'd0)cb1o <= ~cb1o;end3'b110:if (sr_cnt != 5'd0)cb1o <= ~cb1o;3'b111: ; // used as inputendcase// CB2 outputcase(sr_mode)3'b000,3'b001,3'b010,3'b011:if (cb2_mode==3'b100 && cb1_trans)cb2o <= 1'b1;else if (cb2_mode==3'b101)cb2o <= 1'b1;3'b100:if (t2[pBitsPerByte-1:0]=={pBitsPerByte{1'b0}}) beginif (cb1_ne)cb2o <= sr[pBitsPerByte-1];end3'b101:if (t2[pBitsPerByte-1:0]=={pBitsPerByte{1'b0}}) beginif (sr_cnt != 5'd0) beginif (cb1_ne)cb2o <= sr[pBitsPerByte-1];endif (sr_cnt==5'd0)cb2o <= cb2_mode[0];end3'b110:if (sr_cnt != 5'd0) beginif (cb1_ne)cb2o <= sr[pBitsPerByte-1];end3'b111:if (cb1_ne)cb2o <= sr[pBitsPerByte-1];endcaseif (cs) beginif (we_i) begincase(adr_i)`PA:beginpao <= dat_i;if (ca2_mode==3'b100||ca2_mode==3'b101)ca2o <= 1'b0;ca1_if <= 1'b0;ca2_if <= 1'b0;end`PB:beginpbo <= dat_i;if (cb2_mode==3'b100||cb2_mode==3'b101)cb2o <= 1'b0;cb1_if <= 1'b0;cb2_if <= 1'b0;end`DDRA:beginddra <= dat_i;end`DDRB:beginddrb <= dat_i;end`T1CL:begint1l[pBitsPerByte-1:0] <= dat_i;end`T1CH:begint1 <= {dat_i[pBitsPerByte-1:0],t1l[pBitsPerByte-1:0]};t1_if <= 1'b0;if (t1_mode[1]==1'b1)pbo[11] <= 1'b0;end`T1LL:begint1l[pBitsPerByte-1:0] <= dat_i;end`T1LH:begint1l[pBitsPerByte*2-1:pBitsPerByte] <= {{pBitsPerByte{1'd0}},dat_i};t1_if <= 1'b0;end`T2CL:begint2l[pBitsPerByte-1:0] <= dat_i;end`T2CH:begint2 <= {dat_i,t2l[pBitsPerByte-1:0]};t2_if <= 1'b0;end`PCR:beginca1_mode <= dat_i[0];ca2_mode <= dat_i[3:1];cb1_mode <= dat_i[4];cb2_mode <= dat_i[7:5];end`SR:beginsr <= dat_i;sr_cnt <= 5'd11;if (sr_mode==3'b001)cb1o <= 1'b1;sr_if <= 1'b0;end`ACR:beginpa_le <= dat_i[0];pb_le <= dat_i[1];sr_mode <= dat_i[4:2];t2_mode <= dat_i[5];t1_mode <= dat_i[7:6];if (pBitsPerByte > 8)t3_mode <= dat_i[8];end`IER:beginif (pBitsPerByte==8) beginif (dat_i[pBitsPerByte-1])ierd[6:0] <= ier[6:0] | dat_i[6:0];elseierd[6:0] <= ier[6:0] & ~dat_i[6:0];endelse beginif (dat_i[pBitsPerByte-1])ierd[7:0] <= ier[7:0] | dat_i[7:0];elseierd[7:0] <= ier[7:0] & ~dat_i[7:0];endier[pBitsPerByte-1] <= 1'b0;ie_delay <= 6'h01;end`ORA:beginpao <= dat_i;end`T3CL: ;`T3CH: ;`T3LL:begint3l[pBitsPerByte-1:0] <= dat_i;end`T3LH:begint3l[pBitsPerByte*2-1:pBitsPerByte] <= dat_i;wr_t3 <= 1'b1;t3_if <= 1'b0;end`T3CMPL:begint3cmp[pBitsPerByte-1:0] <= dat_i;end`T3CMPH:begint3cmp[pBitsPerByte*2-1:pBitsPerByte] <= dat_i;endendcasedat_o <= {pBitsPerByte{1'h0}};endelse begincase(adr_i)`PA:begindat_o <= pai;if (ca2_mode==3'b100||ca2_mode==3'b101)ca2o <= 1'b0;ca1_if <= 1'b0;ca2_if <= 1'b0;end`PB:begindat_o <= pbi;cb1_if <= 1'b0;cb2_if <= 1'b0;end`DDRA: dat_o <= ddra;`DDRB: dat_o <= ddrb;`T1CL:begindat_o <= t1[pBitsPerByte-1:0];t1_if <= 1'b0;end`T1CH:dat_o <= t1[pBitsPerByte*2-1:pBitsPerByte];`T1LL:dat_o <= t1l[pBitsPerByte-1:0];`T1LH:dat_o <= t1l[pBitsPerByte*2-1:pBitsPerByte];`T2CL:begindat_o <= t2[pBitsPerByte-1:0];t2_if <= 1'b0;end`T2CH:dat_o <= t2[pBitsPerByte*2-1:pBitsPerByte];`PCR: dat_o <= {4'd0,cb2_mode,cb1_mode,ca2_mode,ca1_mode};`SR:begindat_o <= sr;if (sr_mode==3'b001)cb1o <= 1'b1;sr_cnt <= 5'd11;sr_if <= 1'b0;end`ACR: dat_o <= pBitsPerByte==8 ? {t1_mode,t2_mode,sr_mode,pb_le,pa_le} : {3'd0,t3_mode,t1_mode,t2_mode,sr_mode,pb_le,pa_le};`IFR: dat_o <= pBitsPerByte==8 ? {irq_o,t2_irq,t1_irq,cb1_irq,cb2_irq,sr_irq,ca1_irq,ca2_irq} :{irq_o,3'd0,t3_irq,t2_irq,t1_irq,cb1_irq,cb2_irq,sr_irq,ca1_irq,ca2_irq};`IER: dat_o <= {3'd0,ier};`ORA: dat_o <= pai;`T3CL:begindat_o <= t3[pBitsPerByte-1:0];t3_if <= 1'b0;end`T3CH:dat_o <= t3[pBitsPerByte*2-1:pBitsPerByte];`T3LL:dat_o <= t3l[pBitsPerByte-1:0];`T3LH:dat_o <= t3l[pBitsPerByte*2-1:pBitsPerByte];`T3CMPL:dat_o <= t3cmp[pBitsPerByte-1:0];`T3CMPH:dat_o <= t3cmp[pBitsPerByte*2-1:pBitsPerByte];default: dat_o <= {pBitsPerByte{1'h0}};endcaseendend// Allows wire-or of data buselsedat_o <= {pBitsPerByte{1'h0}};ca2_irq <= ca2_trans & ier[0];ca1_irq <= ca1_trans & ier[1];sr_irq <= sr_if & ier[2];cb2_irq <= cb2_trans & ier[3];cb1_irq <= cb1_trans & ier[4];t1_irq <= t1_if & ier[5];t2_irq <= t2_if & ier[6];if (pBitsPerByte > 8)t3_irq <= t3_if & ier[7];elset3_irq <= 1'b0;irq_o <=(ca2_trans & ier[0])| (ca1_trans & ier[1])| (sr_if & ier[2])| (cb2_trans & ier[3])| (cb1_trans & ier[4])| (t1_if & ier[5])| (t2_if & ier[6])| ((t3_if & ier[7]) && pBitsPerByte > 8);end// Outputsgenvar g;generate begin : gPortsfor (g = 0; g < pBitsPerByte; g = g + 1) beginassign pa_t[g] = ddra[g];endfor (g = 0; g < pBitsPerByte; g = g + 1) beginassign pb_t[g] = ddrb[g];endendendgenerate// CA1 is always an input// CA2,CB1,CB2 output enablesassign ca2_t = ca2_mode[2]==1'b0;assign ca2_o = ca2_mode==3'b100 ? ca2o :ca2_mode==3'b101 ? ca2o :ca2_mode==3'b110 ? 1'b0 :1'b1;assign cb1_t = sr_mode==3'b000 || sr_mode==3'b011 || sr_mode==3'b111;assign cb1_o = cb1o;assign cb2_t = sr_mode[2]==1'b0 && cb2_mode[2]==1'b0;assign cb2_o = sr_mode[2]==1'b0 ? (cb2_mode[2]==1'b0 ? 1'b1 :cb2_mode==3'b100 ? cb2o :cb2_mode==3'b101 ? cb2o :cb2_mode==3'b110 ? 1'b0 :1'b1) :cb2o;assign pa_o = pao;assign pb_o = pbo;endmodule
