update sim environment
This commit is contained in:
@@ -1,20 +1,17 @@
|
||||
TARGETS= timer interrupt_controller spi_controller
|
||||
TB=$(patsubst %, %_tb.sv, $(TARGETS))
|
||||
SRCS=$(shell find src/ -type f -name "*.*v")
|
||||
SRCS+=$(shell find ../ip/ -type f -name "*.*v" -not \( -name "*tmpl*" \))
|
||||
SRCS+=$(shell find ../src/ -type f -name "*.*v")
|
||||
|
||||
all: $(TARGETS)
|
||||
INC=$(shell find include/ -type f)
|
||||
|
||||
timer: timer_tb.sv
|
||||
iverilog -g2005-sv -s sim -o $@ $@_tb.sv ../$@.sv
|
||||
#TODO implement something like sources.list
|
||||
|
||||
spi_controller: spi_controller_tb.sv ../spi_controller.sv
|
||||
iverilog -g2005-sv -s sim -o $@ $@_tb.sv ../$@.sv
|
||||
TOP_MODULE=sim_top
|
||||
TARGET=sim_top
|
||||
|
||||
interrupt_controller: interrupt_controller_tb.sv
|
||||
iverilog -g2005-sv -s sim -o $@ $@_tb.sv ../$@.sv
|
||||
all:
|
||||
iverilog -g2005-sv -s $(TOP_MODULE) -o $(TARGET) $(INC) $(SRCS)
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
clean:
|
||||
rm -f $(TARGETS)
|
||||
rm -f *.vcd
|
||||
rm -f *.vvp
|
||||
rm -rf $(TARGET)
|
||||
@@ -5,10 +5,10 @@ localparam tIORT_u = 2;
|
||||
localparam BL = 1;
|
||||
localparam DDIO_TYPE = "SOFT";
|
||||
localparam DQ_WIDTH = 8;
|
||||
localparam DQ_GROUP = 4;
|
||||
localparam DQ_GROUP = 2;
|
||||
localparam BA_WIDTH = 2;
|
||||
localparam ROW_WIDTH = 13;
|
||||
localparam COL_WIDTH = 10;
|
||||
localparam COL_WIDTH = 9;
|
||||
localparam tPWRUP = 200000;
|
||||
localparam tRAS = 44;
|
||||
localparam tRC = 66;
|
||||
@@ -1,76 +0,0 @@
|
||||
module sim();
|
||||
|
||||
timeunit 10ns;
|
||||
timeprecision 1ns;
|
||||
|
||||
logic clk;
|
||||
logic reset;
|
||||
logic [2:0] addr;
|
||||
logic [7:0] i_data;
|
||||
logic [7:0] o_data;
|
||||
logic cs;
|
||||
logic rwb;
|
||||
|
||||
logic irqb_master;
|
||||
logic irqb0, irqb1, irqb2, irqb3, irqb4, irqb5, irqb6, irqb7;
|
||||
|
||||
interrupt_controller dut(
|
||||
.*);
|
||||
|
||||
always #100 clk = clk === 1'b0;
|
||||
|
||||
task write_reg(input logic [2:0] _addr, input logic [7:0] _data);
|
||||
@(negedge clk);
|
||||
cs <= '1;
|
||||
addr <= _addr;
|
||||
rwb <= '0;
|
||||
i_data <= '1;
|
||||
@(posedge clk);
|
||||
i_data <= _data;
|
||||
@(negedge clk);
|
||||
cs <= '0;
|
||||
rwb <= '1;
|
||||
endtask
|
||||
|
||||
task read_reg(input logic [2:0] _addr, output logic [7:0] _data);
|
||||
@(negedge clk);
|
||||
cs <= '1;
|
||||
addr <= _addr;
|
||||
rwb <= '1;
|
||||
i_data <= '1;
|
||||
@(posedge clk);
|
||||
_data <= o_data;
|
||||
@(negedge clk);
|
||||
cs <= '0;
|
||||
rwb <= '1;
|
||||
endtask
|
||||
|
||||
initial
|
||||
begin
|
||||
$dumpfile("interrupt_controller.vcd");
|
||||
$dumpvars(0,sim);
|
||||
end
|
||||
|
||||
initial begin
|
||||
reset <= '1;
|
||||
irqb0 <= '1;
|
||||
irqb1 <= '1;
|
||||
irqb2 <= '1;
|
||||
irqb3 <= '1;
|
||||
irqb4 <= '1;
|
||||
irqb5 <= '1;
|
||||
irqb6 <= '1;
|
||||
irqb7 <= '1;
|
||||
repeat(5) @(posedge clk);
|
||||
reset <= '0;
|
||||
|
||||
repeat(5) @(posedge clk);
|
||||
|
||||
irqb0 <= '0;
|
||||
|
||||
repeat(5) @(posedge clk);
|
||||
|
||||
$finish();
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -1,102 +0,0 @@
|
||||
module sim();
|
||||
|
||||
timeunit 10ns;
|
||||
timeprecision 1ns;
|
||||
|
||||
logic clk_50;
|
||||
|
||||
logic i_clk;
|
||||
logic i_rst;
|
||||
|
||||
logic i_cs;
|
||||
logic i_rwb;
|
||||
logic [1:0] i_addr;
|
||||
logic [7:0] i_data;
|
||||
logic [7:0] o_data;
|
||||
|
||||
logic o_spi_cs;
|
||||
logic o_spi_clk;
|
||||
logic o_spi_mosi;
|
||||
logic i_spi_miso;
|
||||
|
||||
spi_controller dut(.*);
|
||||
|
||||
always #1 clk_50 = clk_50 === 1'b0;
|
||||
always #100 i_clk = i_clk === 1'b0;
|
||||
|
||||
task write_reg(input logic [2:0] _addr, input logic [7:0] _data);
|
||||
@(negedge i_clk);
|
||||
i_cs <= '1;
|
||||
i_addr <= _addr;
|
||||
i_rwb <= '0;
|
||||
i_data <= '1;
|
||||
@(posedge i_clk);
|
||||
i_data <= _data;
|
||||
@(negedge i_clk);
|
||||
i_cs <= '0;
|
||||
i_rwb <= '1;
|
||||
endtask
|
||||
|
||||
task read_reg(input logic [2:0] _addr, output logic [7:0] _data);
|
||||
@(negedge i_clk);
|
||||
i_cs <= '1;
|
||||
i_addr <= _addr;
|
||||
i_rwb <= '1;
|
||||
i_data <= '1;
|
||||
@(posedge i_clk);
|
||||
_data <= o_data;
|
||||
@(negedge i_clk);
|
||||
i_cs <= '0;
|
||||
i_rwb <= '1;
|
||||
endtask
|
||||
|
||||
initial
|
||||
begin
|
||||
$dumpfile("spi_controller.vcd");
|
||||
$dumpvars(0,sim);
|
||||
end
|
||||
|
||||
logic [7:0] data;
|
||||
|
||||
initial begin
|
||||
i_rst <= '1;
|
||||
repeat(5) @(posedge i_clk);
|
||||
i_cs <= '0;
|
||||
i_rwb <= '1;
|
||||
i_addr <= '0;
|
||||
i_rst <= '0;
|
||||
|
||||
repeat(5) @(posedge i_clk);
|
||||
|
||||
write_reg(3, 1);
|
||||
write_reg(2, 8'hFF);
|
||||
data = (1 << 7);
|
||||
while(data & (1 << 7)) begin
|
||||
read_reg(3, data);
|
||||
end
|
||||
write_reg(3, 0);
|
||||
read_reg(1, data);
|
||||
assert(data == 8'h55);
|
||||
|
||||
repeat(50) @(posedge i_clk);
|
||||
|
||||
$finish();
|
||||
end
|
||||
|
||||
|
||||
logic [7:0] _spi_device_data;
|
||||
|
||||
initial begin
|
||||
_spi_device_data <= 8'h55;
|
||||
end
|
||||
|
||||
always @(edge o_spi_clk) begin
|
||||
if (o_spi_cs == '0) begin
|
||||
if (o_spi_clk == '1)
|
||||
i_spi_miso <= _spi_device_data[7];
|
||||
if (o_spi_clk == '0)
|
||||
_spi_device_data <= _spi_device_data << 1;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -49,7 +49,7 @@
|
||||
|
||||
module generic_sdr (Dq, Addr, Ba, Clk, Cke, Cs_n, Ras_n, Cas_n, We_n, Dqm);
|
||||
|
||||
`include "super6502_sdram_controller_define.vh"
|
||||
`include "include/super6502_sdram_controller_define.vh"
|
||||
|
||||
parameter tCK = 1000/fCK_MHz; // tCK ns Nominal Clock Cycle Time
|
||||
`ifdef CLK_200
|
||||
@@ -6,7 +6,5 @@ cpu_65c02 u_cpu();
|
||||
//TODO: also this
|
||||
super6502 u_dut();
|
||||
|
||||
//TODO: decide what to do here
|
||||
memory u_mem();
|
||||
|
||||
endmodule
|
||||
108
hw/efinix_fpga/simulation/src/verilog-6502/ALU.v
Executable file
108
hw/efinix_fpga/simulation/src/verilog-6502/ALU.v
Executable file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* ALU.
|
||||
*
|
||||
* AI and BI are 8 bit inputs. Result in OUT.
|
||||
* CI is Carry In.
|
||||
* CO is Carry Out.
|
||||
*
|
||||
* op[3:0] is defined as follows:
|
||||
*
|
||||
* 0011 AI + BI
|
||||
* 0111 AI - BI
|
||||
* 1011 AI + AI
|
||||
* 1100 AI | BI
|
||||
* 1101 AI & BI
|
||||
* 1110 AI ^ BI
|
||||
* 1111 AI
|
||||
*
|
||||
*/
|
||||
|
||||
module ALU( clk, op, right, AI, BI, CI, CO, BCD, OUT, V, Z, N, HC, RDY );
|
||||
input clk;
|
||||
input right;
|
||||
input [3:0] op; // operation
|
||||
input [7:0] AI;
|
||||
input [7:0] BI;
|
||||
input CI;
|
||||
input BCD; // BCD style carry
|
||||
output [7:0] OUT;
|
||||
output CO;
|
||||
output V;
|
||||
output Z;
|
||||
output N;
|
||||
output HC;
|
||||
input RDY;
|
||||
|
||||
reg [7:0] OUT;
|
||||
reg CO;
|
||||
wire V;
|
||||
wire Z;
|
||||
reg N;
|
||||
reg HC;
|
||||
|
||||
reg AI7;
|
||||
reg BI7;
|
||||
reg [8:0] temp_logic;
|
||||
reg [7:0] temp_BI;
|
||||
reg [4:0] temp_l;
|
||||
reg [4:0] temp_h;
|
||||
wire [8:0] temp = { temp_h, temp_l[3:0] };
|
||||
wire adder_CI = (right | (op[3:2] == 2'b11)) ? 0 : CI;
|
||||
|
||||
// calculate the logic operations. The 'case' can be done in 1 LUT per
|
||||
// bit. The 'right' shift is a simple mux that can be implemented by
|
||||
// F5MUX.
|
||||
always @* begin
|
||||
case( op[1:0] )
|
||||
2'b00: temp_logic = AI | BI;
|
||||
2'b01: temp_logic = AI & BI;
|
||||
2'b10: temp_logic = AI ^ BI;
|
||||
2'b11: temp_logic = AI;
|
||||
endcase
|
||||
|
||||
if( right )
|
||||
temp_logic = { AI[0], CI, AI[7:1] };
|
||||
end
|
||||
|
||||
// Add logic result to BI input. This only makes sense when logic = AI.
|
||||
// This stage can be done in 1 LUT per bit, using carry chain logic.
|
||||
always @* begin
|
||||
case( op[3:2] )
|
||||
2'b00: temp_BI = BI; // A+B
|
||||
2'b01: temp_BI = ~BI; // A-B
|
||||
2'b10: temp_BI = temp_logic; // A+A
|
||||
2'b11: temp_BI = 0; // A+0
|
||||
endcase
|
||||
end
|
||||
|
||||
// HC9 is the half carry bit when doing BCD add
|
||||
wire HC9 = BCD & (temp_l[3:1] >= 3'd5);
|
||||
|
||||
// CO9 is the carry-out bit when doing BCD add
|
||||
wire CO9 = BCD & (temp_h[3:1] >= 3'd5);
|
||||
|
||||
// combined half carry bit
|
||||
wire temp_HC = temp_l[4] | HC9;
|
||||
|
||||
// perform the addition as 2 separate nibble, so we get
|
||||
// access to the half carry flag
|
||||
always @* begin
|
||||
temp_l = temp_logic[3:0] + temp_BI[3:0] + adder_CI;
|
||||
temp_h = temp_logic[8:4] + temp_BI[7:4] + temp_HC;
|
||||
end
|
||||
|
||||
// calculate the flags
|
||||
always @(posedge clk)
|
||||
if( RDY ) begin
|
||||
AI7 <= AI[7];
|
||||
BI7 <= temp_BI[7];
|
||||
OUT <= temp[7:0];
|
||||
CO <= temp[8] | CO9;
|
||||
N <= temp[7];
|
||||
HC <= temp_HC;
|
||||
end
|
||||
|
||||
assign V = AI7 ^ BI7 ^ CO ^ N;
|
||||
assign Z = ~|OUT;
|
||||
|
||||
endmodule
|
||||
69
hw/efinix_fpga/simulation/src/verilog-6502/README.md
Normal file
69
hw/efinix_fpga/simulation/src/verilog-6502/README.md
Normal file
@@ -0,0 +1,69 @@
|
||||
========================================================
|
||||
A Verilog HDL version of the old MOS 6502 and 65C02 CPUs
|
||||
========================================================
|
||||
|
||||
Original 6502 core by Arlet Ottens
|
||||
|
||||
65C02 extensions by David Banks and Ed Spittles
|
||||
|
||||
==========
|
||||
6502 Core
|
||||
==========
|
||||
|
||||
Arlet's original 6502 core (cpu.v) is unchanged.
|
||||
|
||||
Note: the 6502/65C02 cores assumes a synchronous memory. This means
|
||||
that valid data (DI) is expected on the cycle *after* valid
|
||||
address. This allows direct connection to (Xilinx) block RAMs. When
|
||||
using asynchronous memory, I suggest registering the address/control
|
||||
lines for glitchless output signals.
|
||||
|
||||
[Also check out my new 65C02 project](https://github.com/Arlet/verilog-65c02)
|
||||
|
||||
Have fun.
|
||||
|
||||
==========
|
||||
65C02 Core
|
||||
==========
|
||||
|
||||
A second core (cpu_65c02.v) has been added, based on Arlet's 6502
|
||||
core, with additional 65C02 instructions and addressing modes:
|
||||
- PHX, PHY, PLX, PLY
|
||||
- BRA
|
||||
- INC A, DEC A
|
||||
- (zp) addressing mode
|
||||
- STZ
|
||||
- BIT zpx, absx, imm
|
||||
- TSB/TRB
|
||||
- JMP (,X)
|
||||
- NOPs (optional)
|
||||
- 65C02 BCD N/Z flags (optional, disabled)
|
||||
|
||||
The Rockwell/WDC specific instructions (RMB/SMB/BBR/BBS/WAI/STP) are
|
||||
not currently implemented
|
||||
|
||||
The 65C02 core passes the Dormann 6502 test suite, and also passes the
|
||||
Dormann 65C02 test suite if the optional support for NOPs and 65C02
|
||||
BCD flags is enabled.
|
||||
|
||||
It has been tested as a BBC Micro "Matchbox" 65C02 Co Processor, in a
|
||||
XC6SLX9-2 FPGA, running at 80MHz using 64KB of internel block RAM. It
|
||||
just meets timing at 80MHz in this environment. It successfully runs
|
||||
BBC Basic IV and Tube Elite.
|
||||
|
||||
============
|
||||
Known Issues
|
||||
============
|
||||
|
||||
The Matchbox Co Processor needed one wait state (via RDY) to be added
|
||||
to each ROM access (only needed early in the boot process, as
|
||||
eventually everything runs from RAM). The DIHOLD logic did not work
|
||||
correctly with a single wait state, and so has been commented out.
|
||||
|
||||
I now believe the correct fix is actually just:
|
||||
|
||||
always @(posedge clk )
|
||||
if( RDY )
|
||||
DIHOLD <= DI;
|
||||
|
||||
assign DIMUX = ~RDY ? DIHOLD : DI;
|
||||
1220
hw/efinix_fpga/simulation/src/verilog-6502/cpu.v
Normal file
1220
hw/efinix_fpga/simulation/src/verilog-6502/cpu.v
Normal file
File diff suppressed because it is too large
Load Diff
1418
hw/efinix_fpga/simulation/src/verilog-6502/cpu_65c02.v
Normal file
1418
hw/efinix_fpga/simulation/src/verilog-6502/cpu_65c02.v
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,75 +0,0 @@
|
||||
module sim();
|
||||
|
||||
timeunit 10ns;
|
||||
timeprecision 1ns;
|
||||
|
||||
logic clk;
|
||||
logic rwb;
|
||||
logic clk_50;
|
||||
logic reset;
|
||||
|
||||
logic [2:0] addr;
|
||||
logic [7:0] i_data;
|
||||
logic [7:0] o_data;
|
||||
logic cs;
|
||||
logic irq;
|
||||
|
||||
timer dut(
|
||||
.*);
|
||||
|
||||
always #1 clk_50 = clk_50 === 1'b0;
|
||||
always #100 clk = clk === 1'b0;
|
||||
|
||||
task write_reg(input logic [2:0] _addr, input logic [7:0] _data);
|
||||
@(negedge clk);
|
||||
cs <= '1;
|
||||
addr <= _addr;
|
||||
rwb <= '0;
|
||||
i_data <= '1;
|
||||
@(posedge clk);
|
||||
i_data <= _data;
|
||||
@(negedge clk);
|
||||
cs <= '0;
|
||||
rwb <= '1;
|
||||
endtask
|
||||
|
||||
task read_reg(input logic [2:0] _addr, output logic [7:0] _data);
|
||||
@(negedge clk);
|
||||
cs <= '1;
|
||||
addr <= _addr;
|
||||
rwb <= '1;
|
||||
i_data <= '1;
|
||||
@(posedge clk);
|
||||
_data <= o_data;
|
||||
@(negedge clk);
|
||||
cs <= '0;
|
||||
rwb <= '1;
|
||||
endtask
|
||||
|
||||
initial
|
||||
begin
|
||||
$dumpfile("timer.vcd");
|
||||
$dumpvars(0,sim);
|
||||
end
|
||||
|
||||
logic [7:0] read_data;
|
||||
|
||||
initial begin
|
||||
reset <= '1;
|
||||
repeat(5) @(posedge clk);
|
||||
reset <= '0;
|
||||
|
||||
write_reg(5, 16);
|
||||
|
||||
repeat(1024) @(posedge clk);
|
||||
|
||||
repeat(10) begin
|
||||
read_reg(0, read_data);
|
||||
$display("Read: %d", read_data);
|
||||
repeat(1024) @(posedge clk);
|
||||
end
|
||||
$finish();
|
||||
|
||||
end
|
||||
|
||||
endmodule
|
||||
Submodule hw/efinix_fpga/simulation/verilog-6502 deleted from a5f605d00d
@@ -245,10 +245,11 @@ logic [3:0] o_dbg_BA;
|
||||
logic [25:0] o_dbg_ADDR;
|
||||
logic [31:0] o_dbg_DATA_out;
|
||||
logic [31:0] o_dbg_DATA_in;
|
||||
logic o_sdr_init_done;
|
||||
logic sdr_init_done;
|
||||
logic [3:0] o_sdr_state;
|
||||
|
||||
assign o_ref_req = o_dbg_ref_req;
|
||||
assign o_sdr_init_done = sdr_init_done;
|
||||
|
||||
|
||||
sdram_controller u_sdram_controller(
|
||||
@@ -265,7 +266,7 @@ sdram_controller u_sdram_controller(
|
||||
.i_din(r_write_data), //Data to write to SDRAM. Twice normal width when running at half speed (hence the even addresses)
|
||||
.i_dm(r_dm), //dm (r_dm)
|
||||
.o_dout(w_data_o), //Data read from SDRAM, doubled as above.
|
||||
.o_sdr_init_done(o_sdr_init_done), //Indicates that the SDRAM initialization is done.
|
||||
.o_sdr_init_done(sdr_init_done), //Indicates that the SDRAM initialization is done.
|
||||
.o_wr_ack(w_wr_ack), //Write acknowledge, handshake with we
|
||||
.o_rd_ack(w_rd_ack), //Read acknowledge, handshake with re
|
||||
.o_rd_valid(w_rd_valid),//Read valid. The data on o_dout is valid
|
||||
|
||||
Reference in New Issue
Block a user