URL
https://opencores.org/ocsvn/t6507lp/t6507lp/trunk
Subversion Repositories t6507lp
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 70 to Rev 71
- ↔ Reverse comparison
Rev 70 → Rev 71
/t6507lp/trunk/rtl/verilog/t6507lp_fsm_tb.v
46,8 → 46,8
`timescale 1ns / 1ps |
|
module t6507lp_fsm_tb(); |
reg clk_in; |
reg rst_in_n; |
reg clk; |
reg reset_n; |
reg [7:0] alu_result; |
reg [7:0] alu_status; |
reg [7:0] data_in; |
61,31 → 61,53
|
`include "../T6507LP_Package.v" |
|
t6507lp_fsm #(8,13) my_dut(clk_in, rst_in_n, alu_result, alu_status, data_in, address, control, data_out, alu_opcode, alu_a, alu_enable); |
t6507lp_fsm #(8,13) my_dut(clk, reset_n, alu_result, alu_status, data_in, address, control, data_out, alu_opcode, alu_a, alu_enable); |
|
always #10 clk_in = ~clk_in; |
always #10 clk = ~clk; |
|
reg[7:0] fake_mem[20:0]; |
|
initial begin |
clk_in = 0; |
data_in = ASL_ACC; |
rst_in_n = 1'b0; |
alu_result = 0; |
clk = 0; |
reset_n = 1'b0; |
alu_result = 8'h01; |
alu_status = 0; |
|
@(negedge clk_in) //will wait for next negative edge of the clock (t=20) |
rst_in_n=1'b1; |
|
@(negedge clk_in) //will wait for next negative edge of the clock (t=40) |
data_in = ROL_ACC; |
fake_mem[0] = ASL_ACC; // testing ACC mode |
fake_mem[1] = ADC_IMM; // testing IMM mode |
fake_mem[2] = 8'h27; |
fake_mem[3] = JMP_ABS; // testing ABS mode, JMP type |
fake_mem[4] = 8'h09; |
fake_mem[5] = 8'h00; |
fake_mem[6] = ASL_ACC; // wont be executed |
fake_mem[7] = ASL_ACC; // wont be executed |
fake_mem[8] = ASL_ACC; // wont be executed |
fake_mem[9] = ASL_ACC; // wont be executed |
fake_mem[10] = LDA_ABS; // testing ABS mode, READ type. A = MEM[0002]. (a=27) |
fake_mem[11] = 8'h02; |
fake_mem[12] = 8'h00; |
fake_mem[13] = ASL_ABS; // testing ABS mode, READ_MODIFY_WRITE type. should overwrite the first ASL_ACC |
fake_mem[14] = 8'h04; |
fake_mem[15] = 8'h00; |
fake_mem[16] = 8'h00; |
|
@(negedge clk_in) //will wait for next negative edge of the clock (t=60) |
data_in = ROR_ACC; |
@(negedge clk) // will wait for next negative edge of the clock (t=20) |
reset_n=1'b1; |
|
|
@(negedge clk_in) //will wait for next negative edge of the clock (t=80) |
@(negedge clk_in) //will wait for next negative edge of the clock (t=100) |
@(negedge clk_in) //will wait for next negative edge of the clock (t=120) |
#500; |
$finish; // to shut down the simulation |
end //initial |
|
always @(clk) begin |
if (control == 0) begin // MEM_READ |
data_in <= fake_mem[address]; |
$write("\nreading from mem position %h: %h", address, fake_mem[address]); |
end |
else if (control == 1'b1) begin // MEM_WRITE |
fake_mem[address] <= data_out; |
$write("\nreading from mem position %h: %h", address, fake_mem[address]); |
end |
end |
|
endmodule |
/t6507lp/trunk/rtl/verilog/t6507lp_fsm.v
48,13 → 48,12
|
`timescale 1ns / 1ps |
|
module t6507lp_fsm(clk_in, rst_in_n, alu_result, alu_status, data_in, address, control, data_out, alu_opcode, alu_a, alu_enable); |
|
module t6507lp_fsm(clk, reset_n, alu_result, alu_status, data_in, address, control, data_out, alu_opcode, alu_a, alu_enable); |
parameter DATA_SIZE = 4'd8; |
parameter ADDR_SIZE = 4'd13; |
|
input clk_in; |
input rst_in_n; |
input clk; |
input reset_n; |
input [DATA_SIZE-1:0] alu_result; |
input [DATA_SIZE-1:0] alu_status; |
input [DATA_SIZE-1:0] data_in; |
72,6 → 71,10
localparam FETCH_OP_CALC = 4'b0001; |
localparam FETCH_LOW = 4'b0010; |
localparam FETCH_HIGH = 4'b0011; |
localparam READ_MEM = 4'b0100; |
localparam DUMMY_WRT_CALC = 4'b0101; |
localparam WRITE_MEM = 4'b0110; |
localparam FETCH_OP_CALC_PARAM = 4'b0111; |
|
// OPCODES TODO: verify how this get synthesised |
`include "../T6507LP_Package.v" |
83,7 → 86,7
reg [ADDR_SIZE-1:0] pc; // program counter |
reg [DATA_SIZE-1:0] sp; // stack pointer |
reg [DATA_SIZE-1:0] ir; // instruction register |
reg [ADDR_SIZE:0] temp_add; // temporary address |
reg [ADDR_SIZE:0] temp_addr; // temporary address |
reg [DATA_SIZE-1:0] temp_data; // temporary data |
|
reg [3:0] state, next_state; // current and next state registers |
109,19 → 112,23
wire [ADDR_SIZE-1:0] next_pc; |
assign next_pc = pc + 13'b0000000000001; |
|
always @ (posedge clk_in or negedge rst_in_n) begin // sequencial always block |
if (rst_in_n == 1'b0) begin |
// TODO: all internal flip-flops must assume default values |
|
always @ (posedge clk or negedge reset_n) begin // sequencial always block |
if (reset_n == 1'b0) begin |
// all registers must assume default values |
pc <= 0; // TODO: this is written somewhere. something about a reset vector. must be checked. |
sp <= 0; // TODO: the default is not 0. maybe $0100 or something like that. must be checked. |
ir <= 0; |
temp_add <= 0; |
temp_addr <= 0; |
temp_data <= 0; |
state <= RESET; |
// registered outputs also receive default values |
address <= 0; |
control <= 0; // check if these 2 shouldnt be on the other always block along with the address |
data_out <= 0; |
end |
else begin |
state <= next_state; |
control <= MEM_READ; |
|
case (state) |
RESET: begin |
130,65 → 137,78
FETCH_OP: begin // this state is the simplest one. it is a simple fetch that must be done when the cpu was reset or |
// the last cycle was a memory write. |
pc <= next_pc; |
address <= next_pc; |
ir <= data_in; |
end |
FETCH_OP_CALC: begin // this is the pipeline happening! |
FETCH_OP_CALC, FETCH_OP_CALC_PARAM: begin // this is the pipeline happening! |
pc <= next_pc; |
address <= next_pc; |
ir <= data_in; |
end |
FETCH_LOW: begin // in this state the opcode is already known so truly execution begins |
if (accumulator || implied) begin |
pc <= pc; // is this better? |
address <= pc; |
end |
else if (immediate) begin |
pc <= next_pc; |
address <= next_pc; |
temp_data <= data_in; // the follow-up byte is saved in temp_data |
end |
else if (absolute) begin |
pc <= next_pc; |
address <= next_pc; |
temp_addr[7:0] <= data_in; |
end |
end |
default: begin |
$write("unknown state"); // TODO: check if synth really ignores this 2 lines. Otherwise wrap it with a `ifdef |
$finish(0); |
FETCH_HIGH: begin |
if (jump) begin |
pc <= {data_in[4:0], temp_addr}; // PCL <= first byte, PCH <= second byte |
address <= {data_in[4:0], temp_addr}; |
end |
else begin |
if (write) begin |
pc <= next_pc; |
temp_addr[12:8] <= data_in[4:0]; |
address <= {data_in[4:0],temp_addr[7:0]}; |
control <= MEM_WRITE; |
end |
else begin // read_modify_write or just read |
pc <= next_pc; |
temp_addr[12:8] <= data_in[4:0]; |
address <= {data_in[4:0],temp_addr[7:0]}; |
end |
end |
//else begin |
// $write("FETCHHIGH PROBLEM"); |
// $finish(0); |
//end |
end |
|
endcase |
end |
end |
|
always @ (posedge clk_in or negedge rst_in_n) begin |
if (rst_in_n == 1'b0) begin |
// TODO: all outputs must assume default values |
address <= 0; |
control <= 0; // one bit is enough? read = 0, write = 1 |
data_out <= 0; |
alu_opcode <= 0; |
alu_a <= 0; |
alu_enable <= 0; |
end |
else begin |
|
address <= pc; |
|
case (state) |
RESET: begin |
// The processor was reset. No output whatsoever. |
READ_MEM: begin |
if (read_modify_write) begin |
pc <= pc; |
address <= temp_addr; |
control <= MEM_WRITE; |
temp_data <= data_in; |
data_out <= data_in; // writeback the same value |
end |
else begin |
pc <= pc; |
address <= pc; |
temp_data <= data_in; |
end |
end |
FETCH_OP: begin |
// it is a simple fetch. no output change. |
DUMMY_WRT_CALC: begin |
pc <= pc; |
address <= temp_addr; |
control <= MEM_WRITE; |
data_out <= alu_result; |
end |
FETCH_OP_CALC: begin // this is the pipeline happening! |
alu_opcode <= ir; |
alu_a <= temp_data; |
alu_enable <= 1'b1; |
WRITE_MEM: begin |
pc <= pc; |
address <= pc; |
data_out = 8'hzz; |
end |
FETCH_LOW: begin // in this state the opcode is already known so truly execution begins |
if (accumulator || implied) begin |
alu_opcode <= ir; |
alu_enable <= 1'b1; |
end |
else begin // nothing? |
|
end |
end |
default: begin |
$write("unknown state"); // TODO: check if synth really ignores this 2 lines. Otherwise wrap it with a `ifdef |
$finish(0); |
196,50 → 216,92
|
endcase |
end |
|
end |
|
always @ (*) begin // this is the next_state logic always block |
//address = pc; |
always @ (*) begin // this is the next_state logic and the output logic always block |
//control = MEM_READ; |
//data_out = 8'h00; |
//alu_opcode = 8'h00; |
//alu_a = 8'h00; |
//alu_enable = 1'b0; |
|
alu_opcode = 8'h00; |
alu_a = 8'h00; |
alu_enable = 1'b0; |
//address = pc; |
|
next_state = RESET; // this prevents the latch |
next_state = RESET; // this prevents the latch |
|
begin |
case (state) |
RESET: begin |
case (state) |
RESET: begin |
next_state = FETCH_OP; |
end |
FETCH_OP: begin |
next_state = FETCH_LOW; |
//address = pc; |
end |
FETCH_OP_CALC: begin |
next_state = FETCH_LOW; |
alu_opcode = ir; |
alu_enable = 1'b1; |
//address = next_pc; |
|
end |
FETCH_OP_CALC_PARAM: begin |
next_state = FETCH_LOW; |
alu_opcode = ir; |
alu_enable = 1'b1; |
alu_a = temp_data; |
//address = next_pc; |
end |
FETCH_LOW: begin |
if (accumulator || implied) begin |
alu_opcode = ir; |
alu_enable = 1'b1; |
next_state = FETCH_OP; |
end |
else if (immediate) begin |
next_state = FETCH_OP_CALC_PARAM; |
end |
else begin // at least the absolute address mode falls here |
next_state = FETCH_HIGH; |
end |
//address = next_pc; |
|
end |
FETCH_HIGH: begin |
if (jump) begin |
next_state = FETCH_OP; |
end |
FETCH_OP: begin |
next_state = FETCH_LOW; |
else if (read || read_modify_write) begin |
next_state = READ_MEM; |
end |
FETCH_OP_CALC: begin |
next_state = FETCH_LOW; |
//alu_opcode = ir; |
//alu_enable = 1'b1; |
else if (write) begin |
next_state = WRITE_MEM; |
end |
FETCH_LOW: begin |
if (accumulator || implied) begin |
//alu_opcode = data_in; |
//alu_enable = 1'b1; |
next_state = FETCH_OP; |
end |
else if (immediate) begin |
next_state = FETCH_OP_CALC; |
end |
else begin // at least the immediate address mode falls here |
next_state = FETCH_HIGH; |
end |
else begin |
$write("unknown behavior"); |
$finish(0); |
end |
default: begin |
next_state = RESET; |
end |
READ_MEM: begin |
if (read) begin |
next_state = FETCH_OP_CALC_PARAM; |
end |
endcase |
end |
else if (read_modify_write) begin |
next_state = DUMMY_WRT_CALC; |
end |
end |
DUMMY_WRT_CALC: begin |
alu_opcode = ir; |
alu_enable = 1'b1; |
alu_a = data_in; |
next_state = WRITE_MEM; |
end |
WRITE_MEM: begin |
next_state = FETCH_OP; |
end |
default: begin |
next_state = RESET; |
end |
endcase |
end |
|
// this always block is responsible for updating the address mode |
293,34 → 355,29
ORA_IDY, SBC_IDY, STA_IDY: begin // all these opcodes are 8'hX1; TODO: optimize this |
indirect = 1'b1; |
end |
default: begin |
$write("unknown OPCODE!"); |
$finish(); |
end |
endcase |
|
case (ir) |
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, |
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, |
DEC_ABX: begin |
read_modify_write = 1'b1; |
end |
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 |
write = 1'b1; |
end |
default: begin // this should work fine since the previous case statement will detect the unknown/undocumented/unsupported opcodes |
read = 1'b1; |
end |
endcase |
|
if (data_in == JMP_ABS || data_in == JMP_IND) begin // the opcodes are 8'h4C and 8'h6C |
if (ir == JMP_ABS || ir == JMP_IND) begin // the opcodes are 8'h4C and 8'h6C |
jump = 1'b1; |
end |
|
// if (data_in == ) |
|
/*LDA_IMM = 8'hA9, |
LDA_ZPG = 8'hA5, |
LDA_ZPX = 8'hB5, |
LDA_ABS = 8'hAD, |
LDA_ABX = 8'hBD, |
LDA_ABY = 8'hB9, |
LDA_IDX = 8'hA1, |
LDA_IDY = 8'hB1; |
LDX_IMM = 8'hA2, |
LDX_ZPG = 8'hA6, |
LDX_ZPY = 8'hB6, |
LDX_ABS = 8'hAE, |
LDX_ABY = 8'hBE; |
LDY_IMM = 8'hA0, |
LDY_ZPG = 8'hA4, |
LDY_ZPX = 8'hB4, |
LDY_ABS = 8'hAC, |
LDY_ABX = 8'hBC; |
*/ |
|
end // no way |
endmodule |
|