diff --git a/.gitmodules b/.gitmodules index 21b2181..0a0a7e3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "sw/cc65"] path = sw/cc65 url = https://git.byronlathi.com/bslathi19/cc65 +[submodule "hw/efinix_fpga/simulation/src/verilog-6502"] + path = hw/efinix_fpga/simulation/src/verilog-6502 + url = https://git.byronlathi.com/bslathi19/verilog-6502 diff --git a/hw/efinix_fpga/simulation/Makefile b/hw/efinix_fpga/simulation/Makefile index c3b0f2e..773850c 100644 --- a/hw/efinix_fpga/simulation/Makefile +++ b/hw/efinix_fpga/simulation/Makefile @@ -1,20 +1,27 @@ -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 +TEST_PROGRAM_NAME?=loop_test -spi_controller: spi_controller_tb.sv ../spi_controller.sv - iverilog -g2005-sv -s sim -o $@ $@_tb.sv ../$@.sv +TEST_PROGRAM?=$(REPO_TOP)/sw/test_code/$(TEST_PROGRAM_NAME)/$(TEST_PROGRAM_NAME).hex -interrupt_controller: interrupt_controller_tb.sv - iverilog -g2005-sv -s sim -o $@ $@_tb.sv ../$@.sv +#TODO implement something like sources.list + +TOP_MODULE=sim_top +TARGET=sim_top +INIT_MEM=init_hex.mem +FLAGS=-DSIM -DRTL_SIM + +all: $(INIT_MEM) + iverilog -g2005-sv $(FLAGS) -s $(TOP_MODULE) -o $(TARGET) $(INC) $(SRCS) + +$(INIT_MEM): + cp $(TEST_PROGRAM) ./init_hex.mem .PHONY: clean - clean: - rm -f $(TARGETS) - rm -f *.vcd - rm -f *.vvp \ No newline at end of file + rm -rf $(TARGET) + rm -rf $(INIT_MEM) \ No newline at end of file diff --git a/hw/efinix_fpga/simulation/include/super6502_sdram_controller_define.vh b/hw/efinix_fpga/simulation/include/super6502_sdram_controller_define.vh new file mode 100644 index 0000000..3bbfa9a --- /dev/null +++ b/hw/efinix_fpga/simulation/include/super6502_sdram_controller_define.vh @@ -0,0 +1,80 @@ +// ============================================================================= +// Generated by efx_ipmgr +// Version: 2023.1.150 +// IP Version: 5.0 +// ============================================================================= + +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2013-2023 Efinix Inc. All rights reserved. +// +// This document contains proprietary information which is +// protected by copyright. All rights are reserved. This notice +// refers to original work by Efinix, Inc. which may be derivitive +// of other work distributed under license of the authors. In the +// case of derivative work, nothing in this notice overrides the +// original author's license agreement. Where applicable, the +// original license agreement is included in it's original +// unmodified form immediately below this header. +// +// WARRANTY DISCLAIMER. +// THE DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND +// EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH +// RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES, +// INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR +// PURPOSE. SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED +// WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE. +// +// LIMITATION OF LIABILITY. +// NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY +// INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT +// MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY +// OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT, +// SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY +// CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF +// GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR +// MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN +// THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER +// (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE +// BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO +// NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR +// CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT +// APPLY TO LICENSEE. +// +//////////////////////////////////////////////////////////////////////////////// + +localparam fSYS_MHz = 100; +localparam fCK_MHz = 200; +localparam tIORT_u = 2; +localparam CL = 3; +localparam BL = 1; +localparam DDIO_TYPE = "SOFT"; +localparam DQ_WIDTH = 8; +localparam DQ_GROUP = 2; +localparam BA_WIDTH = 2; +localparam ROW_WIDTH = 13; +localparam COL_WIDTH = 9; +localparam tPWRUP = 200000; +localparam tRAS = 44; +localparam tRAS_MAX = 120000; +localparam tRC = 66; +localparam tRCD = 20; +localparam tREF = 64000000; +localparam tRFC = 66; +localparam tRP = 20; +localparam tWR = 2; +localparam tMRD = 2; +localparam SDRAM_MODE = "Native"; +localparam DATA_RATE = 2; +localparam AXI_AWADDR_WIDTH = 24; +localparam AXI_WDATA_WIDTH = 32; +localparam AXI_ARADDR_WIDTH = 24; +localparam AXI_RDATA_WIDTH = 32; +localparam AXI_AWID_WIDTH = 4; +localparam AXI_AWUSER_WIDTH = 2; +localparam AXI_WUSER_WIDTH = 2; +localparam AXI_BID_WIDTH = 4; +localparam AXI_BUSER_WIDTH = 2; +localparam AXI_ARID_WIDTH = 4; +localparam AXI_ARUSER_WIDTH = 3; +localparam AXI_RUSER_WIDTH = 3; diff --git a/hw/efinix_fpga/simulation/interrupt_controller_tb.sv b/hw/efinix_fpga/simulation/interrupt_controller_tb.sv deleted file mode 100644 index 7cd41e8..0000000 --- a/hw/efinix_fpga/simulation/interrupt_controller_tb.sv +++ /dev/null @@ -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 diff --git a/hw/efinix_fpga/simulation/spi_controller_tb.sv b/hw/efinix_fpga/simulation/spi_controller_tb.sv deleted file mode 100644 index ad20da4..0000000 --- a/hw/efinix_fpga/simulation/spi_controller_tb.sv +++ /dev/null @@ -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 diff --git a/hw/efinix_fpga/simulation/src/generic_sdr.v b/hw/efinix_fpga/simulation/src/generic_sdr.v new file mode 100644 index 0000000..8cbcfcb --- /dev/null +++ b/hw/efinix_fpga/simulation/src/generic_sdr.v @@ -0,0 +1,1145 @@ +/************************************************************************** +* +* File Name: sdr.v +* Version: 2.2 +* Date: October 12th, 2010 +* Model: BUS Functional +* Simulator: Model Technology +* +* Dependencies: None +* +* Email: modelsupport@micron.com +* Company: Micron Technology, Inc. +* +* Description: Micron SDRAM Verilog model +* +* Limitation: - Doesn't check for refresh timing +* +* Note: - Set simulator resolution to "ps" accuracy +* - Set Debug = 0 to disable $display messages +* +* Disclaimer: THESE DESIGNS ARE PROVIDED "AS IS" WITH NO WARRANTY +* WHATSOEVER AND MICRON SPECIFICALLY DISCLAIMS ANY +* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR +* A PARTICULAR PURPOSE, OR AGAINST INFRINGEMENT. +* +* Copyright � 2001 Micron Semiconductor Products, Inc. +* All rights researved +* +* Rev Author Date Changes +* --- -------------------------- --------------------------------------- +* 2.3 SH 05/12/2016 - Update tAC, tHZ timing +* Micron Technology Inc. +* +* 2.2 SH 10/12/2010 - Combine all parts into sdr_parameters.vh +* Micron Technology Inc. +* +* 2.1 SH 06/06/2002 - Typo in bank multiplex +* Micron Technology Inc. +* +* 2.0 SH 04/30/2002 - Second release +* Micron Technology Inc. +* +**************************************************************************/ + +`timescale 1ns / 1ps +`define x8 +`define CLK_200 +`define SYS_CLK_100 + +module generic_sdr (Dq, Addr, Ba, Clk, Cke, Cs_n, Ras_n, Cas_n, We_n, Dqm); + +`include "include/super6502_sdram_controller_define.vh" + +parameter tCK = 1000/fCK_MHz; // tCK ns Nominal Clock Cycle Time +`ifdef CLK_200 + parameter real tAC3 = 4.5; // tAC3 ns Access time from CLK (pos edge) CL = 3 + parameter real tAC2 = 4.5; // tAC2 ns Access time from CLK (pos edge) CL = 2 + parameter real tAC1 = 4.5; // tAC1 ns Parameter definition for compilation - CL = 1 illegal for sg75 +`elsif CLK_166 + parameter real tAC3 = 5.4; // tAC3 ns Access time from CLK (pos edge) CL = 3 + parameter real tAC2 = 5.4; // tAC2 ns Access time from CLK (pos edge) CL = 2 + parameter real tAC1 = 5.4; // tAC1 ns Parameter definition for compilation - CL = 1 illegal for sg75 +`elsif CLK_133 + parameter real tAC3 = 6.0; // tAC3 ns Access time from CLK (pos edge) CL = 3 + parameter real tAC2 = 6.0; // tAC2 ns Access time from CLK (pos edge) CL = 2 + parameter real tAC1 = 6.0; // tAC1 ns Parameter definition for compilation - CL = 1 illegal for sg75 +`endif + +`ifdef CLK_200 + parameter real tHZ3 = 4.5; // tHZ3 ns Data Out High Z time - CL = 3 + parameter real tHZ2 = 4.5; // tHZ2 ns Data Out High Z time - CL = 2 + parameter real tHZ1 = 4.5; // tHZ1 ns Parameter definition for compilation - CL = 1 illegal for sg75 +`elsif CLK_166 + parameter real tHZ3 = 5.4; // tHZ3 ns Data Out High Z time - CL = 3 + parameter real tHZ2 = 5.4; // tHZ2 ns Data Out High Z time - CL = 2 + parameter real tHZ1 = 5.4; // tHZ1 ns Parameter definition for compilation - CL = 1 illegal for sg75 +`elsif CLK_133 + parameter real tHZ3 = 6.0; // tHZ3 ns Data Out High Z time - CL = 3 + parameter real tHZ2 = 6.0; // tHZ2 ns Data Out High Z time - CL = 2 + parameter real tHZ1 = 6.0; // tHZ1 ns Parameter definition for compilation - CL = 1 illegal for sg75 +`endif + +parameter tOH = 2.7; // tOH ns Data Out Hold time +parameter tRRD = 2.0; // tRRD tCK Active bank a to Active bank b command time (2 * tCK) +parameter tWRa = tCK; // tWR ns Write recovery time (auto-precharge mode - must add 1 CLK) +parameter tWRm = 2*tCK; // tWR ns Write recovery time +parameter ADDR_BITS = ROW_WIDTH; // Set this parameter to control how many Address bits are used +parameter ROW_BITS = ROW_WIDTH; // Set this parameter to control how many Row bits are used +parameter COL_BITS = COL_WIDTH; // Set this parameter to control how many Column bits are used +parameter DQ_BITS = DQ_WIDTH; // Set this parameter to control how many Data bits are used +parameter DM_BITS = 1; // Set this parameter to control how many DM bits are used +parameter BA_BITS = BA_WIDTH; // Bank bits +parameter mem_sizes = 2**(ROW_BITS+COL_BITS) - 1; + + input Clk; + input Cke; + input Cs_n; + input Ras_n; + input Cas_n; + input We_n; + input [ADDR_BITS - 1 : 0] Addr; + input [BA_BITS - 1 : 0] Ba; + inout [DQ_BITS - 1 : 0] Dq; + input [DM_BITS - 1 : 0] Dqm; + + reg [DQ_BITS - 1 : 0] Bank0 [0 : mem_sizes]; + reg [DQ_BITS - 1 : 0] Bank1 [0 : mem_sizes]; + reg [DQ_BITS - 1 : 0] Bank2 [0 : mem_sizes]; + reg [DQ_BITS - 1 : 0] Bank3 [0 : mem_sizes]; + + reg [1 : 0] Bank_addr [0 : 3]; // Bank Address Pipeline + reg [COL_BITS - 1 : 0] Col_addr [0 : 3]; // Column Address Pipeline + reg [3 : 0] Command [0 : 3]; // Command Operation Pipeline + reg [1 : 0] Dqm_reg0, Dqm_reg1; // DQM Operation Pipeline + reg [ADDR_BITS - 1 : 0] B0_row_addr, B1_row_addr, B2_row_addr, B3_row_addr; + + reg [ADDR_BITS - 1 : 0] Mode_reg; + reg [DQ_BITS - 1 : 0] Dq_reg, Dq_dqm; + reg [COL_BITS - 1 : 0] Col_temp, Burst_counter; + + reg Act_b0, Act_b1, Act_b2, Act_b3; // Bank Activate + reg Pc_b0, Pc_b1, Pc_b2, Pc_b3; // Bank Precharge + + reg [1 : 0] Bank_precharge [0 : 3]; // Precharge Command + reg A10_precharge [0 : 3]; // Addr[10] = 1 (All banks) + reg Auto_precharge [0 : 3]; // RW Auto Precharge (Bank) + reg Read_precharge [0 : 3]; // R Auto Precharge + reg Write_precharge [0 : 3]; // W Auto Precharge + reg RW_interrupt_read [0 : 3]; // RW Interrupt Read with Auto Precharge + reg RW_interrupt_write [0 : 3]; // RW Interrupt Write with Auto Precharge + reg [1 : 0] RW_interrupt_bank; // RW Interrupt Bank + integer RW_interrupt_counter [0 : 3]; // RW Interrupt Counter + integer Count_precharge [0 : 3]; // RW Auto Precharge Counter + + reg Data_in_enable; + reg Data_out_enable; + + reg [1 : 0] Bank, Prev_bank; + reg [ADDR_BITS - 1 : 0] Row; + reg [COL_BITS - 1 : 0] Col, Col_brst; + + // Internal system clock + reg CkeZ, Sys_clk; + + // Commands Decode + wire Active_enable = ~Cs_n & ~Ras_n & Cas_n & We_n; + wire Aref_enable = ~Cs_n & ~Ras_n & ~Cas_n & We_n; + wire Burst_term = ~Cs_n & Ras_n & Cas_n & ~We_n; + wire Mode_reg_enable = ~Cs_n & ~Ras_n & ~Cas_n & ~We_n; + wire Prech_enable = ~Cs_n & ~Ras_n & Cas_n & ~We_n; + wire Read_enable = ~Cs_n & Ras_n & ~Cas_n & We_n; + wire Write_enable = ~Cs_n & Ras_n & ~Cas_n & ~We_n; + + // Burst Length Decode + wire Burst_length_1 = ~Mode_reg[2] & ~Mode_reg[1] & ~Mode_reg[0]; + wire Burst_length_2 = ~Mode_reg[2] & ~Mode_reg[1] & Mode_reg[0]; + wire Burst_length_4 = ~Mode_reg[2] & Mode_reg[1] & ~Mode_reg[0]; + wire Burst_length_8 = ~Mode_reg[2] & Mode_reg[1] & Mode_reg[0]; + wire Burst_length_f = Mode_reg[2] & Mode_reg[1] & Mode_reg[0]; + + // CAS Latency Decode + wire [2 : 0] Cas_latency = {Mode_reg[6], Mode_reg[5], Mode_reg[4]}; + + // Write Burst Mode + wire Write_burst_mode = Mode_reg[9]; + + wire Debug = 1'b0; // Debug messages : 1 = On + wire Dq_chk = Sys_clk & Data_in_enable; // Check setup/hold time for DQ + + assign Dq = Dq_reg; // DQ buffer + + // Commands Operation + `define ACT 0 + `define NOP 1 + `define READ 2 + `define WRITE 3 + `define PRECH 4 + `define A_REF 5 + `define BST 6 + `define LMR 7 + + // These timing dynamically adjust based on CAS Latency + time tAC, tHZ; + + // Timing Check variable + time MRD_chk; + time WR_chkm [0 : 3]; + time RFC_chk, RRD_chk; + time RC_chk0, RC_chk1, RC_chk2, RC_chk3; + time RAS_chk0, RAS_chk1, RAS_chk2, RAS_chk3; + time RCD_chk0, RCD_chk1, RCD_chk2, RCD_chk3; + time RP_chk0, RP_chk1, RP_chk2, RP_chk3; + + initial begin + Dq_reg = {DQ_BITS{1'bz}}; + Data_in_enable = 0; Data_out_enable = 0; + Act_b0 = 1; Act_b1 = 1; Act_b2 = 1; Act_b3 = 1; + Pc_b0 = 0; Pc_b1 = 0; Pc_b2 = 0; Pc_b3 = 0; + WR_chkm[0] = 0; WR_chkm[1] = 0; WR_chkm[2] = 0; WR_chkm[3] = 0; + RW_interrupt_read[0] = 0; RW_interrupt_read[1] = 0; RW_interrupt_read[2] = 0; RW_interrupt_read[3] = 0; + RW_interrupt_write[0] = 0; RW_interrupt_write[1] = 0; RW_interrupt_write[2] = 0; RW_interrupt_write[3] = 0; + MRD_chk = 0; RFC_chk = 0; RRD_chk = 0; + RAS_chk0 = 0; RAS_chk1 = 0; RAS_chk2 = 0; RAS_chk3 = 0; + RCD_chk0 = 0; RCD_chk1 = 0; RCD_chk2 = 0; RCD_chk3 = 0; + RC_chk0 = 0; RC_chk1 = 0; RC_chk2 = 0; RC_chk3 = 0; + RP_chk0 = 0; RP_chk1 = 0; RP_chk2 = 0; RP_chk3 = 0; + $timeformat (-9, 1, " ns", 12); + end + + // System clock generator + always begin + @ (posedge Clk) begin + Sys_clk = CkeZ; + CkeZ = Cke; + end + @ (negedge Clk) begin + Sys_clk = 1'b0; + end + end + + // Adjust tAC, tHZ based on CAS Latency + always @ (Cas_latency) begin + case (Cas_latency) + 1 : begin tAC = tAC1; tHZ = tHZ1; end + 2 : begin tAC = tAC2; tHZ = tHZ2; end + 3 : begin tAC = tAC3; tHZ = tHZ3; end + endcase + end + + always @ (posedge Sys_clk) begin + // Internal Commamd Pipelined + Command[0] = Command[1]; + Command[1] = Command[2]; + Command[2] = Command[3]; + Command[3] = `NOP; + + Col_addr[0] = Col_addr[1]; + Col_addr[1] = Col_addr[2]; + Col_addr[2] = Col_addr[3]; + Col_addr[3] = {COL_BITS{1'b0}}; + + Bank_addr[0] = Bank_addr[1]; + Bank_addr[1] = Bank_addr[2]; + Bank_addr[2] = Bank_addr[3]; + Bank_addr[3] = 2'b0; + + Bank_precharge[0] = Bank_precharge[1]; + Bank_precharge[1] = Bank_precharge[2]; + Bank_precharge[2] = Bank_precharge[3]; + Bank_precharge[3] = 2'b0; + + A10_precharge[0] = A10_precharge[1]; + A10_precharge[1] = A10_precharge[2]; + A10_precharge[2] = A10_precharge[3]; + A10_precharge[3] = 1'b0; + + // Dqm pipeline for Read + Dqm_reg0 = Dqm_reg1; + Dqm_reg1 = Dqm; + + // Read or Write with Auto Precharge Counter + if (Auto_precharge[0] === 1'b1) begin + Count_precharge[0] = Count_precharge[0] + 1; + end + if (Auto_precharge[1] === 1'b1) begin + Count_precharge[1] = Count_precharge[1] + 1; + end + if (Auto_precharge[2] === 1'b1) begin + Count_precharge[2] = Count_precharge[2] + 1; + end + if (Auto_precharge[3] === 1'b1) begin + Count_precharge[3] = Count_precharge[3] + 1; + end + + // Read or Write Interrupt Counter + if (RW_interrupt_write[0] === 1'b1) begin + RW_interrupt_counter[0] = RW_interrupt_counter[0] + 1; + end + if (RW_interrupt_write[1] === 1'b1) begin + RW_interrupt_counter[1] = RW_interrupt_counter[1] + 1; + end + if (RW_interrupt_write[2] === 1'b1) begin + RW_interrupt_counter[2] = RW_interrupt_counter[2] + 1; + end + if (RW_interrupt_write[3] === 1'b1) begin + RW_interrupt_counter[3] = RW_interrupt_counter[3] + 1; + end + + // tMRD Counter + MRD_chk = MRD_chk + 1; + + // Auto Refresh + if (Aref_enable === 1'b1) begin + if (Debug) begin + $display ("%m : at time %t AREF : Auto Refresh", $time); + end + + // Auto Refresh to Auto Refresh + if ($time - RFC_chk < tRFC) begin + $display ("%m : at time %t ERROR: tRFC violation during Auto Refresh", $time); + end + + // Precharge to Auto Refresh + if (($time - RP_chk0 < tRP) || ($time - RP_chk1 < tRP) || + ($time - RP_chk2 < tRP) || ($time - RP_chk3 < tRP)) begin + $display ("%m : at time %t ERROR: tRP violation during Auto Refresh", $time); + end + + // Precharge to Refresh + if (Pc_b0 === 1'b0 || Pc_b1 === 1'b0 || Pc_b2 === 1'b0 || Pc_b3 === 1'b0) begin + $display ("%m : at time %t ERROR: All banks must be Precharge before Auto Refresh", $time); + end + + // Load Mode Register to Auto Refresh + if (MRD_chk < tMRD) begin + $display ("%m : at time %t ERROR: tMRD violation during Auto Refresh", $time); + end + + // Record Current tRFC time + RFC_chk = $time; + end + + // Load Mode Register + if (Mode_reg_enable === 1'b1) begin + // Register Mode + Mode_reg = Addr; + + // Decode CAS Latency, Burst Length, Burst Type, and Write Burst Mode + if (Debug) begin + $display ("%m : at time %t LMR : Load Mode Register", $time); + // CAS Latency + case (Addr[6 : 4]) + 3'b010 : $display ("%m : CAS Latency = 2"); + 3'b011 : $display ("%m : CAS Latency = 3"); + default : $display ("%m : CAS Latency = Reserved"); + endcase + + // Burst Length + case (Addr[2 : 0]) + 3'b000 : $display ("%m : Burst Length = 1"); + 3'b001 : $display ("%m : Burst Length = 2"); + 3'b010 : $display ("%m : Burst Length = 4"); + 3'b011 : $display ("%m : Burst Length = 8"); + 3'b111 : $display ("%m : Burst Length = Full"); + default : $display ("%m : Burst Length = Reserved"); + endcase + + // Burst Type + if (Addr[3] === 1'b0) begin + $display ("%m : Burst Type = Sequential"); + end else if (Addr[3] === 1'b1) begin + $display ("%m : Burst Type = Interleaved"); + end else begin + $display ("%m : Burst Type = Reserved"); + end + + // Write Burst Mode + if (Addr[9] === 1'b0) begin + $display ("%m : Write Burst Mode = Programmed Burst Length"); + end else if (Addr[9] === 1'b1) begin + $display ("%m : Write Burst Mode = Single Location Access"); + end else begin + $display ("%m : Write Burst Mode = Reserved"); + end + end + + // Precharge to Load Mode Register + if (Pc_b0 === 1'b0 && Pc_b1 === 1'b0 && Pc_b2 === 1'b0 && Pc_b3 === 1'b0) begin + $display ("%m : at time %t ERROR: all banks must be Precharge before Load Mode Register", $time); + end + + // Precharge to Load Mode Register + if (($time - RP_chk0 < tRP) || ($time - RP_chk1 < tRP) || + ($time - RP_chk2 < tRP) || ($time - RP_chk3 < tRP)) begin + $display ("%m : at time %t ERROR: tRP violation during Load Mode Register", $time); + end + + // Auto Refresh to Load Mode Register + if ($time - RFC_chk < tRFC) begin + $display ("%m : at time %t ERROR: tRFC violation during Load Mode Register", $time); + end + + // Load Mode Register to Load Mode Register + if (MRD_chk < tMRD) begin + $display ("%m : at time %t ERROR: tMRD violation during Load Mode Register", $time); + end + + // Reset MRD Counter + MRD_chk = 0; + end + + // Active Block (Latch Bank Address and Row Address) + if (Active_enable === 1'b1) begin + // Activate an open bank can corrupt data + if ((Ba === 2'b00 && Act_b0 === 1'b1) || (Ba === 2'b01 && Act_b1 === 1'b1) || + (Ba === 2'b10 && Act_b2 === 1'b1) || (Ba === 2'b11 && Act_b3 === 1'b1)) begin + $display ("%m : at time %t ERROR: Bank already activated -- data can be corrupted", $time); + end + + // Activate Bank 0 + if (Ba === 2'b00 && Pc_b0 === 1'b1) begin + // Debug Message + if (Debug) begin + $display ("%m : at time %t ACT : Bank = 0 Row = %d", $time, Addr); + end + + // ACTIVE to ACTIVE command period + if ($time - RC_chk0 < tRC) begin + $display ("%m : at time %t ERROR: tRC violation during Activate bank 0", $time); + end + + // Precharge to Activate Bank 0 + if ($time - RP_chk0 < tRP) begin + $display ("%m : at time %t ERROR: tRP violation during Activate bank 0", $time); + end + + // Record variables + Act_b0 = 1'b1; + Pc_b0 = 1'b0; + B0_row_addr = Addr [ADDR_BITS - 1 : 0]; + RAS_chk0 = $time; + RC_chk0 = $time; + RCD_chk0 = $time; + end + + if (Ba == 2'b01 && Pc_b1 == 1'b1) begin + // Debug Message + if (Debug) begin + $display ("%m : at time %t ACT : Bank = 1 Row = %d", $time, Addr); + end + + // ACTIVE to ACTIVE command period + if ($time - RC_chk1 < tRC) begin + $display ("%m : at time %t ERROR: tRC violation during Activate bank 1", $time); + end + + // Precharge to Activate Bank 1 + if ($time - RP_chk1 < tRP) begin + $display ("%m : at time %t ERROR: tRP violation during Activate bank 1", $time); + end + + // Record variables + Act_b1 = 1'b1; + Pc_b1 = 1'b0; + B1_row_addr = Addr [ADDR_BITS - 1 : 0]; + RAS_chk1 = $time; + RC_chk1 = $time; + RCD_chk1 = $time; + end + + if (Ba == 2'b10 && Pc_b2 == 1'b1) begin + // Debug Message + if (Debug) begin + $display ("%m : at time %t ACT : Bank = 2 Row = %d", $time, Addr); + end + + // ACTIVE to ACTIVE command period + if ($time - RC_chk2 < tRC) begin + $display ("%m : at time %t ERROR: tRC violation during Activate bank 2", $time); + end + + // Precharge to Activate Bank 2 + if ($time - RP_chk2 < tRP) begin + $display ("%m : at time %t ERROR: tRP violation during Activate bank 2", $time); + end + + // Record variables + Act_b2 = 1'b1; + Pc_b2 = 1'b0; + B2_row_addr = Addr [ADDR_BITS - 1 : 0]; + RAS_chk2 = $time; + RC_chk2 = $time; + RCD_chk2 = $time; + end + + if (Ba == 2'b11 && Pc_b3 == 1'b1) begin + // Debug Message + if (Debug) begin + $display ("%m : at time %t ACT : Bank = 3 Row = %d", $time, Addr); + end + + // ACTIVE to ACTIVE command period + if ($time - RC_chk3 < tRC) begin + $display ("%m : at time %t ERROR: tRC violation during Activate bank 3", $time); + end + + // Precharge to Activate Bank 3 + if ($time - RP_chk3 < tRP) begin + $display ("%m : at time %t ERROR: tRP violation during Activate bank 3", $time); + end + + // Record variables + Act_b3 = 1'b1; + Pc_b3 = 1'b0; + B3_row_addr = Addr [ADDR_BITS - 1 : 0]; + RAS_chk3 = $time; + RC_chk3 = $time; + RCD_chk3 = $time; + end + + // Active Bank A to Active Bank B + if ((Prev_bank != Ba) && ($time - RRD_chk < tRRD)) begin + $display ("%m : at time %t ERROR: tRRD violation during Activate bank = %d", $time, Ba); + end + + // Auto Refresh to Activate + if ($time - RFC_chk < tRFC) begin + $display ("%m : at time %t ERROR: tRFC violation during Activate bank = %d", $time, Ba); + end + + // Load Mode Register to Active + if (MRD_chk < tMRD ) begin + $display ("%m : at time %t ERROR: tMRD violation during Activate bank = %d", $time, Ba); + end + + // Record variables for checking violation + RRD_chk = $time; + Prev_bank = Ba; + end + + // Precharge Block + if (Prech_enable == 1'b1) begin + // Load Mode Register to Precharge + if ($time - MRD_chk < tMRD) begin + $display ("%m : at time %t ERROR: tMRD violaiton during Precharge", $time); + end + + // Precharge Bank 0 + if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b00)) && Act_b0 === 1'b1) begin + Act_b0 = 1'b0; + Pc_b0 = 1'b1; + RP_chk0 = $time; + + // Debug Message + if (Debug) begin + $display ("%m : at time %t PRECHARGE : Bank = 0", $time); + end + + // Activate to Precharge + if ($time - RAS_chk0 < tRAS) begin + $display ("%m : at time %t ERROR: tRAS violation during Precharge", $time); + end + + // tWR violation check for write + if ($time - WR_chkm[0] < tWRm) begin + $display ("%m : at time %t ERROR: tWR violation during Precharge", $time); + end + end + + // Precharge Bank 1 + if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b01)) && Act_b1 === 1'b1) begin + Act_b1 = 1'b0; + Pc_b1 = 1'b1; + RP_chk1 = $time; + + // Debug Message + if (Debug) begin + $display ("%m : at time %t PRECHARGE : Bank = 1", $time); + end + + // Activate to Precharge + if ($time - RAS_chk1 < tRAS) begin + $display ("%m : at time %t ERROR: tRAS violation during Precharge", $time); + end + + // tWR violation check for write + if ($time - WR_chkm[1] < tWRm) begin + $display ("%m : at time %t ERROR: tWR violation during Precharge", $time); + end + end + + // Precharge Bank 2 + if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b10)) && Act_b2 === 1'b1) begin + Act_b2 = 1'b0; + Pc_b2 = 1'b1; + RP_chk2 = $time; + + // Debug Message + if (Debug) begin + $display ("%m : at time %t PRECHARGE : Bank = 2", $time); + end + + // Activate to Precharge + if ($time - RAS_chk2 < tRAS) begin + $display ("%m : at time %t ERROR: tRAS violation during Precharge", $time); + end + + // tWR violation check for write + if ($time - WR_chkm[2] < tWRm) begin + $display ("%m : at time %t ERROR: tWR violation during Precharge", $time); + end + end + + // Precharge Bank 3 + if ((Addr[10] === 1'b1 || (Addr[10] === 1'b0 && Ba === 2'b11)) && Act_b3 === 1'b1) begin + Act_b3 = 1'b0; + Pc_b3 = 1'b1; + RP_chk3 = $time; + + // Debug Message + if (Debug) begin + $display ("%m : at time %t PRECHARGE : Bank = 3", $time); + end + + // Activate to Precharge + if ($time - RAS_chk3 < tRAS) begin + $display ("%m : at time %t ERROR: tRAS violation during Precharge", $time); + end + + // tWR violation check for write + if ($time - WR_chkm[3] < tWRm) begin + $display ("%m : at time %t ERROR: tWR violation during Precharge", $time); + end + end + + // Precharge truncation with DQM set + if ((Data_in_enable == 1'b1) && ~(&Dqm)) begin + $display ("%m : at time %t ERROR: DQM not asserted during Precharge truncation", $time); + end + + // Terminate a Write Immediately (if same bank or all banks) + if (Data_in_enable === 1'b1 && (Bank === Ba || Addr[10] === 1'b1)) begin + Data_in_enable = 1'b0; + end + + // Precharge Command Pipeline for Read + Command[Cas_latency - 1] = `PRECH; + Bank_precharge[Cas_latency - 1] = Ba; + A10_precharge[Cas_latency - 1] = Addr[10]; + end + + // Burst terminate + if (Burst_term === 1'b1) begin + // Terminate a Write Immediately + if (Data_in_enable == 1'b1) begin + Data_in_enable = 1'b0; + end + + // Terminate a Read Depend on CAS Latency + Command[Cas_latency - 1] = `BST; + + // Display debug message + if (Debug) begin + $display ("%m : at time %t BST : Burst Terminate",$time); + end + end + + // Read, Write, Column Latch + if (Read_enable === 1'b1) begin + // Check to see if bank is open (ACT) + if ((Ba == 2'b00 && Pc_b0 == 1'b1) || (Ba == 2'b01 && Pc_b1 == 1'b1) || + (Ba == 2'b10 && Pc_b2 == 1'b1) || (Ba == 2'b11 && Pc_b3 == 1'b1)) begin + $display("%m : at time %t ERROR: Bank is not Activated for Read", $time); + end + + // Activate to Read or Write + if ((Ba == 2'b00) && ($time - RCD_chk0 < tRCD) || + (Ba == 2'b01) && ($time - RCD_chk1 < tRCD) || + (Ba == 2'b10) && ($time - RCD_chk2 < tRCD) || + (Ba == 2'b11) && ($time - RCD_chk3 < tRCD)) begin + $display("%m : at time %t ERROR: tRCD violation during Read", $time); + end + + // CAS Latency pipeline + Command[Cas_latency - 1] = `READ; + Col_addr[Cas_latency - 1] = Addr; + Bank_addr[Cas_latency - 1] = Ba; + + // Read interrupt Write (terminate Write immediately) + if (Data_in_enable == 1'b1) begin + Data_in_enable = 1'b0; + + // Interrupting a Write with Autoprecharge + if (Auto_precharge[RW_interrupt_bank] == 1'b1 && Write_precharge[RW_interrupt_bank] == 1'b1) begin + RW_interrupt_write[RW_interrupt_bank] = 1'b1; + RW_interrupt_counter[RW_interrupt_bank] = 0; + + // Display debug message + if (Debug) begin + $display ("%m : at time %t NOTE : Read interrupt Write with Autoprecharge", $time); + end + end + end + + // Read with Auto Precharge + if (Addr[10] == 1'b1) begin + Auto_precharge[Ba] = 1'b1; + Count_precharge[Ba] = 0; + RW_interrupt_bank = Ba; + Read_precharge[Ba] = 1'b1; + end + end + + // Write Command + if (Write_enable == 1'b1) begin + // Activate to Write + if ((Ba == 2'b00 && Pc_b0 == 1'b1) || (Ba == 2'b01 && Pc_b1 == 1'b1) || + (Ba == 2'b10 && Pc_b2 == 1'b1) || (Ba == 2'b11 && Pc_b3 == 1'b1)) begin + $display("%m : at time %t ERROR: Bank is not Activated for Write", $time); + end + + // Activate to Read or Write + if ((Ba == 2'b00) && ($time - RCD_chk0 < tRCD) || + (Ba == 2'b01) && ($time - RCD_chk1 < tRCD) || + (Ba == 2'b10) && ($time - RCD_chk2 < tRCD) || + (Ba == 2'b11) && ($time - RCD_chk3 < tRCD)) begin + $display("%m : at time %t ERROR: tRCD violation during Read", $time); + end + + // Latch Write command, Bank, and Column + Command[0] = `WRITE; + Col_addr[0] = Addr; + Bank_addr[0] = Ba; + + // Write interrupt Write (terminate Write immediately) + if (Data_in_enable == 1'b1) begin + Data_in_enable = 1'b0; + + // Interrupting a Write with Autoprecharge + if (Auto_precharge[RW_interrupt_bank] == 1'b1 && Write_precharge[RW_interrupt_bank] == 1'b1) begin + RW_interrupt_write[RW_interrupt_bank] = 1'b1; + + // Display debug message + if (Debug) begin + $display ("%m : at time %t NOTE : Read Bank %d interrupt Write Bank %d with Autoprecharge", $time, Ba, RW_interrupt_bank); + end + end + end + + // Write interrupt Read (terminate Read immediately) + if (Data_out_enable == 1'b1) begin + Data_out_enable = 1'b0; + + // Interrupting a Read with Autoprecharge + if (Auto_precharge[RW_interrupt_bank] == 1'b1 && Read_precharge[RW_interrupt_bank] == 1'b1) begin + RW_interrupt_read[RW_interrupt_bank] = 1'b1; + + // Display debug message + if (Debug) begin + $display ("%m : at time %t NOTE : Write Bank %d interrupt Read Bank %d with Autoprecharge", $time, Ba, RW_interrupt_bank); + end + end + end + + // Write with Auto Precharge + if (Addr[10] == 1'b1) begin + Auto_precharge[Ba] = 1'b1; + Count_precharge[Ba] = 0; + RW_interrupt_bank = Ba; + Write_precharge[Ba] = 1'b1; + end + end + + /* + Write with Auto Precharge Calculation + The device start internal precharge when: + 1. Meet minimum tRAS requirement + and 2. tWR cycle(s) after last valid data + or 3. Interrupt by a Read or Write (with or without Auto Precharge) + + Note: Model is starting the internal precharge 1 cycle after they meet all the + requirement but tRP will be compensate for the time after the 1 cycle. + */ + if ((Auto_precharge[0] == 1'b1) && (Write_precharge[0] == 1'b1)) begin + if ((($time - RAS_chk0 >= tRAS) && // Case 1 + (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [0] >= 1) || // Case 2 + (Burst_length_2 == 1'b1 && Count_precharge [0] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge [0] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge [0] >= 8))) || + (RW_interrupt_write[0] == 1'b1 && RW_interrupt_counter[0] >= 1)) begin // Case 3 + Auto_precharge[0] = 1'b0; + Write_precharge[0] = 1'b0; + RW_interrupt_write[0] = 1'b0; + Pc_b0 = 1'b1; + Act_b0 = 1'b0; + RP_chk0 = $time + tWRa; + if (Debug) begin + $display ("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 0", $time); + end + end + end + if ((Auto_precharge[1] == 1'b1) && (Write_precharge[1] == 1'b1)) begin + if ((($time - RAS_chk1 >= tRAS) && // Case 1 + (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [1] >= 1) || // Case 2 + (Burst_length_2 == 1'b1 && Count_precharge [1] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge [1] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge [1] >= 8))) || + (RW_interrupt_write[1] == 1'b1 && RW_interrupt_counter[1] >= 1)) begin // Case 3 + Auto_precharge[1] = 1'b0; + Write_precharge[1] = 1'b0; + RW_interrupt_write[1] = 1'b0; + Pc_b1 = 1'b1; + Act_b1 = 1'b0; + RP_chk1 = $time + tWRa; + if (Debug) begin + $display ("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 1", $time); + end + end + end + if ((Auto_precharge[2] == 1'b1) && (Write_precharge[2] == 1'b1)) begin + if ((($time - RAS_chk2 >= tRAS) && // Case 1 + (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [2] >= 1) || // Case 2 + (Burst_length_2 == 1'b1 && Count_precharge [2] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge [2] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge [2] >= 8))) || + (RW_interrupt_write[2] == 1'b1 && RW_interrupt_counter[2] >= 1)) begin // Case 3 + Auto_precharge[2] = 1'b0; + Write_precharge[2] = 1'b0; + RW_interrupt_write[2] = 1'b0; + Pc_b2 = 1'b1; + Act_b2 = 1'b0; + RP_chk2 = $time + tWRa; + if (Debug) begin + $display ("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 2", $time); + end + end + end + if ((Auto_precharge[3] == 1'b1) && (Write_precharge[3] == 1'b1)) begin + if ((($time - RAS_chk3 >= tRAS) && // Case 1 + (((Burst_length_1 == 1'b1 || Write_burst_mode == 1'b1) && Count_precharge [3] >= 1) || // Case 2 + (Burst_length_2 == 1'b1 && Count_precharge [3] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge [3] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge [3] >= 8))) || + (RW_interrupt_write[3] == 1'b1 && RW_interrupt_counter[3] >= 1)) begin // Case 3 + Auto_precharge[3] = 1'b0; + Write_precharge[3] = 1'b0; + RW_interrupt_write[3] = 1'b0; + Pc_b3 = 1'b1; + Act_b3 = 1'b0; + RP_chk3 = $time + tWRa; + if (Debug) begin + $display ("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 3", $time); + end + end + end + + // Read with Auto Precharge Calculation + // The device start internal precharge: + // 1. Meet minimum tRAS requirement + // and 2. CAS Latency - 1 cycles before last burst + // or 3. Interrupt by a Read or Write (with or without AutoPrecharge) + if ((Auto_precharge[0] == 1'b1) && (Read_precharge[0] == 1'b1)) begin + if ((($time - RAS_chk0 >= tRAS) && // Case 1 + ((Burst_length_1 == 1'b1 && Count_precharge[0] >= 1) || // Case 2 + (Burst_length_2 == 1'b1 && Count_precharge[0] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge[0] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge[0] >= 8))) || + (RW_interrupt_read[0] == 1'b1)) begin // Case 3 + Pc_b0 = 1'b1; + Act_b0 = 1'b0; + RP_chk0 = $time; + Auto_precharge[0] = 1'b0; + Read_precharge[0] = 1'b0; + RW_interrupt_read[0] = 1'b0; + if (Debug) begin + $display ("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 0", $time); + end + end + end + if ((Auto_precharge[1] == 1'b1) && (Read_precharge[1] == 1'b1)) begin + if ((($time - RAS_chk1 >= tRAS) && + ((Burst_length_1 == 1'b1 && Count_precharge[1] >= 1) || + (Burst_length_2 == 1'b1 && Count_precharge[1] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge[1] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge[1] >= 8))) || + (RW_interrupt_read[1] == 1'b1)) begin + Pc_b1 = 1'b1; + Act_b1 = 1'b0; + RP_chk1 = $time; + Auto_precharge[1] = 1'b0; + Read_precharge[1] = 1'b0; + RW_interrupt_read[1] = 1'b0; + if (Debug) begin + $display ("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 1", $time); + end + end + end + if ((Auto_precharge[2] == 1'b1) && (Read_precharge[2] == 1'b1)) begin + if ((($time - RAS_chk2 >= tRAS) && + ((Burst_length_1 == 1'b1 && Count_precharge[2] >= 1) || + (Burst_length_2 == 1'b1 && Count_precharge[2] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge[2] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge[2] >= 8))) || + (RW_interrupt_read[2] == 1'b1)) begin + Pc_b2 = 1'b1; + Act_b2 = 1'b0; + RP_chk2 = $time; + Auto_precharge[2] = 1'b0; + Read_precharge[2] = 1'b0; + RW_interrupt_read[2] = 1'b0; + if (Debug) begin + $display ("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 2", $time); + end + end + end + if ((Auto_precharge[3] == 1'b1) && (Read_precharge[3] == 1'b1)) begin + if ((($time - RAS_chk3 >= tRAS) && + ((Burst_length_1 == 1'b1 && Count_precharge[3] >= 1) || + (Burst_length_2 == 1'b1 && Count_precharge[3] >= 2) || + (Burst_length_4 == 1'b1 && Count_precharge[3] >= 4) || + (Burst_length_8 == 1'b1 && Count_precharge[3] >= 8))) || + (RW_interrupt_read[3] == 1'b1)) begin + Pc_b3 = 1'b1; + Act_b3 = 1'b0; + RP_chk3 = $time; + Auto_precharge[3] = 1'b0; + Read_precharge[3] = 1'b0; + RW_interrupt_read[3] = 1'b0; + if (Debug) begin + $display("%m : at time %t NOTE : Start Internal Auto Precharge for Bank 3", $time); + end + end + end + + // Internal Precharge or Bst + if (Command[0] == `PRECH) begin // Precharge terminate a read with same bank or all banks + if (Bank_precharge[0] == Bank || A10_precharge[0] == 1'b1) begin + if (Data_out_enable == 1'b1) begin + Data_out_enable = 1'b0; + end + end + end else if (Command[0] == `BST) begin // BST terminate a read to current bank + if (Data_out_enable == 1'b1) begin + Data_out_enable = 1'b0; + end + end + + if (Data_out_enable == 1'b0) begin + Dq_reg <= #tOH {DQ_BITS{1'bz}}; + end + + // Detect Read or Write command + if (Command[0] == `READ) begin + Bank = Bank_addr[0]; + Col = Col_addr[0]; + Col_brst = Col_addr[0]; + case (Bank_addr[0]) + 2'b00 : Row = B0_row_addr; + 2'b01 : Row = B1_row_addr; + 2'b10 : Row = B2_row_addr; + 2'b11 : Row = B3_row_addr; + endcase + Burst_counter = 0; + Data_in_enable = 1'b0; + Data_out_enable = 1'b1; + end else if (Command[0] == `WRITE) begin + Bank = Bank_addr[0]; + Col = Col_addr[0]; + Col_brst = Col_addr[0]; + case (Bank_addr[0]) + 2'b00 : Row = B0_row_addr; + 2'b01 : Row = B1_row_addr; + 2'b10 : Row = B2_row_addr; + 2'b11 : Row = B3_row_addr; + endcase + Burst_counter = 0; + Data_in_enable = 1'b1; + Data_out_enable = 1'b0; + end + + // DQ buffer (Driver/Receiver) + if (Data_in_enable == 1'b1) begin // Writing Data to Memory + // Array buffer + case (Bank) + 2'b00 : Dq_dqm = Bank0 [{Row, Col}]; + 2'b01 : Dq_dqm = Bank1 [{Row, Col}]; + 2'b10 : Dq_dqm = Bank2 [{Row, Col}]; + 2'b11 : Dq_dqm = Bank3 [{Row, Col}]; + endcase + + // Dqm operation +`ifdef x4 + if (Dqm[0] == 1'b0) begin + Dq_dqm [ 3 : 0] = Dq [ 3 : 0]; + end +`elsif x8 + if (Dqm[0] == 1'b0) begin + Dq_dqm [ 7 : 0] = Dq [ 7 : 0]; + end +`elsif x16 + if (Dqm[0] == 1'b0) begin + Dq_dqm [ 7 : 0] = Dq [ 7 : 0]; + end + if (Dqm[1] == 1'b0) begin + Dq_dqm [15 : 8] = Dq [15 : 8]; + end +`endif + + // Write to memory + case (Bank) + 2'b00 : Bank0 [{Row, Col}] = Dq_dqm; + 2'b01 : Bank1 [{Row, Col}] = Dq_dqm; + 2'b10 : Bank2 [{Row, Col}] = Dq_dqm; + 2'b11 : Bank3 [{Row, Col}] = Dq_dqm; + endcase + + // Display debug message + if (Dqm !== 2'b11) begin + // Record tWR for manual precharge + WR_chkm [Bank] = $time; + + if (Debug) begin + $display("%m : at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = %h", $time, Bank, Row, Col, Dq_dqm); + end + end else begin + if (Debug) begin + $display("%m : at time %t WRITE: Bank = %d Row = %d, Col = %d, Data = Hi-Z due to DQM", $time, Bank, Row, Col); + end + end + + // Advance burst counter subroutine + #tHZ Burst_decode; + + end else if (Data_out_enable == 1'b1) begin // Reading Data from Memory + // Array buffer + case (Bank) + 2'b00 : Dq_dqm = Bank0[{Row, Col}]; + 2'b01 : Dq_dqm = Bank1[{Row, Col}]; + 2'b10 : Dq_dqm = Bank2[{Row, Col}]; + 2'b11 : Dq_dqm = Bank3[{Row, Col}]; + endcase + + // Dqm operation +`ifdef x4 + if (Dqm_reg0 [0] == 1'b1) begin + Dq_dqm [ 3 : 0] = 4'bz; + end +`elsif x8 + if (Dqm_reg0 [0] == 1'b1) begin + Dq_dqm [ 7 : 0] = 8'bz; + end +`elsif x16 + if (Dqm_reg0 [0] == 1'b1) begin + Dq_dqm [ 7 : 0] = 8'bz; + end + if (Dqm_reg0 [1] == 1'b1) begin + Dq_dqm [15 : 8] = 8'bz; + end +`endif + + // Display debug message + Dq_reg = #tAC Dq_dqm; + if (Debug) begin + $display("%m : at time %t READ : Bank = %d Row = %d, Col = %d, Dqm = %b, Data = %h", $time, Bank, Row, Col, Dqm_reg0, Dq_reg); + end + + // Advance burst counter subroutine + Burst_decode; + end + end + + // Burst counter decode + task Burst_decode; + begin + // Advance Burst Counter + Burst_counter = Burst_counter + 1; + + // Burst Type + if (Mode_reg[3] == 1'b0) begin // Sequential Burst + Col_temp = Col + 1; + end else if (Mode_reg[3] == 1'b1) begin // Interleaved Burst + Col_temp[2] = Burst_counter[2] ^ Col_brst[2]; + Col_temp[1] = Burst_counter[1] ^ Col_brst[1]; + Col_temp[0] = Burst_counter[0] ^ Col_brst[0]; + end + + // Burst Length + if (Burst_length_2) begin // Burst Length = 2 + Col [0] = Col_temp [0]; + end else if (Burst_length_4) begin // Burst Length = 4 + Col [1 : 0] = Col_temp [1 : 0]; + end else if (Burst_length_8) begin // Burst Length = 8 + Col [2 : 0] = Col_temp [2 : 0]; + end else begin // Burst Length = FULL + Col = Col_temp; + end + + // Burst Read Single Write + if (Write_burst_mode == 1'b1) begin + Data_in_enable = 1'b0; + end + + // Data Counter + if (Burst_length_1 == 1'b1) begin + if (Burst_counter >= 1) begin + Data_in_enable = 1'b0; + Data_out_enable = 1'b0; + end + end else if (Burst_length_2 == 1'b1) begin + if (Burst_counter >= 2) begin + Data_in_enable = 1'b0; + Data_out_enable = 1'b0; + end + end else if (Burst_length_4 == 1'b1) begin + if (Burst_counter >= 4) begin + Data_in_enable = 1'b0; + Data_out_enable = 1'b0; + end + end else if (Burst_length_8 == 1'b1) begin + if (Burst_counter >= 8) begin + Data_in_enable = 1'b0; + Data_out_enable = 1'b0; + end + end + end + endtask + + // Timing Parameters for -75 (133 MHz @ CL3) + specify + specparam + tAH = 0.8, // Addr, Ba Hold Time + tAS = 1.5, // Addr, Ba Setup Time + `ifdef CLK_166 + tCK3 = 6, + `elsif CLK_133 + tCK3 = 7.5, + `elsif CLK_100 + tCK3 = 10, + `elsif CLK_200 + tCK3 = 5, + `endif + tCH = 2.5, // Clock High-Level Width + tCL = 2.5, // Clock Low-Level Width + tCKH = 0.8, // CKE Hold Time + tCKS = 1.5, // CKE Setup Time + tCMH = 0.8, // CS#, RAS#, CAS#, WE#, DQM# Hold Time + tCMS = 1.5, // CS#, RAS#, CAS#, WE#, DQM# Setup Time + tDH = 0.8, // Data-in Hold Time + tDS = 1.5; // Data-in Setup Time + $width (posedge Clk, tCH); + $width (negedge Clk, tCL); + $period (negedge Clk, tCK3); + $period (posedge Clk, tCK3); + $setuphold(posedge Clk, Cke, tCKS, tCKH); + $setuphold(posedge Clk, Cs_n, tCMS, tCMH); + $setuphold(posedge Clk, Cas_n, tCMS, tCMH); + $setuphold(posedge Clk, Ras_n, tCMS, tCMH); + $setuphold(posedge Clk, We_n, tCMS, tCMH); + $setuphold(posedge Clk, Addr, tAS, tAH); + $setuphold(posedge Clk, Ba, tAS, tAH); + $setuphold(posedge Clk, Dqm, tCMS, tCMH); + $setuphold(posedge Dq_chk, Dq, tDS, tDH); + endspecify + +endmodule diff --git a/hw/efinix_fpga/simulation/src/sim_top.sv b/hw/efinix_fpga/simulation/src/sim_top.sv new file mode 100644 index 0000000..0b9945e --- /dev/null +++ b/hw/efinix_fpga/simulation/src/sim_top.sv @@ -0,0 +1,154 @@ +`timescale 1ns/1ps + +module sim_top(); + +`include "include/super6502_sdram_controller_define.vh" + +logic r_sysclk, r_sdrclk, r_clk_50, r_clk_2; + +// clk_100 +initial begin + r_sysclk <= '1; + forever begin + #5 r_sysclk <= ~r_sysclk; + end +end + +// clk_200 +initial begin + r_sdrclk <= '1; + forever begin + #2.5 r_sdrclk <= ~r_sdrclk; + end +end + +// clk_50 +initial begin + r_clk_50 <= '1; + forever begin + #10 r_clk_50 <= ~r_clk_50; + end +end + +// clk_2 +initial begin + r_clk_2 <= '1; + forever begin + #250 r_clk_2 <= ~r_clk_2; + end +end + +initial begin + $dumpfile("sim_top.vcd"); + $dumpvars(0,sim_top); +end + +logic button_reset; + +initial begin + button_reset <= '0; + repeat(10) @(r_clk_2); + button_reset <= '1; + repeat(20000) @(r_clk_2); + $finish(); +end + +logic w_cpu_reset; +logic [15:0] w_cpu_addr; +logic [7:0] w_cpu_data_from_cpu, w_cpu_data_from_dut; +logic w_cpu_rdy; +logic w_cpu_we; +logic w_cpu_phi2; + +//TODO: this +cpu_65c02 u_cpu( + .phi2(w_cpu_phi2), + .reset(~w_cpu_reset), + .AB(w_cpu_addr), + .RDY(w_cpu_rdy), + .IRQ('0), + .NMI('0), + .DI_s1(w_cpu_data_from_dut), + .DO(w_cpu_data_from_cpu), + .WE(w_cpu_we) +); + + +// Having the super6502 causes an infinite loop, +// but just the rom works. Need to whittle down +// which block is causing it. +// rom #(.DATA_WIDTH(8), .ADDR_WIDTH(12)) u_rom( +// .addr(w_cpu_addr[11:0]), +// .clk(r_clk_2), +// .data(w_cpu_data_from_dut) +// ); + +//TODO: also this +super6502 u_dut( + .i_sysclk(r_sysclk), + .i_sdrclk(r_sdrclk), + .i_tACclk(~r_sdrclk), + .clk_50(r_clk_50), + .clk_2(r_clk_2), + .button_reset(button_reset), + .cpu_resb(w_cpu_reset), + .cpu_addr(w_cpu_addr), + .cpu_data_out(w_cpu_data_from_dut), + .cpu_data_in(w_cpu_data_from_cpu), + .cpu_rwb(~w_cpu_we), + .cpu_rdy(w_cpu_rdy), + .cpu_phi2(w_cpu_phi2), + + .o_sdr_CKE(w_sdr_CKE), + .o_sdr_n_CS(w_sdr_n_CS), + .o_sdr_n_WE(w_sdr_n_WE), + .o_sdr_n_RAS(w_sdr_n_RAS), + .o_sdr_n_CAS(w_sdr_n_CAS), + .o_sdr_BA(w_sdr_BA), + .o_sdr_ADDR(w_sdr_ADDR), + .i_sdr_DATA(w_sdr_DQ), + .o_sdr_DATA(w_sdr_DATA), + .o_sdr_DATA_oe(w_sdr_DATA_oe), + .o_sdr_DQM(w_sdr_DQM) +); + +wire w_sdr_CKE; +wire w_sdr_n_CS; +wire w_sdr_n_WE; +wire w_sdr_n_RAS; +wire w_sdr_n_CAS; +wire [BA_WIDTH -1:0]w_sdr_BA; +wire [ROW_WIDTH -1:0]w_sdr_ADDR; +wire [DQ_GROUP *DQ_WIDTH -1:0]w_sdr_DATA; +wire [DQ_GROUP *DQ_WIDTH -1:0]w_sdr_DATA_oe; +wire [DQ_GROUP -1:0]w_sdr_DQM; +wire [DQ_GROUP *DQ_WIDTH -1:0]w_sdr_DQ; + +genvar i, j; +generate + for (i=0; i= 16'hf000 && i_addr <= 16'hffff; assign o_timer_cs = i_addr >= 16'heff8 && i_addr <= 16'heffb; assign o_multiplier_cs = i_addr >= 16'heff0 && i_addr <= 16'heff7; diff --git a/hw/efinix_fpga/src/sdram_adapter.sv b/hw/efinix_fpga/src/sdram_adapter.sv index c9c1603..9b0b7c0 100644 --- a/hw/efinix_fpga/src/sdram_adapter.sv +++ b/hw/efinix_fpga/src/sdram_adapter.sv @@ -104,7 +104,7 @@ end logic r_wait; logic _r_wait; -assign o_wait = r_wait; +assign o_wait = r_wait & i_cs; // we need to assert rdy low until a falling edge if a reset happens @@ -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 diff --git a/hw/efinix_fpga/src/spi_controller.sv b/hw/efinix_fpga/src/spi_controller.sv index 2d085e4..9f5c09d 100644 --- a/hw/efinix_fpga/src/spi_controller.sv +++ b/hw/efinix_fpga/src/spi_controller.sv @@ -90,6 +90,7 @@ always_comb begin 1: o_data = r_input_data; 2:; 3: o_data = {active, r_control[6:0]}; + default: o_data = 'x; endcase end diff --git a/hw/efinix_fpga/src/super6502.sv b/hw/efinix_fpga/src/super6502.sv index abe90d8..b0b1a49 100644 --- a/hw/efinix_fpga/src/super6502.sv +++ b/hw/efinix_fpga/src/super6502.sv @@ -81,17 +81,6 @@ logic w_divider_cs; logic w_uart_cs; logic w_spi_cs; -addr_decode u_addr_decode( - .i_addr(cpu_addr), - .o_rom_cs(w_rom_cs), - .o_leds_cs(w_leds_cs), - .o_timer_cs(w_timer_cs), - .o_multiplier_cs(w_multiplier_cs), - .o_divider_cs(w_divider_cs), - .o_uart_cs(w_uart_cs), - .o_spi_cs(w_spi_cs), - .o_sdram_cs(w_sdram_cs) -); logic [7:0] w_rom_data_out; logic [7:0] w_leds_data_out; @@ -103,6 +92,16 @@ logic [7:0] w_spi_data_out; logic [7:0] w_sdram_data_out; always_comb begin + w_rom_cs = cpu_addr >= 16'hf000 && cpu_addr <= 16'hffff; + w_timer_cs = cpu_addr >= 16'heff8 && cpu_addr <= 16'heffb; + w_multiplier_cs = cpu_addr >= 16'heff0 && cpu_addr <= 16'heff7; + w_divider_cs = cpu_addr >= 16'hefe8 && cpu_addr <= 16'hefef; + w_uart_cs = cpu_addr >= 16'hefe6 && cpu_addr <= 16'hefe7; + w_spi_cs = cpu_addr >= 16'hefd8 && cpu_addr <= 16'hefdb; + w_leds_cs = cpu_addr == 16'hefff; + w_sdram_cs = cpu_addr < 16'he000; + + if (w_rom_cs) cpu_data_out = w_rom_data_out; else if (w_leds_cs) diff --git a/hw/efinix_fpga/src/timer.sv b/hw/efinix_fpga/src/timer.sv index fa7f743..abebef9 100644 --- a/hw/efinix_fpga/src/timer.sv +++ b/hw/efinix_fpga/src/timer.sv @@ -123,6 +123,8 @@ always_comb begin o_data = status; end + default: o_data = 'x; + endcase end diff --git a/hw/efinix_fpga/src/uart_wrapper.sv b/hw/efinix_fpga/src/uart_wrapper.sv index 04d35e3..44bd6e1 100644 --- a/hw/efinix_fpga/src/uart_wrapper.sv +++ b/hw/efinix_fpga/src/uart_wrapper.sv @@ -46,8 +46,9 @@ enum bit [1:0] {READY, WAIT, TRANSMIT} state, next_state; always_ff @(posedge clk_50) begin if (reset) begin - state = READY; + state <= READY; irqb <= '1; + status <= '0; end else begin state <= next_state; end diff --git a/hw/efinix_fpga/init_env.sh b/init_env.sh similarity index 93% rename from hw/efinix_fpga/init_env.sh rename to init_env.sh index 22ec0d4..46419d9 100644 --- a/hw/efinix_fpga/init_env.sh +++ b/init_env.sh @@ -20,6 +20,8 @@ # export PATH=$PATH:"$EFXPT_HOME/bin" source $EFX_SETUP +export REPO_TOP=$(git rev-parse --show-toplevel) + # python -m venv .user_venv --system-site-packages # . .user_venv/bin/activate diff --git a/sw/bios/Makefile b/sw/bios/Makefile index 3a9399a..3d489a2 100644 --- a/sw/bios/Makefile +++ b/sw/bios/Makefile @@ -7,7 +7,7 @@ NAME=bios BIN=$(NAME).bin HEX=$(NAME).hex -FPGA_IMG=../../hw/efinix_fpga/init_hex.mem +FPGA_IMG=$(REPO_TOP)/hw/efinix_fpga/init_hex.mem EFX_RUN=/home/byron/Software/efinity/2023.1/scripts/efx_run.py EFX_PRJ=/home/byron/Projects/super6502/hw/efinix_fpga/super6502.xml diff --git a/sw/test_code/loop_test/Makefile b/sw/test_code/loop_test/Makefile new file mode 100644 index 0000000..d854069 --- /dev/null +++ b/sw/test_code/loop_test/Makefile @@ -0,0 +1,39 @@ +CC=../../cc65/bin/cl65 +LD=../../cc65/bin/cl65 +CFLAGS=-T -t none -I. --cpu "65C02" +LDFLAGS=-C link.ld -m $(NAME).map + +NAME=loop_test + +BIN=$(NAME).bin +HEX=$(NAME).hex + +LISTS=lists + +SRCS=$(wildcard *.s) $(wildcard *.c) +SRCS+=$(wildcard **/*.s) $(wildcard **/*.c) +OBJS+=$(patsubst %.s,%.o,$(filter %s,$(SRCS))) +OBJS+=$(patsubst %.c,%.o,$(filter %c,$(SRCS))) + +# Make sure the kernel linked to correct address, no relocation! +all: $(HEX) + +$(HEX): $(BIN) + objcopy --input-target=binary --output-target=verilog $(BIN) $(HEX) + +$(BIN): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@ + +%.o: %.c $(LISTS) + $(CC) $(CFLAGS) -l $(LISTS)/$<.list -c $< -o $@ + +%.o: %.s $(LISTS) + $(CC) $(CFLAGS) -l $(LISTS)/$<.list -c $< -o $@ + +$(LISTS): + mkdir -p $(addprefix $(LISTS)/,$(sort $(dir $(SRCS)))) + +.PHONY: clean +clean: + rm -rf $(OBJS) $(BIN) $(HEX) $(LISTS) $(NAME).map + diff --git a/sw/test_code/loop_test/link.ld b/sw/test_code/loop_test/link.ld new file mode 100644 index 0000000..66a42fe --- /dev/null +++ b/sw/test_code/loop_test/link.ld @@ -0,0 +1,35 @@ +MEMORY +{ + ZP: start = $0, size = $100, type = rw, define = yes; + SDRAM: start = $9200, size = $4d00, type = rw, define = yes; + ROM: start = $F000, size = $1000, file = %O; +} + +SEGMENTS { + ZEROPAGE: load = ZP, type = zp, define = yes; + DATA: load = ROM, type = rw, define = yes, run = SDRAM; + BSS: load = SDRAM, type = bss, define = yes; + HEAP: load = SDRAM, type = bss, optional = yes; + STARTUP: load = ROM, type = ro; + ONCE: load = ROM, type = ro, optional = yes; + CODE: load = ROM, type = ro; + RODATA: load = ROM, type = ro; + VECTORS: load = ROM, type = ro, start = $FFFA; +} + +FEATURES { + CONDES: segment = STARTUP, + type = constructor, + label = __CONSTRUCTOR_TABLE__, + count = __CONSTRUCTOR_COUNT__; + CONDES: segment = STARTUP, + type = destructor, + label = __DESTRUCTOR_TABLE__, + count = __DESTRUCTOR_COUNT__; +} + +SYMBOLS { + # Define the stack size for the application + __STACKSIZE__: value = $0200, type = weak; + __STACKSTART__: type = weak, value = $0800; # 2k stack +} diff --git a/sw/test_code/loop_test/main.s b/sw/test_code/loop_test/main.s new file mode 100644 index 0000000..4cd88ca --- /dev/null +++ b/sw/test_code/loop_test/main.s @@ -0,0 +1,16 @@ +.export _init, _nmi_int, _irq_int + +.code + +_nmi_int: +_irq_int: + +_init: + lda #$00 +@1: inc + sta $01 + lda $01 + cmp $01 + beq @1 + +@end: bra @end \ No newline at end of file diff --git a/sw/test_code/loop_test/vectors.s b/sw/test_code/loop_test/vectors.s new file mode 100644 index 0000000..81ae6e0 --- /dev/null +++ b/sw/test_code/loop_test/vectors.s @@ -0,0 +1,14 @@ +; --------------------------------------------------------------------------- +; vectors.s +; --------------------------------------------------------------------------- +; +; Defines the interrupt vector table. + +.import _init +.import _nmi_int, _irq_int + +.segment "VECTORS" + +.addr _nmi_int ; NMI vector +.addr _init ; Reset vector +.addr _irq_int ; IRQ/BRK vector \ No newline at end of file diff --git a/sw/test_code/simple_mem_test/Makefile b/sw/test_code/simple_mem_test/Makefile new file mode 100644 index 0000000..34a0ce9 --- /dev/null +++ b/sw/test_code/simple_mem_test/Makefile @@ -0,0 +1,39 @@ +CC=../../cc65/bin/cl65 +LD=../../cc65/bin/cl65 +CFLAGS=-T -t none -I. --cpu "65C02" +LDFLAGS=-C link.ld -m $(NAME).map + +NAME=simple_mem_test + +BIN=$(NAME).bin +HEX=$(NAME).hex + +LISTS=lists + +SRCS=$(wildcard *.s) $(wildcard *.c) +SRCS+=$(wildcard **/*.s) $(wildcard **/*.c) +OBJS+=$(patsubst %.s,%.o,$(filter %s,$(SRCS))) +OBJS+=$(patsubst %.c,%.o,$(filter %c,$(SRCS))) + +# Make sure the kernel linked to correct address, no relocation! +all: $(HEX) + +$(HEX): $(BIN) + objcopy --input-target=binary --output-target=verilog $(BIN) $(HEX) + +$(BIN): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@ + +%.o: %.c $(LISTS) + $(CC) $(CFLAGS) -l $(LISTS)/$<.list -c $< -o $@ + +%.o: %.s $(LISTS) + $(CC) $(CFLAGS) -l $(LISTS)/$<.list -c $< -o $@ + +$(LISTS): + mkdir -p $(addprefix $(LISTS)/,$(sort $(dir $(SRCS)))) + +.PHONY: clean +clean: + rm -rf $(OBJS) $(BIN) $(HEX) $(LISTS) $(NAME).map + diff --git a/sw/test_code/simple_mem_test/link.ld b/sw/test_code/simple_mem_test/link.ld new file mode 100644 index 0000000..66a42fe --- /dev/null +++ b/sw/test_code/simple_mem_test/link.ld @@ -0,0 +1,35 @@ +MEMORY +{ + ZP: start = $0, size = $100, type = rw, define = yes; + SDRAM: start = $9200, size = $4d00, type = rw, define = yes; + ROM: start = $F000, size = $1000, file = %O; +} + +SEGMENTS { + ZEROPAGE: load = ZP, type = zp, define = yes; + DATA: load = ROM, type = rw, define = yes, run = SDRAM; + BSS: load = SDRAM, type = bss, define = yes; + HEAP: load = SDRAM, type = bss, optional = yes; + STARTUP: load = ROM, type = ro; + ONCE: load = ROM, type = ro, optional = yes; + CODE: load = ROM, type = ro; + RODATA: load = ROM, type = ro; + VECTORS: load = ROM, type = ro, start = $FFFA; +} + +FEATURES { + CONDES: segment = STARTUP, + type = constructor, + label = __CONSTRUCTOR_TABLE__, + count = __CONSTRUCTOR_COUNT__; + CONDES: segment = STARTUP, + type = destructor, + label = __DESTRUCTOR_TABLE__, + count = __DESTRUCTOR_COUNT__; +} + +SYMBOLS { + # Define the stack size for the application + __STACKSIZE__: value = $0200, type = weak; + __STACKSTART__: type = weak, value = $0800; # 2k stack +} diff --git a/sw/test_code/simple_mem_test/main.s b/sw/test_code/simple_mem_test/main.s new file mode 100644 index 0000000..d7ce83d --- /dev/null +++ b/sw/test_code/simple_mem_test/main.s @@ -0,0 +1,24 @@ +.export _init, _nmi_int, _irq_int + +.code + +_nmi_int: +_irq_int: + +_init: + lda #$aa + sta $10 + lda #$55 + sta $11 + + lda #$ff + sta $12 + lda #$00 + sta $13 + + lda $10 + lda $11 + lda $12 + lda $13 + +@1: bra @1 \ No newline at end of file diff --git a/sw/test_code/simple_mem_test/vectors.s b/sw/test_code/simple_mem_test/vectors.s new file mode 100644 index 0000000..81ae6e0 --- /dev/null +++ b/sw/test_code/simple_mem_test/vectors.s @@ -0,0 +1,14 @@ +; --------------------------------------------------------------------------- +; vectors.s +; --------------------------------------------------------------------------- +; +; Defines the interrupt vector table. + +.import _init +.import _nmi_int, _irq_int + +.segment "VECTORS" + +.addr _nmi_int ; NMI vector +.addr _init ; Reset vector +.addr _irq_int ; IRQ/BRK vector \ No newline at end of file