├── .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 | --------------------------------------------------------------------------------