OpenCores
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'd21

module 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 flag
output reg t2_if;                                                       // timer 2 interrupt flag
output reg t3_if;                                                       // timer 3 interrupt flag

integer 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 register
reg [pBitsPerByte-1:0] pai, pbi;                // input registers
reg [pBitsPerByte-1:0] pao, pbo;                // output latches
reg [pBitsPerByte-1:0] pal, pbl;                // input latches
reg pa_le, pb_le;                               // latching enable
reg [pBitsPerByte-1:0] ddra, ddrb;      // data direction registers
reg cb1o, cb2o, ca2o;
reg [1:0] t1_mode;
reg t2_mode;
reg t3_mode;
reg [pBitsPerByte*2-1:0] t1, t2, t3;    // 24 bit timers
reg [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 transitions
wire 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 counter
reg [pBitsPerByte-1:0] sr;                                      // shift register
reg sr_32;                                                      // shift register 32 bit mode
reg [2:0] sr_mode;                      // shift register mode
reg 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 begin
        t3 <= t3 + 2'd1;
        if (wr_t3)
                t3 <= t3l;
end

always @(posedge clk_i)
if (rst_i) begin
        ddra <= {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;
end
else begin
  
  if (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) begin
                if (ca1_trans)
                        pai <= pa_i;
        end
        else
                pai <= pa_i;

        // Port B input latches reflect the contents of the output register if the
        // port pin direction is an output.
        if (pb_le) begin
                if (cb1_trans)
                        for (n = 0; n < 12; n = n + 1)
                                pbi <= ddrb[n] ? pbo[n] : pb_i[n];
        end
        else begin
                for (n = 0; n < 12; n = n + 1)
                        pbi <= ddrb[n] ? pbo[n] : pb_i[n];
        end

        // Bring ca2 back high on pulse output mode
        if (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) begin
                t1_if <= 1'b1;
                case(t1_mode)
                2'd1:   t1 <= t1l;
                2'd2:   
                        begin
                                pbo[pBitsPerByte-1] <= 1'b1;
                                ier[5] <= 1'b0;
                        end
                2'd3:   
                        begin
                                pbo[pBitsPerByte-1] <= ~pbo[pBitsPerByte-1];
                                t1 <= t1l;
                        end
                default:        ;
                endcase
        end

        case(t2_mode)
        1'd0:   t2 <= t2 - 2'd1;
        1'd1:   if (pb6_ne) t2 <= t2 - 2'd1;
        endcase
        if (pe_t2z) begin
                t2_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) begin
                if (t3_mode==1'b0 && pBitsPerByte > 8)
                        ier[7] <= 1'b0;
                t3_if <= 1'b1;
        end
        else
                t3_if <= 1'b0;
                
        if (wr_t3) begin
                if (t3==t3l)
                        wr_t3 <= 1'b0;
        end

        case(sr_mode)
        3'b000: ;
        3'b001:
                begin
                        if (cb1_ne) begin
                                sr_cnt <= sr_cnt - 2'd1;
                                sr <= {sr[pBitsPerByte-2:0],cb2_i};
                                if (sr_cnt==5'd0)
                                        sr_if <= 1'b1;
                        end
                end
        3'b010:
                begin
                        if (cb1_ne) begin
                                sr_cnt <= sr_cnt - 2'd1;
                                sr <= {sr[pBitsPerByte-2:0],cb2_i};
                                if (sr_cnt==5'd0)
                                        sr_if <= 1'b1;
                        end
                end
        3'b011:
                begin
                        if (cb1_ne) begin
                                sr_cnt <= sr_cnt - 2'd1;
                                sr <= {sr[pBitsPerByte-2:0],cb2_i};
                                if (sr_cnt==5'd0)
                                        sr_if <= 1'b1;
                        end
                end
        3'b100:
                if (t2[11:0]==12'h00) begin
                        if (cb1_ne) begin
                                sr <= {sr[pBitsPerByte-2:0],sr[pBitsPerByte-1]};
                        end
                end
        3'b101:
                if (t2[11:0]==12'h00) begin
                        if (sr_cnt != 5'd0) begin
                                if (cb1_ne) begin
                                        sr_cnt <= sr_cnt - 2'd1;
                                        sr <= {sr[pBitsPerByte-2:0],sr[pBitsPerByte-1]};
                                        if (sr_cnt==5'd1)
                                                sr_if <= 1'b1;
                                end
                        end
                end
        3'b110:
                if (sr_cnt != 5'd0) begin
                        if (cb1_ne) begin
                                sr_cnt <= sr_cnt - 2'd1;
                                sr <= {sr[pBitsPerByte-2:0],sr[pBitsPerByte-1]};
                                if (sr_cnt==5'd1)
                                        sr_if <= 1'b1;
                        end
                end
        3'b111:
                if (cb1_ne) begin
                        sr_cnt <= sr_cnt - 2'd1;
                        sr <= {sr[pBitsPerByte-2:0],sr[pBitsPerByte-1]};
                        if (sr_cnt==5'd1)
                                sr_if <= 1'b1;
                end
        endcase

        // CB1 output
        case(sr_mode)
        3'b000: ;
        3'b001:
                if (t2[pBitsPerByte-1:0]=={pBitsPerByte{1'b0}})
                        cb1o <= ~cb1o;
        3'b010: cb1o <= ~cb1o;
        3'b011: ;       // used as input
        3'b100:
                if (t2[pBitsPerByte-1:0]=={pBitsPerByte{1'b0}})
                        cb1o <= ~cb1o;
        3'b101:
                if (t2[pBitsPerByte-1:0]=={pBitsPerByte{1'b0}}) begin
                        if (sr_cnt != 5'd0)
                                cb1o <= ~cb1o;
                end
        3'b110:
                if (sr_cnt != 5'd0)
                        cb1o <= ~cb1o;
        3'b111: ;       // used as input
        endcase

        // CB2 output
        case(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}}) begin
                        if (cb1_ne)
                                cb2o <= sr[pBitsPerByte-1];
                end
        3'b101:
                if (t2[pBitsPerByte-1:0]=={pBitsPerByte{1'b0}}) begin
                        if (sr_cnt != 5'd0) begin
                                if (cb1_ne)
                                        cb2o <= sr[pBitsPerByte-1];
                        end
                        if (sr_cnt==5'd0)
                                cb2o <= cb2_mode[0];
                end
        3'b110:
                if (sr_cnt != 5'd0) begin
                        if (cb1_ne)
                                cb2o <= sr[pBitsPerByte-1];
                end
        3'b111:
                if (cb1_ne)
                        cb2o <= sr[pBitsPerByte-1];
        endcase

        if (cs) begin
                if (we_i) begin
                        case(adr_i)
                        `PA:
                                begin
                                        pao <= dat_i;
                                        if (ca2_mode==3'b100||ca2_mode==3'b101)
                                                ca2o <= 1'b0;
                                        ca1_if <= 1'b0;
                                        ca2_if <= 1'b0;
                                end
                        `PB:
                                begin
                                        pbo <= dat_i;
                                        if (cb2_mode==3'b100||cb2_mode==3'b101)
                                                cb2o <= 1'b0;
                                        cb1_if <= 1'b0;
                                        cb2_if <= 1'b0;
                                end
                        `DDRA:  
                                begin
                                        ddra <= dat_i;
                                end
                        `DDRB:  
                                begin
                                        ddrb <= dat_i;
                                end
                        `T1CL:
                                begin
                                        t1l[pBitsPerByte-1:0] <= dat_i;
                                end
                        `T1CH:
                                begin
                                        t1 <= {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:
                                begin
                                        t1l[pBitsPerByte-1:0] <= dat_i;
                                end
                        `T1LH:
                                begin
                                        t1l[pBitsPerByte*2-1:pBitsPerByte] <= {{pBitsPerByte{1'd0}},dat_i};
                                        t1_if <= 1'b0;
                                end
                        `T2CL:
                                begin
                                        t2l[pBitsPerByte-1:0] <= dat_i;
                                end
                        `T2CH:
                                begin
                                        t2 <= {dat_i,t2l[pBitsPerByte-1:0]};
                                        t2_if <= 1'b0;
                                end     
                        `PCR:
                                begin
                                        ca1_mode <= dat_i[0];
                                        ca2_mode <= dat_i[3:1];
                                        cb1_mode <= dat_i[4];
                                        cb2_mode <= dat_i[7:5];
                                end
                        `SR:
                                begin   
                                        sr <= dat_i;
                                        sr_cnt <= 5'd11;
                                        if (sr_mode==3'b001)
                                                cb1o <= 1'b1;
                                        sr_if <= 1'b0;                                          
                                end
                        `ACR:
                                begin
                                        pa_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:
                                begin
                                        if (pBitsPerByte==8) begin
                                                if (dat_i[pBitsPerByte-1])
                                                        ierd[6:0] <= ier[6:0] | dat_i[6:0];
                                                else
                                                        ierd[6:0] <= ier[6:0] & ~dat_i[6:0];
                                        end
                                        else begin
                                                if (dat_i[pBitsPerByte-1])
                                                        ierd[7:0] <= ier[7:0] | dat_i[7:0];
                                                else
                                                        ierd[7:0] <= ier[7:0] & ~dat_i[7:0];
                                        end
                                        ier[pBitsPerByte-1] <= 1'b0;
                                  ie_delay <= 6'h01;
                                end
                        `ORA:
                                begin
                                        pao <= dat_i;
                                end
                        `T3CL:  ;
                        `T3CH:  ;
                        `T3LL:
                                begin
                                        t3l[pBitsPerByte-1:0] <= dat_i;
                                end
                        `T3LH:
                                begin
                                        t3l[pBitsPerByte*2-1:pBitsPerByte] <= dat_i;
                                        wr_t3 <= 1'b1;
                                        t3_if <= 1'b0;
                                end
                        `T3CMPL:
                                begin
                                        t3cmp[pBitsPerByte-1:0] <= dat_i;
                                end
                        `T3CMPH:
                                begin
                                        t3cmp[pBitsPerByte*2-1:pBitsPerByte] <= dat_i;
                                end
                        endcase
                        dat_o <= {pBitsPerByte{1'h0}};
                end     
                else begin
                        case(adr_i)
                        `PA:
                                begin
                                        dat_o <= pai;
                                        if (ca2_mode==3'b100||ca2_mode==3'b101)
                                                ca2o <= 1'b0;
                                        ca1_if <= 1'b0;
                                        ca2_if <= 1'b0;
                                end
                        `PB:    
                                begin
                                        dat_o <= pbi;
                                        cb1_if <= 1'b0;
                                        cb2_if <= 1'b0;
                                end
                        `DDRA:  dat_o <= ddra;
                        `DDRB:  dat_o <= ddrb;
                        `T1CL:
                                begin
                                        dat_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:  
                                begin
                                        dat_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:
                                begin   
                                        dat_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:
                                begin   
                                        dat_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}};
                        endcase
                end
        end
        // Allows wire-or of data bus
        else
                dat_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];
        else
                t3_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

// Outputs

genvar g;
generate begin : gPorts
        for (g = 0; g < pBitsPerByte; g = g + 1) begin
                assign pa_t[g] = ddra[g];
        end
                
        for (g = 0; g < pBitsPerByte; g = g + 1) begin
                assign pb_t[g] = ddrb[g];
        end
end
endgenerate

// CA1 is always an input

// CA2,CB1,CB2 output enables

assign 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

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.