update sim environment

This commit is contained in:
Byron Lathi
2023-09-21 20:35:52 -07:00
parent e50203dd3e
commit 1f503b2d80
13 changed files with 2831 additions and 274 deletions

View File

@@ -1,20 +1,17 @@
TARGETS= timer interrupt_controller spi_controller SRCS=$(shell find src/ -type f -name "*.*v")
TB=$(patsubst %, %_tb.sv, $(TARGETS)) 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 #TODO implement something like sources.list
iverilog -g2005-sv -s sim -o $@ $@_tb.sv ../$@.sv
spi_controller: spi_controller_tb.sv ../spi_controller.sv TOP_MODULE=sim_top
iverilog -g2005-sv -s sim -o $@ $@_tb.sv ../$@.sv TARGET=sim_top
interrupt_controller: interrupt_controller_tb.sv all:
iverilog -g2005-sv -s sim -o $@ $@_tb.sv ../$@.sv iverilog -g2005-sv -s $(TOP_MODULE) -o $(TARGET) $(INC) $(SRCS)
.PHONY: clean .PHONY: clean
clean: clean:
rm -f $(TARGETS) rm -rf $(TARGET)
rm -f *.vcd
rm -f *.vvp

View File

@@ -5,10 +5,10 @@ localparam tIORT_u = 2;
localparam BL = 1; localparam BL = 1;
localparam DDIO_TYPE = "SOFT"; localparam DDIO_TYPE = "SOFT";
localparam DQ_WIDTH = 8; localparam DQ_WIDTH = 8;
localparam DQ_GROUP = 4; localparam DQ_GROUP = 2;
localparam BA_WIDTH = 2; localparam BA_WIDTH = 2;
localparam ROW_WIDTH = 13; localparam ROW_WIDTH = 13;
localparam COL_WIDTH = 10; localparam COL_WIDTH = 9;
localparam tPWRUP = 200000; localparam tPWRUP = 200000;
localparam tRAS = 44; localparam tRAS = 44;
localparam tRC = 66; localparam tRC = 66;

View File

@@ -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

View File

@@ -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

View File

@@ -49,7 +49,7 @@
module generic_sdr (Dq, Addr, Ba, Clk, Cke, Cs_n, Ras_n, Cas_n, We_n, Dqm); 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 parameter tCK = 1000/fCK_MHz; // tCK ns Nominal Clock Cycle Time
`ifdef CLK_200 `ifdef CLK_200

View File

@@ -6,7 +6,5 @@ cpu_65c02 u_cpu();
//TODO: also this //TODO: also this
super6502 u_dut(); super6502 u_dut();
//TODO: decide what to do here
memory u_mem();
endmodule endmodule

View 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

View 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;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -245,10 +245,11 @@ logic [3:0] o_dbg_BA;
logic [25:0] o_dbg_ADDR; logic [25:0] o_dbg_ADDR;
logic [31:0] o_dbg_DATA_out; logic [31:0] o_dbg_DATA_out;
logic [31:0] o_dbg_DATA_in; logic [31:0] o_dbg_DATA_in;
logic o_sdr_init_done; logic sdr_init_done;
logic [3:0] o_sdr_state; logic [3:0] o_sdr_state;
assign o_ref_req = o_dbg_ref_req; assign o_ref_req = o_dbg_ref_req;
assign o_sdr_init_done = sdr_init_done;
sdram_controller u_sdram_controller( 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_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) .i_dm(r_dm), //dm (r_dm)
.o_dout(w_data_o), //Data read from SDRAM, doubled as above. .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_wr_ack(w_wr_ack), //Write acknowledge, handshake with we
.o_rd_ack(w_rd_ack), //Read acknowledge, handshake with re .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 .o_rd_valid(w_rd_valid),//Read valid. The data on o_dout is valid