├── .gitignore
├── LICENSE
├── README.md
└── verilog
├── ALU.v
├── cpu.v
├── mcu.v
├── wb_6502_bridge.v
├── wb_6522_via.v
├── wb_bus.v
├── wb_gpio.v
└── wb_ram.v
/.gitignore:
--------------------------------------------------------------------------------
1 | *_Implmnt/
2 | stdout.log
3 | synlog.tcl
4 | *~
5 | *.swp
6 | *bak
7 | gerbers/
8 | build/
9 | *.vcd
10 | *.vvp
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TinyFPGA-SoC
2 | Opensource building blocks for TinyFPGA microcontrollers and retro computers.
3 |
--------------------------------------------------------------------------------
/verilog/ALU.v:
--------------------------------------------------------------------------------
1 | /*
2 | * ALU.
3 | *
4 | * AI and BI are 8 bit inputs. Result in OUT.
5 | * CI is Carry In.
6 | * CO is Carry Out.
7 | *
8 | * op[3:0] is defined as follows:
9 | *
10 | * 0011 AI + BI
11 | * 0111 AI - BI
12 | * 1011 AI + AI
13 | * 1100 AI | BI
14 | * 1101 AI & BI
15 | * 1110 AI ^ BI
16 | * 1111 AI
17 | *
18 | */
19 |
20 | module ALU( clk, op, right, AI, BI, CI, CO, BCD, OUT, V, Z, N, HC, RDY );
21 | input clk;
22 | input right;
23 | input [3:0] op; // operation
24 | input [7:0] AI;
25 | input [7:0] BI;
26 | input CI;
27 | input BCD; // BCD style carry
28 | output [7:0] OUT;
29 | output CO;
30 | output V;
31 | output Z;
32 | output N;
33 | output HC;
34 | input RDY;
35 |
36 | reg [7:0] OUT;
37 | reg CO;
38 | wire V;
39 | wire Z;
40 | reg N;
41 | reg HC;
42 |
43 | reg AI7;
44 | reg BI7;
45 | reg [8:0] temp_logic;
46 | reg [7:0] temp_BI;
47 | reg [4:0] temp_l;
48 | reg [4:0] temp_h;
49 | wire [8:0] temp = { temp_h, temp_l[3:0] };
50 | wire adder_CI = (right | (op[3:2] == 2'b11)) ? 0 : CI;
51 |
52 | // calculate the logic operations. The 'case' can be done in 1 LUT per
53 | // bit. The 'right' shift is a simple mux that can be implemented by
54 | // F5MUX.
55 | always @* begin
56 | case( op[1:0] )
57 | 2'b00: temp_logic = AI | BI;
58 | 2'b01: temp_logic = AI & BI;
59 | 2'b10: temp_logic = AI ^ BI;
60 | 2'b11: temp_logic = AI;
61 | endcase
62 |
63 | if( right )
64 | temp_logic = { AI[0], CI, AI[7:1] };
65 | end
66 |
67 | // Add logic result to BI input. This only makes sense when logic = AI.
68 | // This stage can be done in 1 LUT per bit, using carry chain logic.
69 | always @* begin
70 | case( op[3:2] )
71 | 2'b00: temp_BI = BI; // A+B
72 | 2'b01: temp_BI = ~BI; // A-B
73 | 2'b10: temp_BI = temp_logic; // A+A
74 | 2'b11: temp_BI = 0; // A+0
75 | endcase
76 | end
77 |
78 | // HC9 is the half carry bit when doing BCD add
79 | wire HC9 = BCD & (temp_l[3:1] >= 3'd5);
80 |
81 | // CO9 is the carry-out bit when doing BCD add
82 | wire CO9 = BCD & (temp_h[3:1] >= 3'd5);
83 |
84 | // combined half carry bit
85 | wire temp_HC = temp_l[4] | HC9;
86 |
87 | // perform the addition as 2 separate nibble, so we get
88 | // access to the half carry flag
89 | always @* begin
90 | temp_l = temp_logic[3:0] + temp_BI[3:0] + adder_CI;
91 | temp_h = temp_logic[8:4] + temp_BI[7:4] + temp_HC;
92 | end
93 |
94 | // calculate the flags
95 | always @(posedge clk)
96 | if( RDY ) begin
97 | AI7 <= AI[7];
98 | BI7 <= temp_BI[7];
99 | OUT <= temp[7:0];
100 | CO <= temp[8] | CO9;
101 | N <= temp[7];
102 | HC <= temp_HC;
103 | end
104 |
105 | assign V = AI7 ^ BI7 ^ CO ^ N;
106 | assign Z = ~|OUT;
107 |
108 | endmodule
109 |
--------------------------------------------------------------------------------
/verilog/cpu.v:
--------------------------------------------------------------------------------
1 | /*
2 | * verilog model of 6502 CPU.
3 | *
4 | * (C) Arlet Ottens,
5 | *
6 | * Feel free to use this code in any project (commercial or not), as long as you
7 | * keep this message, and the copyright notice. This code is provided "as is",
8 | * without any warranties of any kind.
9 | *
10 | */
11 |
12 | /*
13 | * Note that not all 6502 interface signals are supported (yet). The goal
14 | * is to create an Acorn Atom model, and the Atom didn't use all signals on
15 | * the main board.
16 | *
17 | * The data bus is implemented as separate read/write buses. Combine them
18 | * on the output pads if external memory is required.
19 | */
20 |
21 | module cpu( clk, reset, AB, DI, DO, WE, IRQ, NMI, RDY );
22 |
23 | input clk; // CPU clock
24 | input reset; // reset signal
25 | output reg [15:0] AB; // address bus
26 | input [7:0] DI; // data in, read bus
27 | output [7:0] DO; // data out, write bus
28 | output WE; // write enable
29 | input IRQ; // interrupt request
30 | input NMI; // non-maskable interrupt request
31 | input RDY; // Ready signal. Pauses CPU when RDY=0
32 |
33 | /*
34 | * internal signals
35 | */
36 |
37 | reg [15:0] PC; // Program Counter
38 | reg [7:0] ABL; // Address Bus Register LSB
39 | reg [7:0] ABH; // Address Bus Register MSB
40 | wire [7:0] ADD; // Adder Hold Register (registered in ALU)
41 |
42 | reg [7:0] DIHOLD; // Hold for Data In
43 | reg DIHOLD_valid; //
44 | wire [7:0] DIMUX; //
45 |
46 | reg [7:0] IRHOLD; // Hold for Instruction register
47 | reg IRHOLD_valid; // Valid instruction in IRHOLD
48 |
49 | reg [7:0] AXYS[3:0]; // A, X, Y and S register file
50 |
51 | reg C = 0; // carry flag (init at zero to avoid X's in ALU sim)
52 | reg Z = 0; // zero flag
53 | reg I = 0; // interrupt flag
54 | reg D = 0; // decimal flag
55 | reg V = 0; // overflow flag
56 | reg N = 0; // negative flag
57 | wire AZ; // ALU Zero flag
58 | wire AV; // ALU overflow flag
59 | wire AN; // ALU negative flag
60 | wire HC; // ALU half carry
61 |
62 | reg [7:0] AI; // ALU Input A
63 | reg [7:0] BI; // ALU Input B
64 | wire [7:0] DI; // Data In
65 | wire [7:0] IR; // Instruction register
66 | reg [7:0] DO; // Data Out
67 | reg WE; // Write Enable
68 | reg CI; // Carry In
69 | wire CO; // Carry Out
70 | wire [7:0] PCH = PC[15:8];
71 | wire [7:0] PCL = PC[7:0];
72 |
73 | reg NMI_edge = 0; // captured NMI edge
74 |
75 | reg [1:0] regsel; // Select A, X, Y or S register
76 | wire [7:0] regfile = AXYS[regsel]; // Selected register output
77 |
78 | parameter
79 | SEL_A = 2'd0,
80 | SEL_S = 2'd1,
81 | SEL_X = 2'd2,
82 | SEL_Y = 2'd3;
83 |
84 | /*
85 | * define some signals for watching in simulator output
86 | */
87 |
88 |
89 | `ifdef SIM
90 | wire [7:0] A = AXYS[SEL_A]; // Accumulator
91 | wire [7:0] X = AXYS[SEL_X]; // X register
92 | wire [7:0] Y = AXYS[SEL_Y]; // Y register
93 | wire [7:0] S = AXYS[SEL_S]; // Stack pointer
94 | `endif
95 |
96 | // NOTE: FPGA registers are initialized to '0' by default, but we need to
97 | // tell the simulator that or we will get X's propogated everywhere
98 | initial begin
99 | AB = 0;
100 | PC = 0;
101 | ABL = 0;
102 | ABH = 0;
103 | DIHOLD = 0;
104 | DIHOLD_valid = 0;
105 | IRHOLD = 0;
106 | IRHOLD_valid = 0;
107 | AXYS[0] = 0;
108 | AXYS[1] = 0;
109 | AXYS[2] = 0;
110 | AXYS[3] = 0;
111 | C = 0;
112 | Z = 0;
113 | I = 0;
114 | D = 0;
115 | V = 0;
116 | N = 0;
117 | AI = 0;
118 | BI = 0;
119 | DO = 0;
120 | WE = 0;
121 | CI = 0;
122 | NMI_edge = 0;
123 | regsel = 0;
124 | end
125 |
126 |
127 | wire [7:0] P = { N, V, 2'b11, D, I, Z, C };
128 |
129 | /*
130 | * instruction decoder/sequencer
131 | */
132 |
133 | reg [5:0] state;
134 |
135 | /*
136 | * control signals
137 | */
138 |
139 | reg PC_inc; // Increment PC
140 | reg [15:0] PC_temp; // intermediate value of PC
141 |
142 | reg [1:0] src_reg; // source register index
143 | reg [1:0] dst_reg; // destination register index
144 |
145 | reg index_y; // if set, then Y is index reg rather than X
146 | reg load_reg; // loading a register (A, X, Y, S) in this instruction
147 | reg inc; // increment
148 | reg write_back; // set if memory is read/modified/written
149 | reg load_only; // LDA/LDX/LDY instruction
150 | reg store; // doing store (STA/STX/STY)
151 | reg adc_sbc; // doing ADC/SBC
152 | reg compare; // doing CMP/CPY/CPX
153 | reg shift; // doing shift/rotate instruction
154 | reg rotate; // doing rotate (no shift)
155 | reg backwards; // backwards branch
156 | reg cond_true; // branch condition is true
157 | reg [2:0] cond_code; // condition code bits from instruction
158 | reg shift_right; // Instruction ALU shift/rotate right
159 | reg alu_shift_right; // Current cycle shift right enable
160 | reg [3:0] op; // Main ALU operation for instruction
161 | reg [3:0] alu_op; // Current cycle ALU operation
162 | reg adc_bcd; // ALU should do BCD style carry
163 | reg adj_bcd; // results should be BCD adjusted
164 |
165 | /*
166 | * some flip flops to remember we're doing special instructions. These
167 | * get loaded at the DECODE state, and used later
168 | */
169 | reg bit_ins; // doing BIT instruction
170 | reg plp; // doing PLP instruction
171 | reg php; // doing PHP instruction
172 | reg clc; // clear carry
173 | reg sec; // set carry
174 | reg cld; // clear decimal
175 | reg sed; // set decimal
176 | reg cli; // clear interrupt
177 | reg sei; // set interrupt
178 | reg clv; // clear overflow
179 | reg brk; // doing BRK
180 |
181 | reg res; // in reset
182 |
183 | /*
184 | * ALU operations
185 | */
186 |
187 | parameter
188 | OP_OR = 4'b1100,
189 | OP_AND = 4'b1101,
190 | OP_EOR = 4'b1110,
191 | OP_ADD = 4'b0011,
192 | OP_SUB = 4'b0111,
193 | OP_ROL = 4'b1011,
194 | OP_A = 4'b1111;
195 |
196 | /*
197 | * Microcode state machine. Basically, every addressing mode has its own
198 | * path through the state machine. Additional information, such as the
199 | * operation, source and destination registers are decoded in parallel, and
200 | * kept in separate flops.
201 | */
202 |
203 | parameter
204 | ABS0 = 6'd0, // ABS - fetch LSB
205 | ABS1 = 6'd1, // ABS - fetch MSB
206 | ABSX0 = 6'd2, // ABS, X - fetch LSB and send to ALU (+X)
207 | ABSX1 = 6'd3, // ABS, X - fetch MSB and send to ALU (+Carry)
208 | ABSX2 = 6'd4, // ABS, X - Wait for ALU (only if needed)
209 | BRA0 = 6'd5, // Branch - fetch offset and send to ALU (+PC[7:0])
210 | BRA1 = 6'd6, // Branch - fetch opcode, and send PC[15:8] to ALU
211 | BRA2 = 6'd7, // Branch - fetch opcode (if page boundary crossed)
212 | BRK0 = 6'd8, // BRK/IRQ - push PCH, send S to ALU (-1)
213 | BRK1 = 6'd9, // BRK/IRQ - push PCL, send S to ALU (-1)
214 | BRK2 = 6'd10, // BRK/IRQ - push P, send S to ALU (-1)
215 | BRK3 = 6'd11, // BRK/IRQ - write S, and fetch @ fffe
216 | DECODE = 6'd12, // IR is valid, decode instruction, and write prev reg
217 | FETCH = 6'd13, // fetch next opcode, and perform prev ALU op
218 | INDX0 = 6'd14, // (ZP,X) - fetch ZP address, and send to ALU (+X)
219 | INDX1 = 6'd15, // (ZP,X) - fetch LSB at ZP+X, calculate ZP+X+1
220 | INDX2 = 6'd16, // (ZP,X) - fetch MSB at ZP+X+1
221 | INDX3 = 6'd17, // (ZP,X) - fetch data
222 | INDY0 = 6'd18, // (ZP),Y - fetch ZP address, and send ZP to ALU (+1)
223 | INDY1 = 6'd19, // (ZP),Y - fetch at ZP+1, and send LSB to ALU (+Y)
224 | INDY2 = 6'd20, // (ZP),Y - fetch data, and send MSB to ALU (+Carry)
225 | INDY3 = 6'd21, // (ZP),Y) - fetch data (if page boundary crossed)
226 | JMP0 = 6'd22, // JMP - fetch PCL and hold
227 | JMP1 = 6'd23, // JMP - fetch PCH
228 | JMPI0 = 6'd24, // JMP IND - fetch LSB and send to ALU for delay (+0)
229 | JMPI1 = 6'd25, // JMP IND - fetch MSB, proceed with JMP0 state
230 | JSR0 = 6'd26, // JSR - push PCH, save LSB, send S to ALU (-1)
231 | JSR1 = 6'd27, // JSR - push PCL, send S to ALU (-1)
232 | JSR2 = 6'd28, // JSR - write S
233 | JSR3 = 6'd29, // JSR - fetch MSB
234 | PULL0 = 6'd30, // PLP/PLA - save next op in IRHOLD, send S to ALU (+1)
235 | PULL1 = 6'd31, // PLP/PLA - fetch data from stack, write S
236 | PULL2 = 6'd32, // PLP/PLA - prefetch op, but don't increment PC
237 | PUSH0 = 6'd33, // PHP/PHA - send A to ALU (+0)
238 | PUSH1 = 6'd34, // PHP/PHA - write A/P, send S to ALU (-1)
239 | READ = 6'd35, // Read memory for read/modify/write (INC, DEC, shift)
240 | REG = 6'd36, // Read register for reg-reg transfers
241 | RTI0 = 6'd37, // RTI - send S to ALU (+1)
242 | RTI1 = 6'd38, // RTI - read P from stack
243 | RTI2 = 6'd39, // RTI - read PCL from stack
244 | RTI3 = 6'd40, // RTI - read PCH from stack
245 | RTI4 = 6'd41, // RTI - read PCH from stack
246 | RTS0 = 6'd42, // RTS - send S to ALU (+1)
247 | RTS1 = 6'd43, // RTS - read PCL from stack
248 | RTS2 = 6'd44, // RTS - write PCL to ALU, read PCH
249 | RTS3 = 6'd45, // RTS - load PC and increment
250 | WRITE = 6'd46, // Write memory for read/modify/write
251 | ZP0 = 6'd47, // Z-page - fetch ZP address
252 | ZPX0 = 6'd48, // ZP, X - fetch ZP, and send to ALU (+X)
253 | ZPX1 = 6'd49; // ZP, X - load from memory
254 |
255 | `ifdef SIM
256 |
257 | /*
258 | * easy to read names in simulator output
259 | */
260 | reg [8*6-1:0] statename;
261 |
262 | always @*
263 | case( state )
264 | DECODE: statename = "DECODE";
265 | REG: statename = "REG";
266 | ZP0: statename = "ZP0";
267 | ZPX0: statename = "ZPX0";
268 | ZPX1: statename = "ZPX1";
269 | ABS0: statename = "ABS0";
270 | ABS1: statename = "ABS1";
271 | ABSX0: statename = "ABSX0";
272 | ABSX1: statename = "ABSX1";
273 | ABSX2: statename = "ABSX2";
274 | INDX0: statename = "INDX0";
275 | INDX1: statename = "INDX1";
276 | INDX2: statename = "INDX2";
277 | INDX3: statename = "INDX3";
278 | INDY0: statename = "INDY0";
279 | INDY1: statename = "INDY1";
280 | INDY2: statename = "INDY2";
281 | INDY3: statename = "INDY3";
282 | READ: statename = "READ";
283 | WRITE: statename = "WRITE";
284 | FETCH: statename = "FETCH";
285 | PUSH0: statename = "PUSH0";
286 | PUSH1: statename = "PUSH1";
287 | PULL0: statename = "PULL0";
288 | PULL1: statename = "PULL1";
289 | PULL2: statename = "PULL2";
290 | JSR0: statename = "JSR0";
291 | JSR1: statename = "JSR1";
292 | JSR2: statename = "JSR2";
293 | JSR3: statename = "JSR3";
294 | RTI0: statename = "RTI0";
295 | RTI1: statename = "RTI1";
296 | RTI2: statename = "RTI2";
297 | RTI3: statename = "RTI3";
298 | RTI4: statename = "RTI4";
299 | RTS0: statename = "RTS0";
300 | RTS1: statename = "RTS1";
301 | RTS2: statename = "RTS2";
302 | RTS3: statename = "RTS3";
303 | BRK0: statename = "BRK0";
304 | BRK1: statename = "BRK1";
305 | BRK2: statename = "BRK2";
306 | BRK3: statename = "BRK3";
307 | BRA0: statename = "BRA0";
308 | BRA1: statename = "BRA1";
309 | BRA2: statename = "BRA2";
310 | JMP0: statename = "JMP0";
311 | JMP1: statename = "JMP1";
312 | JMPI0: statename = "JMPI0";
313 | JMPI1: statename = "JMPI1";
314 | endcase
315 |
316 | //always @( PC )
317 | // $display( "%t, PC:%04x IR:%02x A:%02x X:%02x Y:%02x S:%02x C:%d Z:%d V:%d N:%d P:%02x", $time, PC, IR, A, X, Y, S, C, Z, V, N, P );
318 |
319 | `endif
320 |
321 |
322 |
323 | /*
324 | * Program Counter Increment/Load. First calculate the base value in
325 | * PC_temp.
326 | */
327 | always @*
328 | case( state )
329 | DECODE: if( (~I & IRQ) | NMI_edge )
330 | PC_temp = { ABH, ABL };
331 | else
332 | PC_temp = PC;
333 |
334 |
335 | JMP1,
336 | JMPI1,
337 | JSR3,
338 | RTS3,
339 | RTI4: PC_temp = { DIMUX, ADD };
340 |
341 | BRA1: PC_temp = { ABH, ADD };
342 |
343 | BRA2: PC_temp = { ADD, PCL };
344 |
345 | BRK2: PC_temp = res ? 16'hfffc :
346 | NMI_edge ? 16'hfffa : 16'hfffe;
347 |
348 | default: PC_temp = PC;
349 | endcase
350 |
351 | /*
352 | * Determine wether we need PC_temp, or PC_temp + 1
353 | */
354 | always @*
355 | case( state )
356 | DECODE: if( (~I & IRQ) | NMI_edge )
357 | PC_inc = 0;
358 | else
359 | PC_inc = 1;
360 |
361 | ABS0,
362 | ABSX0,
363 | FETCH,
364 | BRA0,
365 | BRA2,
366 | BRK3,
367 | JMPI1,
368 | JMP1,
369 | RTI4,
370 | RTS3: PC_inc = 1;
371 |
372 | BRA1: PC_inc = CO ^~ backwards;
373 |
374 | default: PC_inc = 0;
375 | endcase
376 |
377 | /*
378 | * Set new PC
379 | */
380 | always @(posedge clk)
381 | if( RDY )
382 | PC <= PC_temp + PC_inc;
383 |
384 | /*
385 | * Address Generator
386 | */
387 |
388 | parameter
389 | ZEROPAGE = 8'h00,
390 | STACKPAGE = 8'h01;
391 |
392 | always @*
393 | case( state )
394 | ABSX1,
395 | INDX3,
396 | INDY2,
397 | JMP1,
398 | JMPI1,
399 | RTI4,
400 | ABS1: AB = { DIMUX, ADD };
401 |
402 | BRA2,
403 | INDY3,
404 | ABSX2: AB = { ADD, ABL };
405 |
406 | BRA1: AB = { ABH, ADD };
407 |
408 | JSR0,
409 | PUSH1,
410 | RTS0,
411 | RTI0,
412 | BRK0: AB = { STACKPAGE, regfile };
413 |
414 | BRK1,
415 | JSR1,
416 | PULL1,
417 | RTS1,
418 | RTS2,
419 | RTI1,
420 | RTI2,
421 | RTI3,
422 | BRK2: AB = { STACKPAGE, ADD };
423 |
424 | INDY1,
425 | INDX1,
426 | ZPX1,
427 | INDX2: AB = { ZEROPAGE, ADD };
428 |
429 | ZP0,
430 | INDY0: AB = { ZEROPAGE, DIMUX };
431 |
432 | REG,
433 | READ,
434 | WRITE: AB = { ABH, ABL };
435 |
436 | default: AB = PC;
437 | endcase
438 |
439 | /*
440 | * ABH/ABL pair is used for registering previous address bus state.
441 | * This can be used to keep the current address, freeing up the original
442 | * source of the address, such as the ALU or DI.
443 | */
444 | always @(posedge clk)
445 | if( state != PUSH0 && state != PUSH1 && RDY &&
446 | state != PULL0 && state != PULL1 && state != PULL2 )
447 | begin
448 | ABL <= AB[7:0];
449 | ABH <= AB[15:8];
450 | end
451 |
452 | /*
453 | * Data Out MUX
454 | */
455 | always @*
456 | case( state )
457 | WRITE: DO = ADD;
458 |
459 | JSR0,
460 | BRK0: DO = PCH;
461 |
462 | JSR1,
463 | BRK1: DO = PCL;
464 |
465 | PUSH1: DO = php ? P : ADD;
466 |
467 | BRK2: DO = (IRQ | NMI_edge) ? (P & 8'b1110_1111) : P;
468 |
469 | default: DO = regfile;
470 | endcase
471 |
472 | /*
473 | * Write Enable Generator
474 | */
475 |
476 | always @*
477 | case( state )
478 | BRK0, // writing to stack or memory
479 | BRK1,
480 | BRK2,
481 | JSR0,
482 | JSR1,
483 | PUSH1,
484 | WRITE: WE = 1;
485 |
486 | INDX3, // only if doing a STA, STX or STY
487 | INDY3,
488 | ABSX2,
489 | ABS1,
490 | ZPX1,
491 | ZP0: WE = store;
492 |
493 | default: WE = 0;
494 | endcase
495 |
496 | /*
497 | * register file, contains A, X, Y and S (stack pointer) registers. At each
498 | * cycle only 1 of those registers needs to be accessed, so they combined
499 | * in a small memory, saving resources.
500 | */
501 |
502 | reg write_register; // set when register file is written
503 |
504 | always @*
505 | case( state )
506 | DECODE: write_register = load_reg & ~plp;
507 |
508 | PULL1,
509 | RTS2,
510 | RTI3,
511 | BRK3,
512 | JSR0,
513 | JSR2 : write_register = 1;
514 |
515 | default: write_register = 0;
516 | endcase
517 |
518 | /*
519 | * BCD adjust logic
520 | */
521 |
522 | always @(posedge clk)
523 | adj_bcd <= adc_sbc & D; // '1' when doing a BCD instruction
524 |
525 | reg [3:0] ADJL;
526 | reg [3:0] ADJH;
527 |
528 | // adjustment term to be added to ADD[3:0] based on the following
529 | // adj_bcd: '1' if doing ADC/SBC with D=1
530 | // adc_bcd: '1' if doing ADC with D=1
531 | // HC : half carry bit from ALU
532 | always @* begin
533 | casex( {adj_bcd, adc_bcd, HC} )
534 | 3'b0xx: ADJL = 4'd0; // no BCD instruction
535 | 3'b100: ADJL = 4'd10; // SBC, and digital borrow
536 | 3'b101: ADJL = 4'd0; // SBC, but no borrow
537 | 3'b110: ADJL = 4'd0; // ADC, but no carry
538 | 3'b111: ADJL = 4'd6; // ADC, and decimal/digital carry
539 | endcase
540 | end
541 |
542 | // adjustment term to be added to ADD[7:4] based on the following
543 | // adj_bcd: '1' if doing ADC/SBC with D=1
544 | // adc_bcd: '1' if doing ADC with D=1
545 | // CO : carry out bit from ALU
546 | always @* begin
547 | casex( {adj_bcd, adc_bcd, CO} )
548 | 3'b0xx: ADJH = 4'd0; // no BCD instruction
549 | 3'b100: ADJH = 4'd10; // SBC, and digital borrow
550 | 3'b101: ADJH = 4'd0; // SBC, but no borrow
551 | 3'b110: ADJH = 4'd0; // ADC, but no carry
552 | 3'b111: ADJH = 4'd6; // ADC, and decimal/digital carry
553 | endcase
554 | end
555 |
556 | /*
557 | * write to a register. Usually this is the (BCD corrected) output of the
558 | * ALU, but in case of the JSR0 we use the S register to temporarily store
559 | * the PCL. This is possible, because the S register itself is stored in
560 | * the ALU during those cycles.
561 | */
562 | always @(posedge clk)
563 | if( write_register & RDY )
564 | AXYS[regsel] <= (state == JSR0) ? DIMUX : { ADD[7:4] + ADJH, ADD[3:0] + ADJL };
565 |
566 | /*
567 | * register select logic. This determines which of the A, X, Y or
568 | * S registers will be accessed.
569 | */
570 |
571 | always @*
572 | case( state )
573 | INDY1,
574 | INDX0,
575 | ZPX0,
576 | ABSX0 : regsel = index_y ? SEL_Y : SEL_X;
577 |
578 |
579 | DECODE : regsel = dst_reg;
580 |
581 | BRK0,
582 | BRK3,
583 | JSR0,
584 | JSR2,
585 | PULL0,
586 | PULL1,
587 | PUSH1,
588 | RTI0,
589 | RTI3,
590 | RTS0,
591 | RTS2 : regsel = SEL_S;
592 |
593 | default: regsel = src_reg;
594 | endcase
595 |
596 | /*
597 | * ALU
598 | */
599 |
600 | ALU ALU( .clk(clk),
601 | .op(alu_op),
602 | .right(alu_shift_right),
603 | .AI(AI),
604 | .BI(BI),
605 | .CI(CI),
606 | .BCD(adc_bcd & (state == FETCH)),
607 | .CO(CO),
608 | .OUT(ADD),
609 | .V(AV),
610 | .Z(AZ),
611 | .N(AN),
612 | .HC(HC),
613 | .RDY(RDY) );
614 |
615 | /*
616 | * Select current ALU operation
617 | */
618 |
619 | always @*
620 | case( state )
621 | READ: alu_op = op;
622 |
623 | BRA1: alu_op = backwards ? OP_SUB : OP_ADD;
624 |
625 | FETCH,
626 | REG : alu_op = op;
627 |
628 | DECODE,
629 | ABS1: alu_op = 1'bx;
630 |
631 | PUSH1,
632 | BRK0,
633 | BRK1,
634 | BRK2,
635 | JSR0,
636 | JSR1: alu_op = OP_SUB;
637 |
638 | default: alu_op = OP_ADD;
639 | endcase
640 |
641 | /*
642 | * Determine shift right signal to ALU
643 | */
644 |
645 | always @*
646 | if( state == FETCH || state == REG || state == READ )
647 | alu_shift_right = shift_right;
648 | else
649 | alu_shift_right = 0;
650 |
651 | /*
652 | * Sign extend branch offset.
653 | */
654 |
655 | always @(posedge clk)
656 | if( RDY )
657 | backwards <= DIMUX[7];
658 |
659 | /*
660 | * ALU A Input MUX
661 | */
662 |
663 | always @*
664 | case( state )
665 | JSR1,
666 | RTS1,
667 | RTI1,
668 | RTI2,
669 | BRK1,
670 | BRK2,
671 | INDX1: AI = ADD;
672 |
673 | REG,
674 | ZPX0,
675 | INDX0,
676 | ABSX0,
677 | RTI0,
678 | RTS0,
679 | JSR0,
680 | JSR2,
681 | BRK0,
682 | PULL0,
683 | INDY1,
684 | PUSH0,
685 | PUSH1: AI = regfile;
686 |
687 | BRA0,
688 | READ: AI = DIMUX;
689 |
690 | BRA1: AI = ABH; // don't use PCH in case we're
691 |
692 | FETCH: AI = load_only ? 0 : regfile;
693 |
694 | DECODE,
695 | ABS1: AI = 8'hxx; // don't care
696 |
697 | default: AI = 0;
698 | endcase
699 |
700 |
701 | /*
702 | * ALU B Input mux
703 | */
704 |
705 | always @*
706 | case( state )
707 | BRA1,
708 | RTS1,
709 | RTI0,
710 | RTI1,
711 | RTI2,
712 | INDX1,
713 | READ,
714 | REG,
715 | JSR0,
716 | JSR1,
717 | JSR2,
718 | BRK0,
719 | BRK1,
720 | BRK2,
721 | PUSH0,
722 | PUSH1,
723 | PULL0,
724 | RTS0: BI = 8'h00;
725 |
726 | BRA0: BI = PCL;
727 |
728 | DECODE,
729 | ABS1: BI = 8'hxx;
730 |
731 | default: BI = DIMUX;
732 | endcase
733 |
734 | /*
735 | * ALU CI (carry in) mux
736 | */
737 |
738 | always @*
739 | case( state )
740 | INDY2,
741 | BRA1,
742 | ABSX1: CI = CO;
743 |
744 | DECODE,
745 | ABS1: CI = 1'bx;
746 |
747 | READ,
748 | REG: CI = rotate ? C :
749 | shift ? 0 : inc;
750 |
751 | FETCH: CI = rotate ? C :
752 | compare ? 1 :
753 | (shift | load_only) ? 0 : C;
754 |
755 | PULL0,
756 | RTI0,
757 | RTI1,
758 | RTI2,
759 | RTS0,
760 | RTS1,
761 | INDY0,
762 | INDX1: CI = 1;
763 |
764 | default: CI = 0;
765 | endcase
766 |
767 | /*
768 | * Processor Status Register update
769 | *
770 | */
771 |
772 | /*
773 | * Update C flag when doing ADC/SBC, shift/rotate, compare
774 | */
775 | always @(posedge clk )
776 | if( shift && state == WRITE )
777 | C <= CO;
778 | else if( state == RTI2 )
779 | C <= DIMUX[0];
780 | else if( ~write_back && state == DECODE ) begin
781 | if( adc_sbc | shift | compare )
782 | C <= CO;
783 | else if( plp )
784 | C <= ADD[0];
785 | else begin
786 | if( sec ) C <= 1;
787 | if( clc ) C <= 0;
788 | end
789 | end
790 |
791 | /*
792 | * Update Z, N flags when writing A, X, Y, Memory, or when doing compare
793 | */
794 |
795 | always @(posedge clk)
796 | if( state == WRITE )
797 | Z <= AZ;
798 | else if( state == RTI2 )
799 | Z <= DIMUX[1];
800 | else if( state == DECODE ) begin
801 | if( plp )
802 | Z <= ADD[1];
803 | else if( (load_reg & (regsel != SEL_S)) | compare | bit_ins )
804 | Z <= AZ;
805 | end
806 |
807 | always @(posedge clk)
808 | if( state == WRITE )
809 | N <= AN;
810 | else if( state == RTI2 )
811 | N <= DIMUX[7];
812 | else if( state == DECODE ) begin
813 | if( plp )
814 | N <= ADD[7];
815 | else if( (load_reg & (regsel != SEL_S)) | compare )
816 | N <= AN;
817 | end else if( state == FETCH && bit_ins )
818 | N <= DIMUX[7];
819 |
820 | /*
821 | * Update I flag
822 | */
823 |
824 | always @(posedge clk)
825 | if( state == BRK3 )
826 | I <= 1;
827 | else if( state == RTI2 )
828 | I <= DIMUX[2];
829 | else if( state == REG ) begin
830 | if( sei ) I <= 1;
831 | if( cli ) I <= 0;
832 | end else if( state == DECODE )
833 | if( plp ) I <= ADD[2];
834 |
835 | /*
836 | * Update D flag
837 | */
838 | always @(posedge clk )
839 | if( state == RTI2 )
840 | D <= DIMUX[3];
841 | else if( state == DECODE ) begin
842 | if( sed ) D <= 1;
843 | if( cld ) D <= 0;
844 | if( plp ) D <= ADD[3];
845 | end
846 |
847 | /*
848 | * Update V flag
849 | */
850 | always @(posedge clk )
851 | if( state == RTI2 )
852 | V <= DIMUX[6];
853 | else if( state == DECODE ) begin
854 | if( adc_sbc ) V <= AV;
855 | if( clv ) V <= 0;
856 | if( plp ) V <= ADD[6];
857 | end else if( state == FETCH && bit_ins )
858 | V <= DIMUX[6];
859 |
860 | /*
861 | * Instruction decoder
862 | */
863 |
864 | /*
865 | * IR register/mux. Hold previous DI value in IRHOLD in PULL0 and PUSH0
866 | * states. In these states, the IR has been prefetched, and there is no
867 | * time to read the IR again before the next decode.
868 | */
869 |
870 | always @(posedge clk )
871 | if( reset )
872 | IRHOLD_valid <= 0;
873 | else if( RDY ) begin
874 | if( state == PULL0 || state == PUSH0 ) begin
875 | IRHOLD <= DIMUX;
876 | IRHOLD_valid <= 1;
877 | end else if( state == DECODE )
878 | IRHOLD_valid <= 0;
879 | end
880 |
881 | assign IR = (IRQ & ~I) | NMI_edge ? 8'h00 :
882 | IRHOLD_valid ? IRHOLD : DIMUX;
883 |
884 | always @(posedge clk )
885 | if( RDY )
886 | DIHOLD <= DI;
887 |
888 | assign DIMUX = ~RDY ? DIHOLD : DI;
889 |
890 | /*
891 | * Microcode state machine
892 | */
893 | always @(posedge clk or posedge reset)
894 | if( reset )
895 | state <= BRK0;
896 | else if( RDY ) case( state )
897 | DECODE :
898 | casex ( IR )
899 | 8'b0000_0000: state <= BRK0;
900 | 8'b0010_0000: state <= JSR0;
901 | 8'b0010_1100: state <= ABS0; // BIT abs
902 | 8'b0100_0000: state <= RTI0; //
903 | 8'b0100_1100: state <= JMP0;
904 | 8'b0110_0000: state <= RTS0;
905 | 8'b0110_1100: state <= JMPI0;
906 | 8'b0x00_1000: state <= PUSH0;
907 | 8'b0x10_1000: state <= PULL0;
908 | 8'b0xx1_1000: state <= REG; // CLC, SEC, CLI, SEI
909 | 8'b1xx0_00x0: state <= FETCH; // IMM
910 | 8'b1xx0_1100: state <= ABS0; // X/Y abs
911 | 8'b1xxx_1000: state <= REG; // DEY, TYA, ...
912 | 8'bxxx0_0001: state <= INDX0;
913 | 8'bxxx0_01xx: state <= ZP0;
914 | 8'bxxx0_1001: state <= FETCH; // IMM
915 | 8'bxxx0_1101: state <= ABS0; // even E column
916 | 8'bxxx0_1110: state <= ABS0; // even E column
917 | 8'bxxx1_0000: state <= BRA0; // odd 0 column
918 | 8'bxxx1_0001: state <= INDY0; // odd 1 column
919 | 8'bxxx1_01xx: state <= ZPX0; // odd 4,5,6,7 columns
920 | 8'bxxx1_1001: state <= ABSX0; // odd 9 column
921 | 8'bxxx1_11xx: state <= ABSX0; // odd C, D, E, F columns
922 | 8'bxxxx_1010: state <= REG; // A, TXA, ... NOP
923 | endcase
924 |
925 | ZP0 : state <= write_back ? READ : FETCH;
926 |
927 | ZPX0 : state <= ZPX1;
928 | ZPX1 : state <= write_back ? READ : FETCH;
929 |
930 | ABS0 : state <= ABS1;
931 | ABS1 : state <= write_back ? READ : FETCH;
932 |
933 | ABSX0 : state <= ABSX1;
934 | ABSX1 : state <= (CO | store | write_back) ? ABSX2 : FETCH;
935 | ABSX2 : state <= write_back ? READ : FETCH;
936 |
937 | INDX0 : state <= INDX1;
938 | INDX1 : state <= INDX2;
939 | INDX2 : state <= INDX3;
940 | INDX3 : state <= FETCH;
941 |
942 | INDY0 : state <= INDY1;
943 | INDY1 : state <= INDY2;
944 | INDY2 : state <= (CO | store) ? INDY3 : FETCH;
945 | INDY3 : state <= FETCH;
946 |
947 | READ : state <= WRITE;
948 | WRITE : state <= FETCH;
949 | FETCH : state <= DECODE;
950 |
951 | REG : state <= DECODE;
952 |
953 | PUSH0 : state <= PUSH1;
954 | PUSH1 : state <= DECODE;
955 |
956 | PULL0 : state <= PULL1;
957 | PULL1 : state <= PULL2;
958 | PULL2 : state <= DECODE;
959 |
960 | JSR0 : state <= JSR1;
961 | JSR1 : state <= JSR2;
962 | JSR2 : state <= JSR3;
963 | JSR3 : state <= FETCH;
964 |
965 | RTI0 : state <= RTI1;
966 | RTI1 : state <= RTI2;
967 | RTI2 : state <= RTI3;
968 | RTI3 : state <= RTI4;
969 | RTI4 : state <= DECODE;
970 |
971 | RTS0 : state <= RTS1;
972 | RTS1 : state <= RTS2;
973 | RTS2 : state <= RTS3;
974 | RTS3 : state <= FETCH;
975 |
976 | BRA0 : state <= cond_true ? BRA1 : DECODE;
977 | BRA1 : state <= (CO ^ backwards) ? BRA2 : DECODE;
978 | BRA2 : state <= DECODE;
979 |
980 | JMP0 : state <= JMP1;
981 | JMP1 : state <= DECODE;
982 |
983 | JMPI0 : state <= JMPI1;
984 | JMPI1 : state <= JMP0;
985 |
986 | BRK0 : state <= BRK1;
987 | BRK1 : state <= BRK2;
988 | BRK2 : state <= BRK3;
989 | BRK3 : state <= JMP0;
990 |
991 | endcase
992 |
993 | /*
994 | * Additional control signals
995 | */
996 |
997 | always @(posedge clk)
998 | if( reset )
999 | res <= 1;
1000 | else if( state == DECODE )
1001 | res <= 0;
1002 |
1003 | always @(posedge clk)
1004 | if( state == DECODE && RDY )
1005 | casex( IR )
1006 | 8'b0xx01010, // ASLA, ROLA, LSRA, RORA
1007 | 8'b0xxxxx01, // ORA, AND, EOR, ADC
1008 | 8'b100x10x0, // DEY, TYA, TXA, TXS
1009 | 8'b1010xxx0, // LDA/LDX/LDY
1010 | 8'b10111010, // TSX
1011 | 8'b1011x1x0, // LDX/LDY
1012 | 8'b11001010, // DEX
1013 | 8'b1x1xxx01, // LDA, SBC
1014 | 8'bxxx01000: // DEY, TAY, INY, INX
1015 | load_reg <= 1;
1016 |
1017 | default: load_reg <= 0;
1018 | endcase
1019 |
1020 | always @(posedge clk)
1021 | if( state == DECODE && RDY )
1022 | casex( IR )
1023 | 8'b1110_1000, // INX
1024 | 8'b1100_1010, // DEX
1025 | 8'b101x_xx10: // LDX, TAX, TSX
1026 | dst_reg <= SEL_X;
1027 |
1028 | 8'b0x00_1000, // PHP, PHA
1029 | 8'b1001_1010: // TXS
1030 | dst_reg <= SEL_S;
1031 |
1032 | 8'b1x00_1000, // DEY, DEX
1033 | 8'b101x_x100, // LDY
1034 | 8'b1010_x000: // LDY #imm, TAY
1035 | dst_reg <= SEL_Y;
1036 |
1037 | default: dst_reg <= SEL_A;
1038 | endcase
1039 |
1040 | always @(posedge clk)
1041 | if( state == DECODE && RDY )
1042 | casex( IR )
1043 | 8'b1011_1010: // TSX
1044 | src_reg <= SEL_S;
1045 |
1046 | 8'b100x_x110, // STX
1047 | 8'b100x_1x10, // TXA, TXS
1048 | 8'b1110_xx00, // INX, CPX
1049 | 8'b1100_1010: // DEX
1050 | src_reg <= SEL_X;
1051 |
1052 | 8'b100x_x100, // STY
1053 | 8'b1001_1000, // TYA
1054 | 8'b1100_xx00, // CPY
1055 | 8'b1x00_1000: // DEY, INY
1056 | src_reg <= SEL_Y;
1057 |
1058 | default: src_reg <= SEL_A;
1059 | endcase
1060 |
1061 | always @(posedge clk)
1062 | if( state == DECODE && RDY )
1063 | casex( IR )
1064 | 8'bxxx1_0001, // INDY
1065 | 8'b10x1_x110, // LDX/STX zpg/abs, Y
1066 | 8'bxxxx_1001: // abs, Y
1067 | index_y <= 1;
1068 |
1069 | default: index_y <= 0;
1070 | endcase
1071 |
1072 |
1073 | always @(posedge clk)
1074 | if( state == DECODE && RDY )
1075 | casex( IR )
1076 | 8'b100x_x1x0, // STX, STY
1077 | 8'b100x_xx01: // STA
1078 | store <= 1;
1079 |
1080 | default: store <= 0;
1081 |
1082 | endcase
1083 |
1084 | always @(posedge clk )
1085 | if( state == DECODE && RDY )
1086 | casex( IR )
1087 | 8'b0xxx_x110, // ASL, ROL, LSR, ROR
1088 | 8'b11xx_x110: // DEC/INC
1089 | write_back <= 1;
1090 |
1091 | default: write_back <= 0;
1092 | endcase
1093 |
1094 |
1095 | always @(posedge clk )
1096 | if( state == DECODE && RDY )
1097 | casex( IR )
1098 | 8'b101x_xxxx: // LDA, LDX, LDY
1099 | load_only <= 1;
1100 | default: load_only <= 0;
1101 | endcase
1102 |
1103 | always @(posedge clk )
1104 | if( state == DECODE && RDY )
1105 | casex( IR )
1106 | 8'b111x_x110, // INC
1107 | 8'b11x0_1000: // INX, INY
1108 | inc <= 1;
1109 |
1110 | default: inc <= 0;
1111 | endcase
1112 |
1113 | always @(posedge clk )
1114 | if( (state == DECODE || state == BRK0) && RDY )
1115 | casex( IR )
1116 | 8'bx11x_xx01: // SBC, ADC
1117 | adc_sbc <= 1;
1118 |
1119 | default: adc_sbc <= 0;
1120 | endcase
1121 |
1122 | always @(posedge clk )
1123 | if( (state == DECODE || state == BRK0) && RDY )
1124 | casex( IR )
1125 | 8'b011x_xx01: // ADC
1126 | adc_bcd <= D;
1127 |
1128 | default: adc_bcd <= 0;
1129 | endcase
1130 |
1131 | always @(posedge clk )
1132 | if( state == DECODE && RDY )
1133 | casex( IR )
1134 | 8'b0xxx_x110, // ASL, ROL, LSR, ROR (abs, absx, zpg, zpgx)
1135 | 8'b0xxx_1010: // ASL, ROL, LSR, ROR (acc)
1136 | shift <= 1;
1137 |
1138 | default: shift <= 0;
1139 | endcase
1140 |
1141 | always @(posedge clk )
1142 | if( state == DECODE && RDY )
1143 | casex( IR )
1144 | 8'b11x0_0x00, // CPX, CPY (imm/zp)
1145 | 8'b11x0_1100, // CPX, CPY (abs)
1146 | 8'b110x_xx01: // CMP
1147 | compare <= 1;
1148 |
1149 | default: compare <= 0;
1150 | endcase
1151 |
1152 | always @(posedge clk )
1153 | if( state == DECODE && RDY )
1154 | casex( IR )
1155 | 8'b01xx_xx10: // ROR, LSR
1156 | shift_right <= 1;
1157 |
1158 | default: shift_right <= 0;
1159 | endcase
1160 |
1161 | always @(posedge clk )
1162 | if( state == DECODE && RDY )
1163 | casex( IR )
1164 | 8'b0x1x_1010, // ROL A, ROR A
1165 | 8'b0x1x_x110: // ROR, ROL
1166 | rotate <= 1;
1167 |
1168 | default: rotate <= 0;
1169 | endcase
1170 |
1171 | always @(posedge clk )
1172 | if( state == DECODE && RDY )
1173 | casex( IR )
1174 | 8'b00xx_xx10: // ROL, ASL
1175 | op <= OP_ROL;
1176 |
1177 | 8'b0010_x100: // BIT zp/abs
1178 | op <= OP_AND;
1179 |
1180 | 8'b01xx_xx10: // ROR, LSR
1181 | op <= OP_A;
1182 |
1183 | 8'b1000_1000, // DEY
1184 | 8'b1100_1010, // DEX
1185 | 8'b110x_x110, // DEC
1186 | 8'b11xx_xx01, // CMP, SBC
1187 | 8'b11x0_0x00, // CPX, CPY (imm, zpg)
1188 | 8'b11x0_1100: op <= OP_SUB;
1189 |
1190 | 8'b010x_xx01, // EOR
1191 | 8'b00xx_xx01: // ORA, AND
1192 | op <= { 2'b11, IR[6:5] };
1193 |
1194 | default: op <= OP_ADD;
1195 | endcase
1196 |
1197 | always @(posedge clk )
1198 | if( state == DECODE && RDY )
1199 | casex( IR )
1200 | 8'b0010_x100: // BIT zp/abs
1201 | bit_ins <= 1;
1202 |
1203 | default: bit_ins <= 0;
1204 | endcase
1205 |
1206 | /*
1207 | * special instructions
1208 | */
1209 | always @(posedge clk )
1210 | if( state == DECODE && RDY ) begin
1211 | php <= (IR == 8'h08);
1212 | clc <= (IR == 8'h18);
1213 | plp <= (IR == 8'h28);
1214 | sec <= (IR == 8'h38);
1215 | cli <= (IR == 8'h58);
1216 | sei <= (IR == 8'h78);
1217 | clv <= (IR == 8'hb8);
1218 | cld <= (IR == 8'hd8);
1219 | sed <= (IR == 8'hf8);
1220 | brk <= (IR == 8'h00);
1221 | end
1222 |
1223 | always @(posedge clk)
1224 | if( RDY )
1225 | cond_code <= IR[7:5];
1226 |
1227 | always @*
1228 | case( cond_code )
1229 | 3'b000: cond_true = ~N;
1230 | 3'b001: cond_true = N;
1231 | 3'b010: cond_true = ~V;
1232 | 3'b011: cond_true = V;
1233 | 3'b100: cond_true = ~C;
1234 | 3'b101: cond_true = C;
1235 | 3'b110: cond_true = ~Z;
1236 | 3'b111: cond_true = Z;
1237 | endcase
1238 |
1239 |
1240 | reg NMI_1 = 0; // delayed NMI signal
1241 |
1242 | always @(posedge clk)
1243 | NMI_1 <= NMI;
1244 |
1245 | always @(posedge clk )
1246 | if( NMI_edge && state == BRK3 )
1247 | NMI_edge <= 0;
1248 | else if( NMI & ~NMI_1 )
1249 | NMI_edge <= 1;
1250 |
1251 | endmodule
1252 |
--------------------------------------------------------------------------------
/verilog/mcu.v:
--------------------------------------------------------------------------------
1 |
2 |
3 | module mcu (
4 | input clock,
5 | input reset,
6 |
7 | inout [7:0] porta,
8 | inout [7:0] portb
9 | );
10 | ///////////////////////////////////////////////////////////////////////////
11 | ///////////////////////////////////////////////////////////////////////////
12 | ///
13 | /// Arlet 6502 Core
14 | ///
15 | ///////////////////////////////////////////////////////////////////////////
16 | ///////////////////////////////////////////////////////////////////////////
17 |
18 | // 6502 cpu interface
19 | wire [15:0] address_bus;
20 | wire [7:0] read_bus;
21 | wire [7:0] write_bus;
22 | wire write_enable;
23 | wire irq = 1'b0;
24 | wire nmi = 1'b0;
25 | wire ready;
26 |
27 | cpu cpu_inst (
28 | .clk(clock),
29 | .reset(reset),
30 | .AB(address_bus),
31 | .DI(read_bus),
32 | .DO(write_bus),
33 | .WE(write_enable),
34 | .IRQ(irq),
35 | .NMI(nmi),
36 | .RDY(ready)
37 | );
38 |
39 | // 6502 wishbone interface
40 | wire cpu_stb_o;
41 | wire cpu_we_o;
42 | wire [15:0] cpu_adr_o;
43 | wire [7:0] cpu_dat_o;
44 | wire cpu_ack_i;
45 | wire [7:0] cpu_dat_i;
46 |
47 | wb_6502_bridge wb_6502_bridge_inst (
48 | .clk_i(clock),
49 | .rst_i(reset),
50 | .stb_o(cpu_stb_o),
51 | .we_o(cpu_we_o),
52 | .adr_o(cpu_adr_o),
53 | .dat_o(cpu_dat_o),
54 | .ack_i(cpu_ack_i),
55 | .dat_i(cpu_dat_i),
56 | .address_bus(address_bus),
57 | .read_bus(read_bus),
58 | .write_bus(write_bus),
59 | .write_enable(write_enable),
60 | .ready(ready)
61 | );
62 |
63 |
64 |
65 | ///////////////////////////////////////////////////////////////////////////
66 | ///////////////////////////////////////////////////////////////////////////
67 | ///
68 | /// RAM
69 | ///
70 | ///////////////////////////////////////////////////////////////////////////
71 | ///////////////////////////////////////////////////////////////////////////
72 | wire ram_stb_i;
73 | wire ram_we_i;
74 | wire [15:0] ram_adr_i;
75 | wire [7:0] ram_dat_i;
76 | wire ram_ack_o;
77 | wire [7:0] ram_dat_o;
78 |
79 | wb_ram #(
80 | .WB_DATA_WIDTH(8),
81 | .WB_ADDR_WIDTH(9),
82 | .WB_ALWAYS_READ(1),
83 | .RAM_DEPTH(512)
84 | ) main_ram (
85 | .clk_i(clock),
86 | .rst_i(reset),
87 | .stb_i(ram_stb_i),
88 | .we_i(ram_we_i),
89 | .adr_i(ram_adr_i),
90 | .dat_i(ram_dat_i),
91 | .ack_o(ram_ack_o),
92 | .dat_o(ram_dat_o)
93 | );
94 |
95 | integer i;
96 | initial begin
97 | for (i = 0; i < 512; i = i + 1) begin
98 | main_ram.ram[i] = 0;
99 | end
100 | end
101 |
102 |
103 |
104 | ///////////////////////////////////////////////////////////////////////////
105 | ///////////////////////////////////////////////////////////////////////////
106 | ///
107 | /// ROM
108 | ///
109 | ///////////////////////////////////////////////////////////////////////////
110 | ///////////////////////////////////////////////////////////////////////////
111 | wire rom_stb_i;
112 | wire rom_we_i;
113 | wire [15:0] rom_adr_i;
114 | wire [7:0] rom_dat_i;
115 | wire rom_ack_o;
116 | wire [7:0] rom_dat_o;
117 |
118 | wb_ram #(
119 | .WB_DATA_WIDTH(8),
120 | .WB_ADDR_WIDTH(9),
121 | .WB_ALWAYS_READ(1),
122 | .RAM_DEPTH(512)
123 | ) main_rom (
124 | .clk_i(clock),
125 | .rst_i(reset),
126 | .stb_i(rom_stb_i),
127 | .we_i(rom_we_i),
128 | .adr_i(rom_adr_i),
129 | .dat_i(rom_dat_i),
130 | .ack_o(rom_ack_o),
131 | .dat_o(rom_dat_o)
132 | );
133 |
134 | integer j;
135 | initial begin
136 | for (j = 0; j < 512; j = j + 1) begin
137 | main_rom.ram[j] = 0;
138 | end
139 |
140 | main_rom.ram[0] = 8'ha9;
141 | main_rom.ram[1] = 8'hff;
142 | main_rom.ram[2] = 8'h8d;
143 | main_rom.ram[3] = 8'h00;
144 | main_rom.ram[4] = 8'hf0;
145 | main_rom.ram[5] = 8'ha9;
146 | main_rom.ram[6] = 8'h01;
147 | main_rom.ram[7] = 8'hee;
148 | main_rom.ram[8] = 8'h02;
149 | main_rom.ram[9] = 8'hf0;
150 | main_rom.ram[10] = 8'h4c; // JMP
151 | main_rom.ram[11] = 8'h07;
152 | main_rom.ram[12] = 8'hfe;
153 |
154 | main_rom.ram[9'h1fe] = 8'h00;
155 | main_rom.ram[9'h1ff] = 8'hfe;
156 | end
157 |
158 |
159 |
160 | ///////////////////////////////////////////////////////////////////////////
161 | ///////////////////////////////////////////////////////////////////////////
162 | ///
163 | /// 6522 VIA
164 | ///
165 | ///////////////////////////////////////////////////////////////////////////
166 | ///////////////////////////////////////////////////////////////////////////
167 | wire via_stb_i;
168 | wire via_we_i;
169 | wire [15:0] via_adr_i;
170 | wire [7:0] via_dat_i;
171 | wire via_ack_o;
172 | wire [7:0] via_dat_o;
173 |
174 | wb_6522_via #(
175 | .WB_DATA_WIDTH(8),
176 | .WB_ADDR_WIDTH(4)
177 | ) wb_6522_via_inst (
178 | .clk_i(clock),
179 | .rst_i(reset),
180 | .stb_i(via_stb_i),
181 | .we_i(via_we_i),
182 | .adr_i(via_adr_i),
183 | .dat_i(via_dat_i),
184 | .ack_o(via_ack_o),
185 | .dat_o(via_dat_o),
186 |
187 | //.irq(),
188 | //.ca2(),
189 | //.ca1(),
190 | //.cb2(),
191 | //.cb1(),
192 |
193 | .port_a(port_a),
194 | .port_b(port_b)
195 | );
196 |
197 |
198 |
199 |
200 | ///////////////////////////////////////////////////////////////////////////
201 | ///////////////////////////////////////////////////////////////////////////
202 | ///
203 | /// PORTB
204 | ///
205 | ///////////////////////////////////////////////////////////////////////////
206 | ///////////////////////////////////////////////////////////////////////////
207 | wire portb_stb_i;
208 | wire portb_we_i;
209 | wire [15:0] portb_adr_i;
210 | wire [7:0] portb_dat_i;
211 | wire portb_ack_o;
212 | wire [7:0] portb_dat_o;
213 |
214 | wb_gpio #(
215 | .WB_DATA_WIDTH(8),
216 | .WB_ADDR_WIDTH(2)
217 | ) portb_inst (
218 | .clk_i(clock),
219 | .rst_i(reset),
220 | .stb_i(portb_stb_i),
221 | .we_i(portb_we_i),
222 | .adr_i(portb_adr_i),
223 | .dat_i(portb_dat_i),
224 | .ack_o(portb_ack_o),
225 | .dat_o(portb_dat_o),
226 | .gpio(portb)
227 | );
228 |
229 |
230 |
231 | ///////////////////////////////////////////////////////////////////////////
232 | ///////////////////////////////////////////////////////////////////////////
233 | ///
234 | /// Wishbone Bus
235 | ///
236 | ///////////////////////////////////////////////////////////////////////////
237 | ///////////////////////////////////////////////////////////////////////////
238 | wb_bus #(
239 | .WB_DATA_WIDTH(8),
240 | .WB_ADDR_WIDTH(16),
241 | .WB_NUM_SLAVES(4)
242 | ) bus (
243 | // syscon
244 | .clk_i(clock),
245 | .rst_i(reset),
246 |
247 | // connection to wishbone master
248 | .mstr_stb_i(cpu_stb_o),
249 | .mstr_we_i(cpu_we_o),
250 | .mstr_adr_i(cpu_adr_o),
251 | .mstr_dat_i(cpu_dat_o),
252 | .mstr_ack_o(cpu_ack_i),
253 | .mstr_dat_o(cpu_dat_i),
254 |
255 | // wishbone slave decode RAM ROM PORTA PORTB
256 | .bus_slv_addr_decode_value({16'h0000, 16'hFE00, 16'hF000, 16'hF004}),
257 | .bus_slv_addr_decode_mask ({16'hFE00, 16'hFE00, 16'hFFFC, 16'hFFFC}),
258 |
259 | // connection to wishbone slaves
260 | .slv_stb_o ({ram_stb_i, rom_stb_i, porta_stb_i, portb_stb_i}),
261 | .slv_we_o ({ram_we_i, rom_we_i, porta_we_i, portb_we_i}),
262 | .slv_adr_o ({ram_adr_i, rom_adr_i, porta_adr_i, portb_adr_i}),
263 | .slv_dat_o ({ram_dat_i, rom_dat_i, porta_dat_i, portb_dat_i}),
264 | .slv_ack_i ({ram_ack_o, rom_ack_o, porta_ack_o, portb_ack_o}),
265 | .slv_dat_i ({ram_dat_o, rom_dat_o, porta_dat_o, portb_dat_o})
266 | );
267 | endmodule
268 |
269 | module mcu_test;
270 | reg clock;
271 | reg reset;
272 | wire [7:0] porta;
273 | wire [7:0] portb;
274 |
275 | mcu dut(
276 | .clock(clock),
277 | .reset(reset),
278 | .porta(porta),
279 | .portb(portb)
280 | );
281 |
282 | initial begin
283 | clock <= 0;
284 | #100;
285 |
286 | while (1) begin
287 | clock <= !clock;
288 | #100;
289 | end
290 | end
291 |
292 | initial begin
293 | reset <= 1;
294 |
295 | #1000;
296 |
297 | reset <= 0;
298 | end
299 |
300 | initial begin
301 | $dumpvars;
302 | end
303 | endmodule
304 |
--------------------------------------------------------------------------------
/verilog/wb_6502_bridge.v:
--------------------------------------------------------------------------------
1 | /*
2 | * Wishbone adapter for Arlet's 6502 core: https://github.com/Arlet/verilog-6502
3 | */
4 | module wb_6502_bridge #(
5 | parameter WB_DATA_WIDTH = 8,
6 | parameter WB_ADDR_WIDTH = 16
7 | ) (
8 | // wishbone interface
9 | input clk_i,
10 | input rst_i,
11 |
12 | output stb_o,
13 | output we_o,
14 | output [WB_ADDR_WIDTH-1:0] adr_o,
15 | output [WB_DATA_WIDTH-1:0] dat_o,
16 |
17 | input ack_i,
18 | input [WB_DATA_WIDTH-1:0] dat_i,
19 |
20 | // 6502 interface
21 | input [15:0] address_bus,
22 | output [7:0] read_bus,
23 | input [7:0] write_bus,
24 | input write_enable,
25 | output ready
26 | );
27 | reg req_in_progress;
28 |
29 | wire stall = req_in_progress && !ack_i;
30 | wire req_initiated = !stall;
31 |
32 | // outputs to wb
33 | assign stb_o = req_initiated;
34 | assign we_o = write_enable;
35 | assign adr_o = address_bus;
36 | assign dat_o = write_bus;
37 |
38 | // outputs to 6502
39 | assign read_bus = dat_i;
40 | assign ready = req_initiated;
41 |
42 | always @(posedge clk_i) begin
43 | if (rst_i) begin
44 | req_in_progress <= 0;
45 |
46 | end else begin
47 | if (ack_i) begin
48 | req_in_progress <= 0;
49 | end
50 |
51 | if (req_initiated) begin
52 | req_in_progress <= 1;
53 | end
54 | end
55 | end
56 | endmodule
57 |
58 | module wb_6502_bridge_test;
59 | // wishbone interface
60 | reg clk_i;
61 | reg rst_i;
62 |
63 | wire stb_o;
64 | wire we_o;
65 | wire [15:0] adr_o;
66 | wire [7:0] dat_o;
67 |
68 | reg ack_i;
69 | reg [7:0] dat_i;
70 |
71 | // 6502 interface
72 | reg [15:0] address_bus;
73 | wire [7:0] read_bus;
74 | reg [7:0] write_bus;
75 | reg write_enable;
76 | wire ready;
77 |
78 | wb_6502_bridge dut(
79 | .clk_i(clk_i),
80 | .rst_i(rst_i),
81 | .stb_o(stb_o),
82 | .we_o(we_o),
83 | .adr_o(adr_o),
84 | .dat_o(dat_o),
85 | .ack_i(ack_i),
86 | .dat_i(dat_i),
87 | .address_bus(address_bus),
88 | .read_bus(read_bus),
89 | .write_bus(write_bus),
90 | .write_enable(write_enable),
91 | .ready(ready)
92 | );
93 |
94 | task clk;
95 | begin
96 | @(posedge clk_i);
97 | end
98 | endtask
99 |
100 | task run_clk(input integer cycles);
101 | integer i;
102 | begin
103 | for (i = 0; i < cycles; i = i + 1) begin
104 | clk();
105 | end
106 | end
107 | endtask
108 |
109 | task reset;
110 | begin
111 | rst_i <= 1'b1;
112 | run_clk(10);
113 | rst_i <= 1'b0;
114 | end
115 | endtask
116 |
117 | initial begin
118 | $dumpvars;
119 | ack_i <= 0;
120 | reset();
121 |
122 | run_clk(10);
123 |
124 | ack_i <= 1;
125 | run_clk(10);
126 |
127 | ack_i <= 0;
128 | run_clk(1);
129 |
130 | ack_i <= 1;
131 | run_clk(10);
132 |
133 | $finish(1);
134 | end
135 |
136 | initial begin
137 | clk_i <= 0;
138 | #1;
139 |
140 | while (1) begin
141 | clk_i <= !clk_i;
142 | #100;
143 | end
144 | end
145 | endmodule
146 |
147 |
148 |
--------------------------------------------------------------------------------
/verilog/wb_6522_via.v:
--------------------------------------------------------------------------------
1 | /*
2 | * Wishbone compliant 6522 Versatile Interface Adapter model.
3 | *
4 | * https://en.wikipedia.org/wiki/MOS_Technology_6522
5 | * http://archive.6502.org/datasheets/mos_6522_preliminary_nov_1977.pdf
6 | * http://www.westerndesigncenter.com/wdc/documentation/w65c22.pdf
7 | */
8 | module wb_6522_via #(
9 | parameter WB_DATA_WIDTH = 8,
10 | parameter WB_ADDR_WIDTH = 4
11 | ) (
12 | // wishbone interface
13 | input clk_i,
14 | input rst_i,
15 |
16 | input stb_i,
17 | input we_i,
18 | input [WB_ADDR_WIDTH-1:0] adr_i,
19 | input [WB_DATA_WIDTH-1:0] dat_i,
20 |
21 | output reg ack_o,
22 | output reg [WB_DATA_WIDTH-1:0] dat_o,
23 |
24 | // interrupt interface
25 | output irq,
26 |
27 | // gpio interface
28 | inout [WB_DATA_WIDTH-1:0] port_a,
29 | inout [WB_DATA_WIDTH-1:0] port_b,
30 |
31 | // handshake and serial io
32 | inout ca2,
33 | input ca1,
34 | inout cb2,
35 | inout cb1
36 | );
37 | initial ack_o = 0;
38 | initial dat_o = 0;
39 |
40 | reg [WB_DATA_WIDTH-1:0] IORB_R = 0;
41 | reg [WB_DATA_WIDTH-1:0] IORB_W = 0;
42 | reg [WB_DATA_WIDTH-1:0] IORA_R = 0;
43 | reg [WB_DATA_WIDTH-1:0] IORA_W = 0;
44 | reg [WB_DATA_WIDTH-1:0] DDRB = 0;
45 | reg [WB_DATA_WIDTH-1:0] DDRA = 0;
46 | reg [WB_DATA_WIDTH-1:0] T1CL_R = 0;
47 | reg [WB_DATA_WIDTH-1:0] T1CL_W = 0;
48 | reg [WB_DATA_WIDTH-1:0] T1CH = 0;
49 | reg [WB_DATA_WIDTH-1:0] T1LL = 0;
50 | reg [WB_DATA_WIDTH-1:0] T1LH = 0;
51 | reg [WB_DATA_WIDTH-1:0] T2CL_R = 0;
52 | reg [WB_DATA_WIDTH-1:0] T2CL_W = 0;
53 | reg [WB_DATA_WIDTH-1:0] T2CH = 0;
54 | reg [WB_DATA_WIDTH-1:0] SR = 0;
55 | reg [WB_DATA_WIDTH-1:0] ACR = 0;
56 | reg [WB_DATA_WIDTH-1:0] PCR = 0;
57 | reg [WB_DATA_WIDTH-1:0] IFR = 0;
58 | reg [WB_DATA_WIDTH-1:0] IER = 0;
59 | reg [WB_DATA_WIDTH-1:0] IORANH_R = 0;
60 | reg [WB_DATA_WIDTH-1:0] IORANH_W = 0;
61 |
62 | wire valid_cmd = !rst_i && stb_i;
63 | wire valid_write_cmd = valid_cmd && we_i;
64 | wire valid_read_cmd = valid_cmd && !we_i;
65 |
66 | wire port_a_input_latching_enabled = 0; // FIXME: need to assign this a value
67 | wire latch_port_a = 0; // FIXME: need to assign this a value
68 | wire port_b_input_latching_enabled = 0; // FIXME: need to assign this a value
69 | wire latch_port_b = 0; // FIXME: need to assign this a value
70 |
71 | // handle wishbone interface
72 | always @(posedge clk_i) begin
73 | // flop input data depending on input latch settings
74 | if ((port_a_input_latching_enabled && latch_port_a) || !port_a_input_latching_enabled) begin
75 | IORA_R <= port_a;
76 | end
77 |
78 | if ((port_b_input_latching_enabled && latch_port_b) || !port_b_input_latching_enabled) begin
79 | IORB_R <= port_b;
80 | end
81 |
82 | // register read path
83 | if (valid_read_cmd) begin
84 | case (adr_i)
85 | 4'h0: dat_o <= IORB_R;
86 | 4'h1: dat_o <= IORA_R;
87 | 4'h2: dat_o <= DDRB;
88 | 4'h3: dat_o <= DDRA;
89 | 4'h4: dat_o <= T1CL_R;
90 | 4'h5: dat_o <= T1CH;
91 | 4'h6: dat_o <= T1LL;
92 | 4'h7: dat_o <= T1LH;
93 | 4'h8: dat_o <= T2CL_R;
94 | 4'h9: dat_o <= T2CH;
95 | 4'ha: dat_o <= SR;
96 | 4'hb: dat_o <= ACR;
97 | 4'hc: dat_o <= PCR;
98 | 4'hd: dat_o <= IFR;
99 | 4'he: dat_o <= IER;
100 | 4'hf: dat_o <= IORANH_R;
101 | endcase
102 | end
103 |
104 | // register write path
105 | if (valid_write_cmd) begin
106 | case (adr_i)
107 | 4'h0: IORB_W <= dat_i;
108 | 4'h1: IORA_W <= dat_i;
109 | 4'h2: DDRB <= dat_i;
110 | 4'h3: DDRA <= dat_i;
111 | 4'h4: T1CL_W <= dat_i;
112 | 4'h5: T1CH <= dat_i;
113 | 4'h6: T1LL <= dat_i;
114 | 4'h7: T1LH <= dat_i;
115 | 4'h8: T2CL_W <= dat_i;
116 | 4'h9: T2CH <= dat_i;
117 | 4'ha: SR <= dat_i;
118 | 4'hb: ACR <= dat_i;
119 | 4'hc: PCR <= dat_i;
120 | 4'hd: IFR <= dat_i;
121 | 4'he: IER <= dat_i;
122 | 4'hf: IORANH_W <= dat_i;
123 | endcase
124 | end
125 |
126 | // acknowledge valid commands
127 | ack_o <= valid_cmd;
128 | end
129 |
130 | // handle gpios
131 | genvar i;
132 | generate
133 | for (i = 0; i < WB_DATA_WIDTH; i = i + 1) begin
134 | // DDR[i] == 0 -> DDR[i] is an input pin
135 | // DDR[i] == 1 -> DDR[i] is an output pin
136 | assign port_a[i] = DDRA[i] ? IORA_W[i] : 1'bz;
137 | assign port_b[i] = DDRB[i] ? IORB_W[i] : 1'bz;
138 | end
139 | endgenerate
140 | endmodule
141 |
--------------------------------------------------------------------------------
/verilog/wb_bus.v:
--------------------------------------------------------------------------------
1 | /*
2 | * Wishbone compliant bus with support for one master and multiple slaves.
3 | */
4 | module wb_bus #(
5 | parameter WB_DATA_WIDTH = 8,
6 | parameter WB_ADDR_WIDTH = 16,
7 | parameter WB_NUM_SLAVES = 1
8 | ) (
9 | // syscon
10 | input clk_i,
11 | input rst_i,
12 |
13 | // connection to wishbone master
14 | input mstr_cyc_i,
15 | input mstr_lock_i,
16 | input mstr_stb_i,
17 | input mstr_we_i,
18 | input [WB_ADDR_WIDTH-1:0] mstr_adr_i,
19 | input [WB_DATA_WIDTH-1:0] mstr_dat_i,
20 |
21 | output mstr_stall_o,
22 | output mstr_ack_o,
23 | output [WB_DATA_WIDTH-1:0] mstr_dat_o,
24 |
25 | // wishbone slave decode
26 | input [(WB_ADDR_WIDTH*WB_NUM_SLAVES)-1:0] bus_slv_addr_decode_value,
27 | input [(WB_ADDR_WIDTH*WB_NUM_SLAVES)-1:0] bus_slv_addr_decode_mask,
28 |
29 | // connection to wishbone slaves
30 | output [WB_NUM_SLAVES-1:0] slv_cyc_o,
31 | output [WB_NUM_SLAVES-1:0] slv_lock_o,
32 | output [WB_NUM_SLAVES-1:0] slv_stb_o,
33 | output [WB_NUM_SLAVES-1:0] slv_we_o,
34 | output [(WB_ADDR_WIDTH*WB_NUM_SLAVES)-1:0] slv_adr_o,
35 | output [(WB_DATA_WIDTH*WB_NUM_SLAVES)-1:0] slv_dat_o,
36 |
37 | input [WB_NUM_SLAVES-1:0] slv_stall_i,
38 | input [WB_NUM_SLAVES-1:0] slv_ack_i,
39 | input [(WB_DATA_WIDTH*WB_NUM_SLAVES)-1:0] slv_dat_i
40 | );
41 | wor mstr_stall_o_wor;
42 | wor mstr_ack_o_wor;
43 | wor [WB_DATA_WIDTH-1:0] mstr_dat_o_wor;
44 |
45 | assign mstr_stall_o = mstr_stall_o_wor;
46 | assign mstr_ack_o = mstr_ack_o_wor;
47 | assign mstr_dat_o = mstr_dat_o_wor;
48 |
49 | wire [WB_NUM_SLAVES-1:0] req_slv_select;
50 | reg [WB_NUM_SLAVES-1:0] ack_slv_select;
51 |
52 | always @(posedge clk_i) begin
53 | ack_slv_select <= req_slv_select;
54 | end
55 |
56 | genvar i;
57 | generate
58 | for (i = 0; i < WB_NUM_SLAVES; i = i + 1) begin
59 | // decode slave addresses
60 | assign req_slv_select[i] =
61 | (bus_slv_addr_decode_value[i * WB_ADDR_WIDTH +: WB_ADDR_WIDTH]) ==
62 | (bus_slv_addr_decode_mask [i * WB_ADDR_WIDTH +: WB_ADDR_WIDTH] & mstr_adr_i);
63 |
64 | // drive slave signals
65 | assign slv_cyc_o[i] = mstr_cyc_i;
66 | assign slv_lock_o[i] = mstr_lock_i;
67 | assign slv_stb_o[i] = mstr_stb_i & req_slv_select[i];
68 | assign slv_we_o[i] = mstr_we_i;
69 | assign slv_adr_o[i * WB_ADDR_WIDTH +: WB_ADDR_WIDTH] = mstr_adr_i;
70 | assign slv_dat_o[i * WB_DATA_WIDTH +: WB_DATA_WIDTH] = mstr_dat_i;
71 |
72 | // drive master wor signals
73 | assign mstr_stall_o_wor = ack_slv_select[i] ? slv_stall_i[i] : 0;
74 | assign mstr_ack_o_wor = ack_slv_select[i] ? slv_ack_i[i] : 0;
75 | assign mstr_dat_o_wor = ack_slv_select[i] ? slv_dat_i[i * WB_DATA_WIDTH +: WB_DATA_WIDTH] : 0;
76 | end
77 | endgenerate
78 | endmodule
79 |
80 |
--------------------------------------------------------------------------------
/verilog/wb_gpio.v:
--------------------------------------------------------------------------------
1 | /*
2 | * Wishbone compliant GPIO port similiar to AVR ports.
3 | */
4 | module wb_gpio #(
5 | parameter WB_DATA_WIDTH = 8,
6 | parameter WB_ADDR_WIDTH = 2
7 | ) (
8 | // wishbone interface
9 | input clk_i,
10 | input rst_i,
11 |
12 | input stb_i,
13 | input we_i,
14 | input [WB_ADDR_WIDTH-1:0] adr_i,
15 | input [WB_DATA_WIDTH-1:0] dat_i,
16 |
17 | output reg ack_o,
18 | output reg [WB_DATA_WIDTH-1:0] dat_o,
19 |
20 | // gpio interface
21 | inout [WB_DATA_WIDTH-1:0] gpio
22 | );
23 | initial ack_o = 0;
24 | initial dat_o = 0;
25 |
26 | reg [WB_DATA_WIDTH-1:0] data_direction_register = 0;
27 | reg [WB_DATA_WIDTH-1:0] input_data_register = 0;
28 | reg [WB_DATA_WIDTH-1:0] output_data_register = 0;
29 |
30 | wire valid_cmd = !rst_i && stb_i;
31 | wire valid_write_cmd = valid_cmd && we_i;
32 | wire valid_read_cmd = valid_cmd && !we_i;
33 |
34 | // handle wishbone interface
35 | always @(posedge clk_i) begin
36 | // always flop input data
37 | input_data_register <= gpio;
38 |
39 | // register read path
40 | if (valid_read_cmd) begin
41 | case (adr_i)
42 | 0: begin
43 | dat_o <= data_direction_register;
44 | end
45 |
46 | 1: begin
47 | dat_o <= input_data_register;
48 | end
49 |
50 | 2: begin
51 | dat_o <= output_data_register;
52 | end
53 | endcase
54 | end
55 |
56 | // register write path
57 | if (valid_write_cmd) begin
58 | case (adr_i)
59 | 0: begin
60 | data_direction_register <= dat_i;
61 | end
62 |
63 | 2: begin
64 | output_data_register <= dat_i;
65 | end
66 | endcase
67 | end
68 |
69 | // acknowledge valid commands
70 | ack_o <= valid_cmd;
71 | end
72 |
73 | // handle gpio
74 | genvar i;
75 | generate
76 | for (i = 0; i < WB_DATA_WIDTH; i = i + 1) begin
77 | assign gpio[i] = data_direction_register[i] ? output_data_register[i] : 1'bz;
78 | end
79 | endgenerate
80 | endmodule
81 |
--------------------------------------------------------------------------------
/verilog/wb_ram.v:
--------------------------------------------------------------------------------
1 | /*
2 | * Simple Wishbone compliant RAM module.
3 | */
4 | module wb_ram #(
5 | parameter WB_DATA_WIDTH = 8,
6 | parameter WB_ADDR_WIDTH = 9,
7 | parameter WB_ALWAYS_READ = 1,
8 | parameter RAM_DEPTH = 512
9 | ) (
10 | // wishbone interface
11 | input clk_i,
12 | input rst_i,
13 |
14 | input stb_i,
15 | input we_i,
16 | input [WB_ADDR_WIDTH-1:0] adr_i,
17 | input [WB_DATA_WIDTH-1:0] dat_i,
18 |
19 | output reg ack_o,
20 | output reg [WB_DATA_WIDTH-1:0] dat_o
21 | );
22 | reg [WB_DATA_WIDTH-1:0] ram [RAM_DEPTH-1:0];
23 |
24 | wire valid_cmd = !rst_i && stb_i;
25 | wire valid_write_cmd = valid_cmd && we_i;
26 | wire valid_read_cmd = valid_cmd && !we_i;
27 |
28 | always @(posedge clk_i) begin
29 | if (valid_read_cmd || WB_ALWAYS_READ) begin
30 | dat_o <= ram[adr_i];
31 | end
32 |
33 | if (valid_write_cmd) begin
34 | ram[adr_i] <= dat_i;
35 | end
36 |
37 | ack_o <= valid_cmd;
38 | end
39 | endmodule
40 |
--------------------------------------------------------------------------------