| 1 |
61 |
creep |
////////////////////////////////////////////////////////////////////////////
|
| 2 |
|
|
//// ////
|
| 3 |
|
|
//// T6507LP IP Core ////
|
| 4 |
|
|
//// ////
|
| 5 |
|
|
//// This file is part of the T6507LP project ////
|
| 6 |
|
|
//// http://www.opencores.org/cores/t6507lp/ ////
|
| 7 |
|
|
//// ////
|
| 8 |
|
|
//// Description ////
|
| 9 |
|
|
//// 6507 FSM ////
|
| 10 |
|
|
//// ////
|
| 11 |
|
|
//// TODO: ////
|
| 12 |
|
|
//// - Fix absolute indexed mode ////
|
| 13 |
|
|
//// - Code the relative mode ////
|
| 14 |
|
|
//// - Code the indexed indirect mode ////
|
| 15 |
|
|
//// - Code the indirect indexed mode ////
|
| 16 |
|
|
//// - Code the absolute indirect mode ////
|
| 17 |
|
|
//// ////
|
| 18 |
|
|
//// Author(s): ////
|
| 19 |
|
|
//// - Gabriel Oshiro Zardo, gabrieloshiro@gmail.com ////
|
| 20 |
|
|
//// - Samuel Nascimento Pagliarini (creep), snpagliarini@gmail.com ////
|
| 21 |
|
|
//// ////
|
| 22 |
|
|
////////////////////////////////////////////////////////////////////////////
|
| 23 |
|
|
//// ////
|
| 24 |
|
|
//// Copyright (C) 2001 Authors and OPENCORES.ORG ////
|
| 25 |
|
|
//// ////
|
| 26 |
|
|
//// This source file may be used and distributed without ////
|
| 27 |
|
|
//// restriction provided that this copyright statement is not ////
|
| 28 |
|
|
//// removed from the file and that any derivative work contains ////
|
| 29 |
|
|
//// the original copyright notice and the associated disclaimer. ////
|
| 30 |
|
|
//// ////
|
| 31 |
|
|
//// This source file is free software; you can redistribute it ////
|
| 32 |
|
|
//// and/or modify it under the terms of the GNU Lesser General ////
|
| 33 |
|
|
//// Public License as published by the Free Software Foundation; ////
|
| 34 |
|
|
//// either version 2.1 of the License, or (at your option) any ////
|
| 35 |
|
|
//// later version. ////
|
| 36 |
|
|
//// ////
|
| 37 |
|
|
//// This source is distributed in the hope that it will be ////
|
| 38 |
|
|
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
|
| 39 |
|
|
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
|
| 40 |
|
|
//// PURPOSE. See the GNU Lesser General Public License for more ////
|
| 41 |
|
|
//// details. ////
|
| 42 |
|
|
//// ////
|
| 43 |
|
|
//// You should have received a copy of the GNU Lesser General ////
|
| 44 |
|
|
//// Public License along with this source; if not, download it ////
|
| 45 |
|
|
//// from http://www.opencores.org/lgpl.shtml ////
|
| 46 |
|
|
//// ////
|
| 47 |
|
|
////////////////////////////////////////////////////////////////////////////
|
| 48 |
|
|
|
| 49 |
|
|
`timescale 1ns / 1ps
|
| 50 |
|
|
|
| 51 |
86 |
creep |
module t6507lp_fsm(clk, reset_n, alu_result, alu_status, data_in, address, control, data_out, alu_opcode, alu_a, alu_enable, alu_x, alu_y);
|
| 52 |
87 |
creep |
parameter DATA_SIZE = 8;
|
| 53 |
|
|
parameter ADDR_SIZE = 13;
|
| 54 |
68 |
creep |
|
| 55 |
83 |
creep |
localparam DATA_SIZE_ = DATA_SIZE - 4'b0001;
|
| 56 |
|
|
localparam ADDR_SIZE_ = ADDR_SIZE - 4'b0001;
|
| 57 |
82 |
creep |
|
| 58 |
71 |
creep |
input clk;
|
| 59 |
|
|
input reset_n;
|
| 60 |
82 |
creep |
input [DATA_SIZE_:0] alu_result;
|
| 61 |
|
|
input [DATA_SIZE_:0] alu_status;
|
| 62 |
|
|
input [DATA_SIZE_:0] data_in;
|
| 63 |
|
|
output reg [ADDR_SIZE_:0] address;
|
| 64 |
61 |
creep |
output reg control; // one bit is enough? read = 0, write = 1
|
| 65 |
82 |
creep |
output reg [DATA_SIZE_:0] data_out;
|
| 66 |
|
|
output reg [DATA_SIZE_:0] alu_opcode;
|
| 67 |
|
|
output reg [DATA_SIZE_:0] alu_a;
|
| 68 |
68 |
creep |
output reg alu_enable;
|
| 69 |
61 |
creep |
|
| 70 |
86 |
creep |
input [DATA_SIZE_:0] alu_x;
|
| 71 |
|
|
input [DATA_SIZE_:0] alu_y;
|
| 72 |
68 |
creep |
|
| 73 |
61 |
creep |
// FSM states
|
| 74 |
63 |
creep |
localparam FETCH_OP = 4'b0000;
|
| 75 |
68 |
creep |
localparam FETCH_OP_CALC = 4'b0001;
|
| 76 |
|
|
localparam FETCH_LOW = 4'b0010;
|
| 77 |
|
|
localparam FETCH_HIGH = 4'b0011;
|
| 78 |
71 |
creep |
localparam READ_MEM = 4'b0100;
|
| 79 |
|
|
localparam DUMMY_WRT_CALC = 4'b0101;
|
| 80 |
|
|
localparam WRITE_MEM = 4'b0110;
|
| 81 |
|
|
localparam FETCH_OP_CALC_PARAM = 4'b0111;
|
| 82 |
86 |
creep |
localparam READ_MEM_CALC_INDEX = 4'b1000;
|
| 83 |
87 |
creep |
localparam FETCH_HIGH_CALC_INDEX = 4'b1001;
|
| 84 |
|
|
localparam READ_MEM_FIX_ADDR = 4'b1010;
|
| 85 |
|
|
localparam RESET = 4'b1111;
|
| 86 |
61 |
creep |
|
| 87 |
|
|
// OPCODES TODO: verify how this get synthesised
|
| 88 |
|
|
`include "../T6507LP_Package.v"
|
| 89 |
|
|
|
| 90 |
|
|
// control signals
|
| 91 |
|
|
localparam MEM_READ = 1'b0;
|
| 92 |
|
|
localparam MEM_WRITE = 1'b1;
|
| 93 |
|
|
|
| 94 |
82 |
creep |
reg [ADDR_SIZE_:0] pc; // program counter
|
| 95 |
|
|
reg [DATA_SIZE_:0] sp; // stack pointer
|
| 96 |
|
|
reg [DATA_SIZE_:0] ir; // instruction register
|
| 97 |
|
|
reg [ADDR_SIZE_:0] temp_addr; // temporary address
|
| 98 |
|
|
reg [DATA_SIZE_:0] temp_data; // temporary data
|
| 99 |
61 |
creep |
|
| 100 |
|
|
reg [3:0] state, next_state; // current and next state registers
|
| 101 |
|
|
// TODO: not sure if this will be 4 bits wide. as of march 9th this was 4bit wide.
|
| 102 |
|
|
|
| 103 |
|
|
// wiring that simplifies the FSM logic
|
| 104 |
|
|
reg absolute;
|
| 105 |
|
|
reg absolute_indexed;
|
| 106 |
|
|
reg accumulator;
|
| 107 |
|
|
reg immediate;
|
| 108 |
|
|
reg implied;
|
| 109 |
|
|
reg indirect;
|
| 110 |
|
|
reg relative;
|
| 111 |
|
|
reg zero_page;
|
| 112 |
|
|
reg zero_page_indexed;
|
| 113 |
86 |
creep |
reg [DATA_SIZE_:0] index; // will be assigned with either X or Y
|
| 114 |
61 |
creep |
|
| 115 |
|
|
// regs that store the type of operation. again, this simplifies the FSM a lot.
|
| 116 |
|
|
reg read;
|
| 117 |
|
|
reg read_modify_write;
|
| 118 |
|
|
reg write;
|
| 119 |
|
|
reg jump;
|
| 120 |
|
|
|
| 121 |
82 |
creep |
wire [ADDR_SIZE_:0] next_pc;
|
| 122 |
63 |
creep |
assign next_pc = pc + 13'b0000000000001;
|
| 123 |
61 |
creep |
|
| 124 |
87 |
creep |
reg [ADDR_SIZE_:0] address_plus_index; // this would update more times than actually needed, consuming power.
|
| 125 |
|
|
reg page_crossed; // so the simple assign was changed into a combinational always block
|
| 126 |
|
|
|
| 127 |
|
|
always @(*) begin
|
| 128 |
|
|
address_plus_index = 0;
|
| 129 |
|
|
page_crossed = 0;
|
| 130 |
86 |
creep |
|
| 131 |
88 |
creep |
if (state == READ_MEM_CALC_INDEX || state == READ_MEM_FIX_ADDR || state == FETCH_HIGH_CALC_INDEX) begin
|
| 132 |
|
|
{page_crossed, address_plus_index[7:0]} = temp_addr[7:0] + index;
|
| 133 |
|
|
address_plus_index[12:8] = temp_addr[12:8] + page_crossed;
|
| 134 |
|
|
|
| 135 |
87 |
creep |
end
|
| 136 |
|
|
end
|
| 137 |
|
|
|
| 138 |
71 |
creep |
always @ (posedge clk or negedge reset_n) begin // sequencial always block
|
| 139 |
|
|
if (reset_n == 1'b0) begin
|
| 140 |
|
|
// all registers must assume default values
|
| 141 |
68 |
creep |
pc <= 0; // TODO: this is written somewhere. something about a reset vector. must be checked.
|
| 142 |
|
|
sp <= 0; // TODO: the default is not 0. maybe $0100 or something like that. must be checked.
|
| 143 |
82 |
creep |
ir <= 8'h00;
|
| 144 |
71 |
creep |
temp_addr <= 0;
|
| 145 |
82 |
creep |
temp_data <= 8'h00;
|
| 146 |
68 |
creep |
state <= RESET;
|
| 147 |
71 |
creep |
// registered outputs also receive default values
|
| 148 |
|
|
address <= 0;
|
| 149 |
82 |
creep |
control <= MEM_READ;
|
| 150 |
|
|
data_out <= 8'h00;
|
| 151 |
61 |
creep |
end
|
| 152 |
|
|
else begin
|
| 153 |
|
|
state <= next_state;
|
| 154 |
83 |
creep |
|
| 155 |
61 |
creep |
case (state)
|
| 156 |
68 |
creep |
RESET: begin
|
| 157 |
82 |
creep |
// The processor was reset
|
| 158 |
|
|
$write("under reset");
|
| 159 |
68 |
creep |
end
|
| 160 |
61 |
creep |
FETCH_OP: begin // this state is the simplest one. it is a simple fetch that must be done when the cpu was reset or
|
| 161 |
|
|
// the last cycle was a memory write.
|
| 162 |
|
|
pc <= next_pc;
|
| 163 |
71 |
creep |
address <= next_pc;
|
| 164 |
83 |
creep |
control <= MEM_READ;
|
| 165 |
70 |
creep |
ir <= data_in;
|
| 166 |
61 |
creep |
end
|
| 167 |
71 |
creep |
FETCH_OP_CALC, FETCH_OP_CALC_PARAM: begin // this is the pipeline happening!
|
| 168 |
61 |
creep |
pc <= next_pc;
|
| 169 |
71 |
creep |
address <= next_pc;
|
| 170 |
83 |
creep |
control <= MEM_READ;
|
| 171 |
70 |
creep |
ir <= data_in;
|
| 172 |
61 |
creep |
end
|
| 173 |
68 |
creep |
FETCH_LOW: begin // in this state the opcode is already known so truly execution begins
|
| 174 |
|
|
if (accumulator || implied) begin
|
| 175 |
70 |
creep |
pc <= pc; // is this better?
|
| 176 |
71 |
creep |
address <= pc;
|
| 177 |
83 |
creep |
control <= MEM_READ;
|
| 178 |
61 |
creep |
end
|
| 179 |
70 |
creep |
else if (immediate) begin
|
| 180 |
68 |
creep |
pc <= next_pc;
|
| 181 |
71 |
creep |
address <= next_pc;
|
| 182 |
83 |
creep |
control <= MEM_READ;
|
| 183 |
70 |
creep |
temp_data <= data_in; // the follow-up byte is saved in temp_data
|
| 184 |
61 |
creep |
end
|
| 185 |
87 |
creep |
else if (absolute || absolute_indexed) begin
|
| 186 |
71 |
creep |
pc <= next_pc;
|
| 187 |
|
|
address <= next_pc;
|
| 188 |
83 |
creep |
control <= MEM_READ;
|
| 189 |
87 |
creep |
temp_addr <= {{5{1'b0}},data_in};
|
| 190 |
71 |
creep |
end
|
| 191 |
77 |
creep |
else if (zero_page) begin
|
| 192 |
|
|
pc <= next_pc;
|
| 193 |
|
|
address <= {{5{1'b0}},data_in};
|
| 194 |
78 |
creep |
temp_addr <= {{5{1'b0}},data_in};
|
| 195 |
|
|
|
| 196 |
77 |
creep |
if (write) begin
|
| 197 |
|
|
control <= MEM_WRITE;
|
| 198 |
78 |
creep |
data_out <= alu_result;
|
| 199 |
77 |
creep |
end
|
| 200 |
83 |
creep |
else begin
|
| 201 |
|
|
control <= MEM_READ;
|
| 202 |
|
|
data_out <= 8'h00;
|
| 203 |
|
|
end
|
| 204 |
77 |
creep |
end
|
| 205 |
86 |
creep |
else if (zero_page_indexed) begin
|
| 206 |
|
|
pc <= next_pc;
|
| 207 |
|
|
address <= {{5{1'b0}},data_in};
|
| 208 |
|
|
temp_addr <= {{5{1'b0}},data_in};
|
| 209 |
|
|
control <= MEM_READ;
|
| 210 |
|
|
end
|
| 211 |
61 |
creep |
end
|
| 212 |
87 |
creep |
FETCH_HIGH_CALC_INDEX: begin
|
| 213 |
|
|
pc <= next_pc;
|
| 214 |
|
|
temp_addr[12:8] <= data_in[4:0];
|
| 215 |
|
|
address <= {data_in[4:0], address_plus_index[7:0]};
|
| 216 |
|
|
control <= MEM_READ;
|
| 217 |
|
|
data_out <= 8'h00;
|
| 218 |
|
|
end
|
| 219 |
71 |
creep |
FETCH_HIGH: begin
|
| 220 |
|
|
if (jump) begin
|
| 221 |
83 |
creep |
pc <= {data_in[4:0], temp_addr[7:0]}; // PCL <= first byte, PCH <= second byte
|
| 222 |
|
|
address <= {data_in[4:0], temp_addr[7:0]};
|
| 223 |
|
|
control <= MEM_READ;
|
| 224 |
|
|
data_out <= 8'h00;
|
| 225 |
71 |
creep |
end
|
| 226 |
|
|
else begin
|
| 227 |
|
|
if (write) begin
|
| 228 |
|
|
pc <= next_pc;
|
| 229 |
|
|
temp_addr[12:8] <= data_in[4:0];
|
| 230 |
|
|
address <= {data_in[4:0],temp_addr[7:0]};
|
| 231 |
|
|
control <= MEM_WRITE;
|
| 232 |
77 |
creep |
data_out <= alu_result;
|
| 233 |
71 |
creep |
end
|
| 234 |
|
|
else begin // read_modify_write or just read
|
| 235 |
|
|
pc <= next_pc;
|
| 236 |
|
|
temp_addr[12:8] <= data_in[4:0];
|
| 237 |
|
|
address <= {data_in[4:0],temp_addr[7:0]};
|
| 238 |
83 |
creep |
control <= MEM_READ;
|
| 239 |
|
|
data_out <= 8'h00;
|
| 240 |
71 |
creep |
end
|
| 241 |
|
|
end
|
| 242 |
|
|
//else begin
|
| 243 |
|
|
// $write("FETCHHIGH PROBLEM");
|
| 244 |
|
|
// $finish(0);
|
| 245 |
|
|
//end
|
| 246 |
61 |
creep |
end
|
| 247 |
71 |
creep |
READ_MEM: begin
|
| 248 |
|
|
if (read_modify_write) begin
|
| 249 |
|
|
pc <= pc;
|
| 250 |
|
|
address <= temp_addr;
|
| 251 |
|
|
control <= MEM_WRITE;
|
| 252 |
|
|
temp_data <= data_in;
|
| 253 |
|
|
data_out <= data_in; // writeback the same value
|
| 254 |
|
|
end
|
| 255 |
|
|
else begin
|
| 256 |
|
|
pc <= pc;
|
| 257 |
|
|
address <= pc;
|
| 258 |
|
|
temp_data <= data_in;
|
| 259 |
83 |
creep |
control <= MEM_READ;
|
| 260 |
|
|
data_out <= 8'h00;
|
| 261 |
71 |
creep |
end
|
| 262 |
70 |
creep |
end
|
| 263 |
86 |
creep |
READ_MEM_CALC_INDEX: begin
|
| 264 |
|
|
//pc <= next_pc; // pc was already updated in the previous cycle
|
| 265 |
|
|
address <= address_plus_index;
|
| 266 |
|
|
temp_addr <= address_plus_index;
|
| 267 |
|
|
|
| 268 |
|
|
if (write) begin
|
| 269 |
|
|
control <= MEM_WRITE;
|
| 270 |
|
|
data_out <= alu_result;
|
| 271 |
|
|
end
|
| 272 |
|
|
else begin
|
| 273 |
|
|
control <= MEM_READ;
|
| 274 |
|
|
data_out <= 8'h00;
|
| 275 |
|
|
end
|
| 276 |
|
|
|
| 277 |
|
|
end
|
| 278 |
87 |
creep |
READ_MEM_FIX_ADDR: begin
|
| 279 |
|
|
if (read) begin
|
| 280 |
|
|
control <= MEM_READ;
|
| 281 |
|
|
data_out <= 8'h00;
|
| 282 |
|
|
|
| 283 |
|
|
if (page_crossed) begin
|
| 284 |
|
|
address <= address_plus_index;
|
| 285 |
|
|
temp_addr <= address_plus_index;
|
| 286 |
|
|
end
|
| 287 |
|
|
else begin
|
| 288 |
|
|
address <= pc;
|
| 289 |
|
|
temp_data <= data_in;
|
| 290 |
|
|
end
|
| 291 |
|
|
end
|
| 292 |
|
|
else if (write) begin
|
| 293 |
|
|
control <= MEM_WRITE;
|
| 294 |
|
|
data_out <= alu_result;
|
| 295 |
|
|
address <= address_plus_index;
|
| 296 |
|
|
temp_addr <= address_plus_index;
|
| 297 |
|
|
|
| 298 |
|
|
end
|
| 299 |
|
|
else begin // read modify write
|
| 300 |
|
|
control <= MEM_READ;
|
| 301 |
|
|
data_out <= 8'h00;
|
| 302 |
|
|
address <= address_plus_index;
|
| 303 |
|
|
temp_addr <= address_plus_index;
|
| 304 |
|
|
end
|
| 305 |
|
|
end
|
| 306 |
71 |
creep |
DUMMY_WRT_CALC: begin
|
| 307 |
|
|
pc <= pc;
|
| 308 |
|
|
address <= temp_addr;
|
| 309 |
|
|
control <= MEM_WRITE;
|
| 310 |
|
|
data_out <= alu_result;
|
| 311 |
70 |
creep |
end
|
| 312 |
71 |
creep |
WRITE_MEM: begin
|
| 313 |
|
|
pc <= pc;
|
| 314 |
|
|
address <= pc;
|
| 315 |
83 |
creep |
control <= MEM_READ;
|
| 316 |
|
|
data_out <= 8'h00;
|
| 317 |
70 |
creep |
end
|
| 318 |
|
|
default: begin
|
| 319 |
|
|
$write("unknown state"); // TODO: check if synth really ignores this 2 lines. Otherwise wrap it with a `ifdef
|
| 320 |
|
|
$finish(0);
|
| 321 |
|
|
end
|
| 322 |
|
|
|
| 323 |
|
|
endcase
|
| 324 |
|
|
end
|
| 325 |
|
|
end
|
| 326 |
|
|
|
| 327 |
71 |
creep |
always @ (*) begin // this is the next_state logic and the output logic always block
|
| 328 |
|
|
alu_opcode = 8'h00;
|
| 329 |
|
|
alu_a = 8'h00;
|
| 330 |
|
|
alu_enable = 1'b0;
|
| 331 |
70 |
creep |
|
| 332 |
71 |
creep |
next_state = RESET; // this prevents the latch
|
| 333 |
68 |
creep |
|
| 334 |
71 |
creep |
case (state)
|
| 335 |
|
|
RESET: begin
|
| 336 |
|
|
next_state = FETCH_OP;
|
| 337 |
|
|
end
|
| 338 |
|
|
FETCH_OP: begin
|
| 339 |
|
|
next_state = FETCH_LOW;
|
| 340 |
|
|
end
|
| 341 |
82 |
creep |
//FETCH_OP_CALC: begin // so far no addressing mode required the use of this state
|
| 342 |
|
|
// next_state = FETCH_LOW;
|
| 343 |
|
|
// alu_opcode = ir;
|
| 344 |
|
|
// alu_enable = 1'b1;
|
| 345 |
|
|
//end
|
| 346 |
71 |
creep |
FETCH_OP_CALC_PARAM: begin
|
| 347 |
|
|
next_state = FETCH_LOW;
|
| 348 |
|
|
alu_opcode = ir;
|
| 349 |
|
|
alu_enable = 1'b1;
|
| 350 |
|
|
alu_a = temp_data;
|
| 351 |
|
|
end
|
| 352 |
|
|
FETCH_LOW: begin
|
| 353 |
|
|
if (accumulator || implied) begin
|
| 354 |
|
|
alu_opcode = ir;
|
| 355 |
|
|
alu_enable = 1'b1;
|
| 356 |
|
|
next_state = FETCH_OP;
|
| 357 |
|
|
end
|
| 358 |
|
|
else if (immediate) begin
|
| 359 |
|
|
next_state = FETCH_OP_CALC_PARAM;
|
| 360 |
|
|
end
|
| 361 |
77 |
creep |
else if (zero_page) begin
|
| 362 |
|
|
if (read || read_modify_write) begin
|
| 363 |
|
|
next_state = READ_MEM;
|
| 364 |
|
|
end
|
| 365 |
|
|
else if (write) begin
|
| 366 |
|
|
next_state = WRITE_MEM;
|
| 367 |
86 |
creep |
alu_opcode = ir;
|
| 368 |
|
|
alu_enable = 1'b1;
|
| 369 |
|
|
alu_a = 8'h00;
|
| 370 |
77 |
creep |
end
|
| 371 |
|
|
else begin
|
| 372 |
|
|
$write("unknown behavior");
|
| 373 |
|
|
$finish(0);
|
| 374 |
|
|
end
|
| 375 |
|
|
end
|
| 376 |
86 |
creep |
else if (zero_page_indexed) begin
|
| 377 |
|
|
next_state = READ_MEM_CALC_INDEX;
|
| 378 |
|
|
end
|
| 379 |
87 |
creep |
else if (absolute) begin // at least the absolute address mode falls here
|
| 380 |
71 |
creep |
next_state = FETCH_HIGH;
|
| 381 |
87 |
creep |
if (write) begin // this is being done one cycle early but i have checked and the ALU will still work properly
|
| 382 |
86 |
creep |
alu_opcode = ir;
|
| 383 |
|
|
alu_enable = 1'b1;
|
| 384 |
|
|
alu_a = 8'h00;
|
| 385 |
|
|
end
|
| 386 |
71 |
creep |
end
|
| 387 |
87 |
creep |
else if (absolute_indexed) begin
|
| 388 |
|
|
next_state = FETCH_HIGH_CALC_INDEX;
|
| 389 |
|
|
end
|
| 390 |
71 |
creep |
end
|
| 391 |
87 |
creep |
FETCH_HIGH_CALC_INDEX: begin
|
| 392 |
|
|
next_state = READ_MEM_FIX_ADDR;
|
| 393 |
|
|
end
|
| 394 |
|
|
READ_MEM_FIX_ADDR: begin
|
| 395 |
|
|
if (read) begin
|
| 396 |
|
|
if (page_crossed) begin
|
| 397 |
|
|
next_state = READ_MEM;
|
| 398 |
|
|
end
|
| 399 |
|
|
else begin
|
| 400 |
|
|
next_state = FETCH_OP_CALC_PARAM;
|
| 401 |
|
|
end
|
| 402 |
|
|
end
|
| 403 |
|
|
else if (read_modify_write) begin
|
| 404 |
|
|
next_state = READ_MEM;
|
| 405 |
|
|
end
|
| 406 |
|
|
else if (write) begin
|
| 407 |
|
|
next_state = WRITE_MEM;
|
| 408 |
|
|
end
|
| 409 |
|
|
else begin
|
| 410 |
|
|
$write("unknown behavior");
|
| 411 |
|
|
$finish(0);
|
| 412 |
|
|
end
|
| 413 |
|
|
end
|
| 414 |
71 |
creep |
FETCH_HIGH: begin
|
| 415 |
|
|
if (jump) begin
|
| 416 |
68 |
creep |
next_state = FETCH_OP;
|
| 417 |
61 |
creep |
end
|
| 418 |
71 |
creep |
else if (read || read_modify_write) begin
|
| 419 |
|
|
next_state = READ_MEM;
|
| 420 |
61 |
creep |
end
|
| 421 |
71 |
creep |
else if (write) begin
|
| 422 |
|
|
next_state = WRITE_MEM;
|
| 423 |
68 |
creep |
end
|
| 424 |
71 |
creep |
else begin
|
| 425 |
|
|
$write("unknown behavior");
|
| 426 |
|
|
$finish(0);
|
| 427 |
61 |
creep |
end
|
| 428 |
71 |
creep |
end
|
| 429 |
86 |
creep |
READ_MEM_CALC_INDEX: begin
|
| 430 |
|
|
if (read || read_modify_write) begin
|
| 431 |
|
|
next_state = READ_MEM;
|
| 432 |
|
|
end
|
| 433 |
|
|
else if (write) begin
|
| 434 |
|
|
alu_opcode = ir;
|
| 435 |
|
|
alu_enable = 1'b1;
|
| 436 |
|
|
next_state = WRITE_MEM;
|
| 437 |
|
|
end
|
| 438 |
|
|
else begin
|
| 439 |
|
|
$write("unknown behavior");
|
| 440 |
|
|
$finish(0);
|
| 441 |
|
|
end
|
| 442 |
|
|
end
|
| 443 |
71 |
creep |
READ_MEM: begin
|
| 444 |
|
|
if (read) begin
|
| 445 |
|
|
next_state = FETCH_OP_CALC_PARAM;
|
| 446 |
61 |
creep |
end
|
| 447 |
71 |
creep |
else if (read_modify_write) begin
|
| 448 |
|
|
next_state = DUMMY_WRT_CALC;
|
| 449 |
|
|
end
|
| 450 |
|
|
end
|
| 451 |
|
|
DUMMY_WRT_CALC: begin
|
| 452 |
|
|
alu_opcode = ir;
|
| 453 |
|
|
alu_enable = 1'b1;
|
| 454 |
|
|
alu_a = data_in;
|
| 455 |
|
|
next_state = WRITE_MEM;
|
| 456 |
|
|
end
|
| 457 |
|
|
WRITE_MEM: begin
|
| 458 |
|
|
next_state = FETCH_OP;
|
| 459 |
|
|
end
|
| 460 |
|
|
default: begin
|
| 461 |
|
|
next_state = RESET;
|
| 462 |
|
|
end
|
| 463 |
|
|
endcase
|
| 464 |
61 |
creep |
end
|
| 465 |
|
|
|
| 466 |
77 |
creep |
// this always block is responsible for updating the address mode and the type of operation being done
|
| 467 |
68 |
creep |
always @ (*) begin //
|
| 468 |
61 |
creep |
absolute = 1'b0;
|
| 469 |
|
|
absolute_indexed = 1'b0;
|
| 470 |
|
|
accumulator = 1'b0;
|
| 471 |
|
|
immediate = 1'b0;
|
| 472 |
|
|
implied = 1'b0;
|
| 473 |
|
|
indirect = 1'b0;
|
| 474 |
|
|
relative = 1'b0;
|
| 475 |
|
|
zero_page = 1'b0;
|
| 476 |
|
|
zero_page_indexed = 1'b0;
|
| 477 |
86 |
creep |
|
| 478 |
|
|
index = 1'b0;
|
| 479 |
61 |
creep |
|
| 480 |
|
|
read = 1'b0;
|
| 481 |
|
|
read_modify_write = 1'b0;
|
| 482 |
|
|
write = 1'b0;
|
| 483 |
|
|
jump = 1'b0;
|
| 484 |
|
|
|
| 485 |
70 |
creep |
case (ir)
|
| 486 |
|
|
BRK_IMP, CLC_IMP, CLD_IMP, CLI_IMP, CLV_IMP, DEX_IMP, DEY_IMP, INX_IMP, INY_IMP, NOP_IMP, PHA_IMP, PHP_IMP, PLA_IMP,
|
| 487 |
|
|
PLP_IMP, RTI_IMP, RTS_IMP, SEC_IMP, SED_IMP, SEI_IMP, TAX_IMP, TAY_IMP, TSX_IMP, TXA_IMP, TXS_IMP, TYA_IMP: begin
|
| 488 |
|
|
implied = 1'b1;
|
| 489 |
|
|
end
|
| 490 |
|
|
ASL_ACC, LSR_ACC, ROL_ACC, ROR_ACC: begin
|
| 491 |
|
|
accumulator = 1'b1;
|
| 492 |
|
|
end
|
| 493 |
|
|
ADC_IMM, AND_IMM, CMP_IMM, CPX_IMM, CPY_IMM, EOR_IMM, LDA_IMM, LDX_IMM, LDY_IMM, ORA_IMM, SBC_IMM: begin
|
| 494 |
|
|
immediate = 1'b1;
|
| 495 |
|
|
end
|
| 496 |
|
|
ADC_ZPG, AND_ZPG, ASL_ZPG, BIT_ZPG, CMP_ZPG, CPX_ZPG, CPY_ZPG, DEC_ZPG, EOR_ZPG, INC_ZPG, LDA_ZPG, LDX_ZPG, LDY_ZPG,
|
| 497 |
|
|
LSR_ZPG, ORA_ZPG, ROL_ZPG, ROR_ZPG, SBC_ZPG, STA_ZPG, STX_ZPG, STY_ZPG: begin
|
| 498 |
|
|
zero_page = 1'b1;
|
| 499 |
|
|
end
|
| 500 |
|
|
ADC_ZPX, AND_ZPX, ASL_ZPX, CMP_ZPX, DEC_ZPX, EOR_ZPX, INC_ZPX, LDA_ZPX, LDY_ZPX, LSR_ZPX, ORA_ZPX, ROL_ZPX, ROR_ZPX,
|
| 501 |
86 |
creep |
SBC_ZPX, STA_ZPX, STY_ZPX: begin
|
| 502 |
70 |
creep |
zero_page_indexed = 1'b1;
|
| 503 |
86 |
creep |
index = alu_x;
|
| 504 |
70 |
creep |
end
|
| 505 |
86 |
creep |
LDX_ZPY, STX_ZPY: begin
|
| 506 |
|
|
zero_page_indexed = 1'b1;
|
| 507 |
|
|
index = alu_y;
|
| 508 |
|
|
end
|
| 509 |
70 |
creep |
BCC_REL, BCS_REL, BEQ_REL, BMI_REL, BNE_REL, BPL_REL, BVC_REL, BVS_REL: begin
|
| 510 |
|
|
relative = 1'b1;
|
| 511 |
|
|
end
|
| 512 |
|
|
ADC_ABS, AND_ABS, ASL_ABS, BIT_ABS, CMP_ABS, CPX_ABS, CPY_ABS, DEC_ABS, EOR_ABS, INC_ABS, JMP_ABS, JSR_ABS, LDA_ABS,
|
| 513 |
|
|
LDX_ABS, LDY_ABS, LSR_ABS, ORA_ABS, ROL_ABS, ROR_ABS, SBC_ABS, STA_ABS, STX_ABS, STY_ABS: begin
|
| 514 |
|
|
absolute = 1'b1;
|
| 515 |
|
|
end
|
| 516 |
|
|
ADC_ABX, AND_ABX, ASL_ABX, CMP_ABX, DEC_ABX, EOR_ABX, INC_ABX, LDA_ABX, LDY_ABX, LSR_ABX, ORA_ABX, ROL_ABX, ROR_ABX,
|
| 517 |
87 |
creep |
SBC_ABX, STA_ABX: begin
|
| 518 |
70 |
creep |
absolute_indexed = 1'b1;
|
| 519 |
87 |
creep |
index = alu_x;
|
| 520 |
70 |
creep |
end
|
| 521 |
87 |
creep |
ADC_ABY, AND_ABY, CMP_ABY, EOR_ABY, LDA_ABY, LDX_ABY, ORA_ABY, SBC_ABY, STA_ABY: begin
|
| 522 |
|
|
absolute_indexed = 1'b1;
|
| 523 |
|
|
index = alu_y;
|
| 524 |
|
|
end
|
| 525 |
70 |
creep |
ADC_IDX, AND_IDX, CMP_IDX, EOR_IDX, LDA_IDX, ORA_IDX, SBC_IDX, STA_IDX, ADC_IDY, AND_IDY, CMP_IDY, EOR_IDY, LDA_IDY,
|
| 526 |
|
|
ORA_IDY, SBC_IDY, STA_IDY: begin // all these opcodes are 8'hX1; TODO: optimize this
|
| 527 |
|
|
indirect = 1'b1;
|
| 528 |
|
|
end
|
| 529 |
71 |
creep |
default: begin
|
| 530 |
86 |
creep |
if (reset_n == 1) begin // the processor is NOT being reset
|
| 531 |
|
|
$write("\nunknown OPCODE!!!!! 0x%h\n", ir);
|
| 532 |
|
|
$finish();
|
| 533 |
|
|
end
|
| 534 |
71 |
creep |
end
|
| 535 |
70 |
creep |
endcase
|
| 536 |
71 |
creep |
|
| 537 |
|
|
case (ir)
|
| 538 |
|
|
ASL_ACC, ASL_ZPG, ASL_ZPX, ASL_ABS, ASL_ABX, LSR_ACC, LSR_ZPG, LSR_ZPX, LSR_ABS, LSR_ABX, ROL_ACC, ROL_ZPG, ROL_ZPX, ROL_ABS,
|
| 539 |
|
|
ROL_ABX, ROR_ACC, ROR_ZPG, ROR_ZPX, ROR_ABS, ROR_ABX, INC_ZPG, INC_ZPX, INC_ABS, INC_ABX, DEC_ZPG, DEC_ZPX, DEC_ABS,
|
| 540 |
|
|
DEC_ABX: begin
|
| 541 |
|
|
read_modify_write = 1'b1;
|
| 542 |
|
|
end
|
| 543 |
|
|
STA_ZPG, STA_ZPX, STA_ABS, STA_ABX, STA_ABY, STA_IDX, STA_IDY, STX_ZPG, STX_ZPY, STX_ABS, STY_ZPG, STY_ZPX, STY_ABS: begin
|
| 544 |
|
|
write = 1'b1;
|
| 545 |
|
|
end
|
| 546 |
|
|
default: begin // this should work fine since the previous case statement will detect the unknown/undocumented/unsupported opcodes
|
| 547 |
|
|
read = 1'b1;
|
| 548 |
|
|
end
|
| 549 |
|
|
endcase
|
| 550 |
61 |
creep |
|
| 551 |
71 |
creep |
if (ir == JMP_ABS || ir == JMP_IND) begin // the opcodes are 8'h4C and 8'h6C
|
| 552 |
70 |
creep |
jump = 1'b1;
|
| 553 |
|
|
end
|
| 554 |
86 |
creep |
end
|
| 555 |
61 |
creep |
endmodule
|
| 556 |
|
|
|
| 557 |
|
|
|
| 558 |
|
|
|