Line 8... |
Line 8... |
//// Description ////
|
//// Description ////
|
//// 6507 FSM ////
|
//// 6507 FSM ////
|
//// ////
|
//// ////
|
//// TODO: ////
|
//// TODO: ////
|
//// - Fix relative mode, bit 7 means negative ////
|
//// - Fix relative mode, bit 7 means negative ////
|
//// - Code the indirect indexed mode ////
|
//// - Comment the code ////
|
//// - Code the absolute indirect mode ////
|
|
//// ////
|
//// ////
|
//// Author(s): ////
|
//// Author(s): ////
|
//// - Gabriel Oshiro Zardo, gabrieloshiro@gmail.com ////
|
//// - Gabriel Oshiro Zardo, gabrieloshiro@gmail.com ////
|
//// - Samuel Nascimento Pagliarini (creep), snpagliarini@gmail.com ////
|
//// - Samuel Nascimento Pagliarini (creep), snpagliarini@gmail.com ////
|
//// ////
|
//// ////
|
Line 57... |
Line 56... |
input reset_n;
|
input reset_n;
|
input [DATA_SIZE_:0] alu_result;
|
input [DATA_SIZE_:0] alu_result;
|
input [DATA_SIZE_:0] alu_status;
|
input [DATA_SIZE_:0] alu_status;
|
input [DATA_SIZE_:0] data_in;
|
input [DATA_SIZE_:0] data_in;
|
output reg [ADDR_SIZE_:0] address;
|
output reg [ADDR_SIZE_:0] address;
|
output reg control; // one bit is enough? read = 0, write = 1
|
output reg control; // read = 0, write = 1
|
output reg [DATA_SIZE_:0] data_out;
|
output reg [DATA_SIZE_:0] data_out;
|
output reg [DATA_SIZE_:0] alu_opcode;
|
output reg [DATA_SIZE_:0] alu_opcode;
|
output reg [DATA_SIZE_:0] alu_a;
|
output reg [DATA_SIZE_:0] alu_a;
|
output reg alu_enable;
|
output reg alu_enable;
|
|
|
input [DATA_SIZE_:0] alu_x;
|
input [DATA_SIZE_:0] alu_x;
|
input [DATA_SIZE_:0] alu_y;
|
input [DATA_SIZE_:0] alu_y;
|
|
|
// FSM states
|
// FSM states
|
localparam FETCH_OP = 5'b00000;
|
localparam FETCH_OP = 5'b00000;
|
localparam FETCH_OP_CALC = 5'b00001;
|
//localparam FETCH_OP_CALC = 5'b00001; this was never used
|
localparam FETCH_LOW = 5'b00010;
|
localparam FETCH_LOW = 5'b00010;
|
localparam FETCH_HIGH = 5'b00011;
|
localparam FETCH_HIGH = 5'b00011;
|
localparam READ_MEM = 5'b00100;
|
localparam READ_MEM = 5'b00100;
|
localparam DUMMY_WRT_CALC = 5'b00101;
|
localparam DUMMY_WRT_CALC = 5'b00101;
|
localparam WRITE_MEM = 5'b00110;
|
localparam WRITE_MEM = 5'b00110;
|
Line 95... |
Line 94... |
localparam PULL_PCL = 5'b10111;
|
localparam PULL_PCL = 5'b10111;
|
localparam PULL_PCH = 5'b11000;
|
localparam PULL_PCH = 5'b11000;
|
localparam INCREMENT_PC = 5'b11001;
|
localparam INCREMENT_PC = 5'b11001;
|
localparam PUSH_REGISTER = 5'b11010;
|
localparam PUSH_REGISTER = 5'b11010;
|
localparam PULL_REGISTER = 5'b11011;
|
localparam PULL_REGISTER = 5'b11011;
|
|
localparam DUMMY = 5'b11100;
|
|
|
localparam RESET = 5'b11111;
|
localparam RESET = 5'b11111;
|
|
|
// OPCODES TODO: verify how this get synthesised
|
// OPCODES TODO: verify how this get synthesised
|
`include "../T6507LP_Package.v"
|
`include "../T6507LP_Package.v"
|
Line 112... |
Line 112... |
reg [DATA_SIZE_:0] ir; // instruction register
|
reg [DATA_SIZE_:0] ir; // instruction register
|
reg [ADDR_SIZE_:0] temp_addr; // temporary address
|
reg [ADDR_SIZE_:0] temp_addr; // temporary address
|
reg [DATA_SIZE_:0] temp_data; // temporary data
|
reg [DATA_SIZE_:0] temp_data; // temporary data
|
|
|
reg [4:0] state, next_state; // current and next state registers
|
reg [4:0] state, next_state; // current and next state registers
|
// TODO: not sure if this will be 5 bits wide. as of march 24th this was 5bit wide.
|
|
|
|
// wiring that simplifies the FSM logic by simplifying the addressing modes
|
// wiring that simplifies the FSM logic by simplifying the addressing modes
|
reg absolute;
|
reg absolute;
|
reg absolute_indexed;
|
reg absolute_indexed;
|
reg accumulator;
|
reg accumulator;
|
Line 142... |
Line 141... |
reg rts;
|
reg rts;
|
reg pha;
|
reg pha;
|
reg php;
|
reg php;
|
reg pla;
|
reg pla;
|
reg plp;
|
reg plp;
|
|
reg jsr;
|
|
|
wire [ADDR_SIZE_:0] next_pc;
|
wire [ADDR_SIZE_:0] next_pc;
|
assign next_pc = pc + 13'b0000000000001;
|
assign next_pc = pc + 13'b0000000000001;
|
|
|
reg [ADDR_SIZE_:0] address_plus_index; // this would update more times than actually needed, consuming power.
|
reg [ADDR_SIZE_:0] address_plus_index; // this would update more times than actually needed, consuming power.
|
Line 218... |
Line 218... |
RESET: begin // The processor was reset
|
RESET: begin // The processor was reset
|
$write("under reset");
|
$write("under reset");
|
end
|
end
|
/*
|
/*
|
FETCH_OP: executed when the processor was reset or the last instruction could not fetch.
|
FETCH_OP: executed when the processor was reset or the last instruction could not fetch.
|
FETCH_OP_CALC: enables the alu and fetchs the next instruction opcode. (pipelining)
|
|
FETCH_OP_CALC_PARAM: enables the alu with an argument (alu_a) and fetchs the next instruction opcode. (pipelining)
|
FETCH_OP_CALC_PARAM: enables the alu with an argument (alu_a) and fetchs the next instruction opcode. (pipelining)
|
*/
|
*/
|
FETCH_OP, FETCH_OP_CALC, FETCH_OP_CALC_PARAM: begin // this is the pipeline happening!
|
FETCH_OP, FETCH_OP_CALC_PARAM: begin // this is the pipeline happening!
|
pc <= next_pc;
|
pc <= next_pc;
|
address <= next_pc;
|
address <= next_pc;
|
control <= MEM_READ;
|
control <= MEM_READ;
|
ir <= data_in;
|
ir <= data_in;
|
end
|
end
|
Line 282... |
Line 281... |
if (break) begin
|
if (break) begin
|
pc <= next_pc;
|
pc <= next_pc;
|
address <= sp;
|
address <= sp;
|
data_out <= {{3{1'b0}}, pc[12:8]};
|
data_out <= {{3{1'b0}}, pc[12:8]};
|
control <= MEM_WRITE;
|
control <= MEM_WRITE;
|
sp <= sp_minus_one;
|
|
end
|
end
|
else if (rti || rts) begin
|
else if (rti || rts) begin
|
address <= sp;
|
address <= sp;
|
control <= MEM_READ;
|
control <= MEM_READ;
|
end
|
end
|
Line 299... |
Line 297... |
else if (pla || plp) begin
|
else if (pla || plp) begin
|
pc <= pc;
|
pc <= pc;
|
address <= sp;
|
address <= sp;
|
control <= MEM_READ;
|
control <= MEM_READ;
|
end
|
end
|
|
else begin // jsr
|
|
address <= sp;
|
|
control <= MEM_READ;
|
|
temp_addr <= {{5{1'b0}}, data_in};
|
|
pc <= next_pc;
|
|
end
|
end
|
end
|
end
|
end
|
FETCH_HIGH_CALC_INDEX: begin
|
FETCH_HIGH_CALC_INDEX: begin
|
pc <= next_pc;
|
pc <= next_pc;
|
temp_addr[12:8] <= data_in[4:0];
|
temp_addr[12:8] <= data_in[4:0];
|
Line 361... |
Line 365... |
address <= {data_in[4:0],temp_addr[7:0]};
|
address <= {data_in[4:0],temp_addr[7:0]};
|
control <= MEM_READ;
|
control <= MEM_READ;
|
data_out <= 8'h00;
|
data_out <= 8'h00;
|
end
|
end
|
end
|
end
|
//else begin
|
|
// $write("FETCHHIGH PROBLEM");
|
|
// $finish(0);
|
|
//end
|
|
end
|
end
|
READ_MEM: begin
|
READ_MEM: begin
|
if (read_modify_write) begin
|
if (read_modify_write) begin
|
pc <= pc;
|
pc <= pc;
|
address <= temp_addr;
|
address <= temp_addr;
|
Line 383... |
Line 383... |
control <= MEM_READ;
|
control <= MEM_READ;
|
data_out <= 8'h00;
|
data_out <= 8'h00;
|
end
|
end
|
end
|
end
|
READ_MEM_CALC_INDEX: begin
|
READ_MEM_CALC_INDEX: begin
|
//pc <= next_pc; // pc was already updated in the previous cycle
|
|
address <= address_plus_index;
|
address <= address_plus_index;
|
temp_addr <= address_plus_index;
|
temp_addr <= address_plus_index;
|
|
|
if (write) begin
|
if (write) begin
|
control <= MEM_WRITE;
|
control <= MEM_WRITE;
|
Line 486... |
Line 485... |
control <= MEM_READ;
|
control <= MEM_READ;
|
end
|
end
|
end
|
end
|
PUSH_PCH: begin
|
PUSH_PCH: begin
|
pc <= pc;
|
pc <= pc;
|
address <= sp;
|
address <= sp_minus_one;
|
data_out <= pc[7:0];
|
data_out <= pc[7:0];
|
control <= MEM_WRITE;
|
control <= MEM_WRITE;
|
sp <= sp_minus_one;
|
sp <= sp_minus_one;
|
end
|
end
|
PUSH_PCL: begin
|
PUSH_PCL: begin
|
|
if (jsr) begin
|
pc <= pc;
|
pc <= pc;
|
address <= sp;
|
address <= pc;
|
|
control <= MEM_READ;
|
|
sp <= sp_minus_one;
|
|
end
|
|
else begin
|
|
pc <= pc;
|
|
address <= sp_minus_one;
|
data_out <= alu_status;
|
data_out <= alu_status;
|
control <= MEM_WRITE;
|
control <= MEM_WRITE;
|
sp <= sp_minus_one;
|
sp <= sp_minus_one;
|
end
|
end
|
|
end
|
PUSH_STATUS: begin
|
PUSH_STATUS: begin
|
address <= 13'hFFFE;
|
address <= 13'hFFFE;
|
control <= MEM_READ;
|
control <= MEM_READ;
|
end
|
end
|
FETCH_PCL: begin
|
FETCH_PCL: begin
|
Line 546... |
Line 553... |
PULL_REGISTER: begin
|
PULL_REGISTER: begin
|
pc <= pc;
|
pc <= pc;
|
address <= pc;
|
address <= pc;
|
temp_data <= data_in;
|
temp_data <= data_in;
|
end
|
end
|
|
DUMMY: begin
|
|
address <= sp;
|
|
control <= MEM_WRITE;
|
|
end
|
default: begin
|
default: begin
|
$write("unknown state"); // TODO: check if synth really ignores this 2 lines. Otherwise wrap it with a `ifdef
|
$write("unknown state"); // TODO: check if synth really ignores this 2 lines. Otherwise wrap it with a `ifdef
|
$finish(0);
|
$finish(0);
|
end
|
end
|
|
|
Line 559... |
Line 570... |
|
|
always @ (*) begin // this is the next_state logic and the output logic always block
|
always @ (*) begin // this is the next_state logic and the output logic always block
|
alu_opcode = 8'h00;
|
alu_opcode = 8'h00;
|
alu_a = 8'h00;
|
alu_a = 8'h00;
|
alu_enable = 1'b0;
|
alu_enable = 1'b0;
|
|
next_state = RESET; // these lines prevents latches
|
next_state = RESET; // this prevents the latch
|
|
|
|
case (state)
|
case (state)
|
RESET: begin
|
RESET: begin
|
next_state = FETCH_OP;
|
next_state = FETCH_OP;
|
end
|
end
|
FETCH_OP: begin
|
FETCH_OP: begin
|
next_state = FETCH_LOW;
|
next_state = FETCH_LOW;
|
end
|
end
|
//FETCH_OP_CALC: begin // so far no addressing mode required the use of this state
|
|
// next_state = FETCH_LOW;
|
|
// alu_opcode = ir;
|
|
// alu_enable = 1'b1;
|
|
//end
|
|
FETCH_OP_CALC_PARAM: begin
|
FETCH_OP_CALC_PARAM: begin
|
next_state = FETCH_LOW;
|
next_state = FETCH_LOW;
|
alu_opcode = ir;
|
alu_opcode = ir;
|
alu_enable = 1'b1;
|
alu_enable = 1'b1;
|
alu_a = temp_data;
|
alu_a = temp_data;
|
Line 607... |
Line 612... |
end
|
end
|
end
|
end
|
else if (zero_page_indexed) begin
|
else if (zero_page_indexed) begin
|
next_state = READ_MEM_CALC_INDEX;
|
next_state = READ_MEM_CALC_INDEX;
|
end
|
end
|
else if (absolute || jump_indirect) begin // at least the absolute address mode falls here
|
else if (absolute || jump_indirect) begin
|
next_state = FETCH_HIGH;
|
next_state = FETCH_HIGH;
|
if (write) begin // this is being done one cycle early but i have checked and the ALU will still work properly
|
if (write) begin // this is being done one cycle early but i have checked and the ALU will still work properly
|
alu_opcode = ir;
|
alu_opcode = ir;
|
alu_enable = 1'b1;
|
alu_enable = 1'b1;
|
alu_a = 8'h00;
|
alu_a = 8'h00;
|
Line 643... |
Line 648... |
next_state = PUSH_REGISTER;
|
next_state = PUSH_REGISTER;
|
end
|
end
|
else if (pla || plp) begin
|
else if (pla || plp) begin
|
next_state = INCREMENT_SP;
|
next_state = INCREMENT_SP;
|
end
|
end
|
|
else begin // jsr
|
|
next_state = DUMMY;
|
|
end
|
end
|
end
|
end
|
end
|
READ_FROM_POINTER: begin
|
READ_FROM_POINTER: begin
|
if (indirectx) begin
|
if (indirectx) begin
|
next_state = READ_FROM_POINTER_X;
|
next_state = READ_FROM_POINTER_X;
|
Line 664... |
Line 672... |
end
|
end
|
else if (indirecty) begin
|
else if (indirecty) begin
|
next_state = READ_MEM_FIX_ADDR;
|
next_state = READ_MEM_FIX_ADDR;
|
end
|
end
|
else begin
|
else begin
|
if (read) begin // read_modify_write was showing up here for no reason. no instruction using pointers is from that type.
|
if (read) begin // no instruction using pointers is from type read_modify_write
|
next_state = READ_MEM;
|
next_state = READ_MEM;
|
end
|
end
|
else if (write) begin
|
else if (write) begin
|
alu_opcode = ir;
|
alu_opcode = ir;
|
alu_enable = 1'b1;
|
alu_enable = 1'b1;
|
Line 768... |
Line 776... |
end
|
end
|
PUSH_PCH: begin
|
PUSH_PCH: begin
|
next_state = PUSH_PCL;
|
next_state = PUSH_PCL;
|
end
|
end
|
PUSH_PCL: begin
|
PUSH_PCL: begin
|
|
if (jsr) begin
|
|
next_state = FETCH_HIGH;
|
|
end
|
|
else begin
|
next_state = PUSH_STATUS;
|
next_state = PUSH_STATUS;
|
end
|
end
|
|
end
|
PUSH_STATUS: begin
|
PUSH_STATUS: begin
|
next_state = FETCH_PCL;
|
next_state = FETCH_PCL;
|
end
|
end
|
FETCH_PCL: begin
|
FETCH_PCL: begin
|
next_state = FETCH_PCH;
|
next_state = FETCH_PCH;
|
Line 816... |
Line 829... |
next_state = FETCH_OP;
|
next_state = FETCH_OP;
|
end
|
end
|
PULL_REGISTER: begin
|
PULL_REGISTER: begin
|
next_state = FETCH_OP_CALC_PARAM;
|
next_state = FETCH_OP_CALC_PARAM;
|
end
|
end
|
|
DUMMY: begin
|
|
next_state = PUSH_PCH;
|
|
end
|
default: begin
|
default: begin
|
next_state = RESET;
|
next_state = RESET;
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
Line 851... |
Line 867... |
rts = 1'b0;
|
rts = 1'b0;
|
pha = 1'b0;
|
pha = 1'b0;
|
php = 1'b0;
|
php = 1'b0;
|
pla = 1'b0;
|
pla = 1'b0;
|
plp = 1'b0;
|
plp = 1'b0;
|
|
jsr = 1'b0;
|
|
|
case (ir)
|
case (ir)
|
CLC_IMP, CLD_IMP, CLI_IMP, CLV_IMP, DEX_IMP, DEY_IMP, INX_IMP, INY_IMP, NOP_IMP,
|
CLC_IMP, CLD_IMP, CLI_IMP, CLV_IMP, DEX_IMP, DEY_IMP, INX_IMP, INY_IMP, NOP_IMP,
|
SEC_IMP, SED_IMP, SEI_IMP, TAX_IMP, TAY_IMP, TSX_IMP, TXA_IMP, TXS_IMP, TYA_IMP: begin
|
SEC_IMP, SED_IMP, SEI_IMP, TAX_IMP, TAY_IMP, TSX_IMP, TXA_IMP, TXS_IMP, TYA_IMP: begin
|
implied = 1'b1;
|
implied = 1'b1;
|
Line 964... |
Line 981... |
end
|
end
|
else begin
|
else begin
|
branch = 1'b0;
|
branch = 1'b0;
|
end
|
end
|
end
|
end
|
ADC_ABS, AND_ABS, ASL_ABS, BIT_ABS, CMP_ABS, CPX_ABS, CPY_ABS, DEC_ABS, EOR_ABS, INC_ABS, JSR_ABS, LDA_ABS,
|
ADC_ABS, AND_ABS, ASL_ABS, BIT_ABS, CMP_ABS, CPX_ABS, CPY_ABS, DEC_ABS, EOR_ABS, INC_ABS, LDA_ABS,
|
LDX_ABS, LDY_ABS, LSR_ABS, ORA_ABS, ROL_ABS, ROR_ABS, SBC_ABS, STA_ABS, STX_ABS, STY_ABS: begin
|
LDX_ABS, LDY_ABS, LSR_ABS, ORA_ABS, ROL_ABS, ROR_ABS, SBC_ABS, STA_ABS, STX_ABS, STY_ABS: begin
|
absolute = 1'b1;
|
absolute = 1'b1;
|
end
|
end
|
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,
|
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,
|
SBC_ABX, STA_ABX: begin
|
SBC_ABX, STA_ABX: begin
|
Line 1013... |
Line 1030... |
pla = 1'b1;
|
pla = 1'b1;
|
end
|
end
|
PLP_IMP: begin
|
PLP_IMP: begin
|
plp = 1'b1;
|
plp = 1'b1;
|
end
|
end
|
|
JSR_ABS: begin
|
|
jsr = 1'b1;
|
|
end
|
default: begin
|
default: begin
|
$write("state : %b", state);
|
$write("state : %b", state);
|
if (reset_n == 1 && state != FETCH_OP_FIX_PC) begin // the processor is NOT being reset neither it is fixing the pc
|
if (reset_n == 1 && state != FETCH_OP_FIX_PC) begin // the processor is NOT being reset neither it is fixing the pc
|
$write("\nunknown OPCODE!!!!! 0x%h\n", ir);
|
$write("\nunknown OPCODE!!!!! 0x%h\n", ir);
|
$finish();
|
$finish();
|