Files
NES_MiSTer/NES.sv
2019-03-21 21:05:27 +08:00

752 lines
20 KiB
Systemverilog

// Copyright (c) 2012-2013 Ludvig Strigeus
// This program is GPL Licensed. See COPYING for the full license.
//
// MiSTer port: Copyright (C) 2017,2018 Sorgelig
module emu
(
//Master input clock
input CLK_50M,
//Async reset from top-level module.
//Can be used as initial reset.
input RESET,
//Must be passed to hps_io module
inout [44:0] HPS_BUS,
//Base video clock. Usually equals to CLK_SYS.
output CLK_VIDEO,
//Multiple resolutions are supported using different CE_PIXEL rates.
//Must be based on CLK_VIDEO
output CE_PIXEL,
//Video aspect ratio for HDMI. Most retro systems have ratio 4:3.
output [7:0] VIDEO_ARX,
output [7:0] VIDEO_ARY,
output [7:0] VGA_R,
output [7:0] VGA_G,
output [7:0] VGA_B,
output VGA_HS,
output VGA_VS,
output VGA_DE, // = ~(VBlank | HBlank)
output VGA_F1,
output [1:0] VGA_SL,
output LED_USER, // 1 - ON, 0 - OFF.
// b[1]: 0 - LED status is system status OR'd with b[0]
// 1 - LED status is controled solely by b[0]
// hint: supply 2'b00 to let the system control the LED.
output [1:0] LED_POWER,
output [1:0] LED_DISK,
output [15:0] AUDIO_L,
output [15:0] AUDIO_R,
output AUDIO_S, // 1 - signed audio samples, 0 - unsigned
output [1:0] AUDIO_MIX, // 0 - no mix, 1 - 25%, 2 - 50%, 3 - 100% (mono)
input TAPE_IN,
// SD-SPI
output SD_SCK,
output SD_MOSI,
input SD_MISO,
output SD_CS,
input SD_CD,
//High latency DDR3 RAM interface
//Use for non-critical time purposes
output DDRAM_CLK,
input DDRAM_BUSY,
output [7:0] DDRAM_BURSTCNT,
output [28:0] DDRAM_ADDR,
input [63:0] DDRAM_DOUT,
input DDRAM_DOUT_READY,
output DDRAM_RD,
output [63:0] DDRAM_DIN,
output [7:0] DDRAM_BE,
output DDRAM_WE,
//SDRAM interface with lower latency
output SDRAM_CLK,
output SDRAM_CKE,
output [12:0] SDRAM_A,
output [1:0] SDRAM_BA,
inout [15:0] SDRAM_DQ,
output SDRAM_DQML,
output SDRAM_DQMH,
output SDRAM_nCS,
output SDRAM_nCAS,
output SDRAM_nRAS,
output SDRAM_nWE,
input UART_CTS,
output UART_RTS,
input UART_RXD,
output UART_TXD,
output UART_DTR,
input UART_DSR,
// Open-drain User port.
// 0 - D+/RX
// 1 - D-/TX
// 2..5 - USR1..USR4
// Set USER_OUT to 1 to read from USER_IN.
input [5:0] USER_IN,
output [5:0] USER_OUT,
input OSD_STATUS
);
assign USER_OUT = '1;
assign AUDIO_S = 0;
assign AUDIO_L = sample;
assign AUDIO_R = sample;
assign AUDIO_MIX = 0;
assign LED_USER = downloading | (loader_fail & led_blink) | bk_state;
assign LED_DISK = 0;
assign LED_POWER = 0;
assign VIDEO_ARX = status[8] ? 8'd16 : 8'd4;
assign VIDEO_ARY = status[8] ? 8'd9 : 8'd3;
assign CLK_VIDEO = clk85;
assign VGA_F1 = 0;
assign {UART_RTS, UART_TXD, UART_DTR} = 0;
assign {DDRAM_CLK, DDRAM_BURSTCNT, DDRAM_ADDR, DDRAM_DIN, DDRAM_BE, DDRAM_RD, DDRAM_WE} = 0;
assign {SD_SCK, SD_MOSI, SD_CS} = 'Z;
`define DEBUG_AUDIO
`include "build_id.v"
parameter CONF_STR1 = {
"NES;;",
"-;",
"FS,NES;",
"F,FDS;",
"-;",
"OG,Disk Swap,Auto,FDS button;",
"O5,Invert mirroring,OFF,ON;",
"-;",
};
parameter CONF_STR2 = {
"6,Load Backup RAM;"
};
parameter CONF_STR3 = {
"7,Save Backup RAM;",
"-;",
"O8,Aspect ratio,4:3,16:9;",
"O13,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%,CRT 75%;",
"O4,Hide overscan,OFF,ON;",
"OCF,Palette,Smooth,Unsat.,FCEUX,NES Classic,Composite,PC-10,PVM,Wavebeam,Real,Sony CXA,YUV,Greyscale,Rockman9,Nintendulator;",
"-;",
"O9,Swap joysticks,NO,YES;",
"OA,Multitap,Disabled,Enabled;",
`ifdef DEBUG_AUDIO
"-;",
"OUV,Audio Enable,Both,Internal,Cart Expansion,None;",
`endif
"-;",
"R0,Reset;",
"J1,A,B,Select,Start,FDS,PP 1,PP 2,PP 3,PP 4,PP 5,PP 6,PP 7,PP 8,PP 9,PP 10,PP 11,PP 12;",
"V,v",`BUILD_DATE
};
wire [20:0] joyA,joyB,joyC,joyD;
wire [1:0] buttons;
wire [31:0] status;
wire arm_reset = status[0];
wire mirroring_osd = status[5];
wire hide_overscan = status[4];
wire [3:0] palette2_osd = status[15:12];
wire joy_swap = status[9];
wire fds_swap_invert = status[16];
`ifdef DEBUG_AUDIO
wire ext_audio = ~status[30];
wire int_audio = ~status[31];
`else
wire ext_audio = 1;
wire int_audio = 1;
`endif
wire forced_scandoubler;
wire ps2_kbd_clk, ps2_kbd_data;
reg [31:0] sd_lba;
reg sd_rd = 0;
reg sd_wr = 0;
wire sd_ack;
wire [8:0] sd_buff_addr;
wire [7:0] sd_buff_dout;
wire [7:0] sd_buff_din;
wire sd_buff_wr;
wire img_mounted;
wire img_readonly;
wire [63:0] img_size;
wire [7:0] filetype;
wire [24:0] ioctl_addr;
hps_io #(.STRLEN(($size(CONF_STR1)>>3) + ($size(CONF_STR2)>>3) + ($size(CONF_STR3)>>3) + 2)) hps_io
(
.clk_sys(clk),
.HPS_BUS(HPS_BUS),
.conf_str({CONF_STR1,bk_ena ? "R" : "+",CONF_STR2,bk_ena ? "R" : "+",CONF_STR3}),
.buttons(buttons),
.forced_scandoubler(forced_scandoubler),
.joystick_0(joyA),
.joystick_1(joyB),
.joystick_2(joyC),
.joystick_3(joyD),
.status(status),
.ioctl_download(downloading),
.ioctl_addr(ioctl_addr),
.ioctl_wr(loader_clk),
.ioctl_dout(file_input),
.ioctl_wait(0),
.ioctl_index(filetype),
.sd_lba(sd_lba),
.sd_rd(sd_rd),
.sd_wr(sd_wr),
.sd_ack(sd_ack),
.sd_buff_addr(sd_buff_addr),
.sd_buff_dout(sd_buff_dout),
.sd_buff_din(sd_buff_din),
.sd_buff_wr(sd_buff_wr),
.img_mounted(img_mounted),
.img_readonly(img_readonly),
.img_size(img_size),
.ps2_kbd_led_use(0),
.ps2_kbd_led_status(0)
);
wire clock_locked;
wire clk85;
wire clk;
pll pll
(
.refclk(CLK_50M),
.rst(0),
.outclk_0(clk85),
.outclk_1(SDRAM_CLK),
.outclk_2(clk),
.locked(clock_locked)
);
// reset after download
reg [7:0] download_reset_cnt;
wire download_reset = download_reset_cnt != 0;
always @(posedge CLK_50M) begin
if(downloading) download_reset_cnt <= 8'hFF;
else if(!loader_busy && download_reset_cnt != 0) download_reset_cnt <= download_reset_cnt - 8'd1;
end
// hold machine in reset until first download starts
reg init_reset;
always @(posedge CLK_50M) begin
if(!clock_locked) init_reset <= 1'b1;
else if(downloading) init_reset <= 1'b0;
end
wire [8:0] cycle;
wire [8:0] scanline;
wire [15:0] sample;
wire [5:0] color;
wire joypad_strobe;
wire [1:0] joypad_clock;
wire [21:0] memory_addr;
wire memory_read_cpu, memory_read_ppu;
wire memory_write;
wire [7:0] memory_din_cpu, memory_din_ppu;
wire [7:0] memory_dout;
reg [23:0] joypad_bits, joypad_bits2;
reg [7:0] powerpad_d3, powerpad_d4;
reg [1:0] last_joypad_clock;
wire [11:0] powerpad = joyA[20:9] | joyB[20:9] | joyC[20:9] | joyD[20:9];
wire [7:0] nes_joy_A = { joyA[0], joyA[1], joyA[2], joyA[3], joyA[7], joyA[6], joyA[5], joyA[4] };
wire [7:0] nes_joy_B = { joyB[0], joyB[1], joyB[2], joyB[3], joyB[7], joyB[6], joyB[5], joyB[4] };
wire [7:0] nes_joy_C = { joyC[0], joyC[1], joyC[2], joyC[3], joyC[7], joyC[6], joyC[5], joyC[4] };
wire [7:0] nes_joy_D = { joyD[0], joyD[1], joyD[2], joyD[3], joyD[7], joyD[6], joyD[5], joyD[4] };
wire fds_btn = joyA[8] | joyB[8];
wire fds_swap = fds_swap_invert ^ fds_btn;
reg [1:0] nes_ce;
always @(posedge clk) begin
if (reset_nes) begin
joypad_bits <= 0;
joypad_bits2 <= 0;
powerpad_d3 <= 0;
powerpad_d4 <= 0;
last_joypad_clock <= 0;
end else begin
if (joypad_strobe) begin
joypad_bits <= {status[10] ? {8'h08, nes_joy_C} : 16'h0000, joy_swap ? nes_joy_B : nes_joy_A} | fds_btn;
joypad_bits2 <= {status[10] ? {8'h04, nes_joy_D} : 16'h0000, joy_swap ? nes_joy_A : nes_joy_B};
powerpad_d4 <= {4'b0000, powerpad[7], powerpad[11], powerpad[2], powerpad[3]};
powerpad_d3 <= {powerpad[6], powerpad[10], powerpad[9], powerpad[5], powerpad[8], powerpad[4], powerpad[0], powerpad[1]};
end
if (!joypad_clock[0] && last_joypad_clock[0]) begin
joypad_bits <= {1'b0, joypad_bits[23:1]};
end
if (!joypad_clock[1] && last_joypad_clock[1]) begin
joypad_bits2 <= {1'b0, joypad_bits2[23:1]};
powerpad_d4 <= {1'b0, powerpad_d4[7:1]};
powerpad_d3 <= {1'b0, powerpad_d3[7:1]};
end
last_joypad_clock <= joypad_clock;
end
end
// Loader
wire [7:0] file_input;
wire [7:0] loader_input = (loader_busy && !downloading) ? bios_data : file_input;
wire loader_clk;
wire [21:0] loader_addr;
wire [7:0] loader_write_data;
wire loader_reset = !download_reset; //loader_conf[0];
wire loader_write;
wire [31:0] loader_flags;
reg [31:0] mapper_flags;
wire loader_busy, loader_done, loader_fail;
GameLoader loader
(
clk, loader_reset, downloading, filetype,
loader_input, loader_clk, mirroring_osd,
loader_addr, loader_write_data, loader_write,
loader_flags, loader_busy, loader_done, loader_fail
);
always @(posedge clk) begin
if (loader_done) mapper_flags <= loader_flags;
end
reg led_blink;
always @(posedge clk) begin
int cnt = 0;
cnt <= cnt + 1;
if(cnt == 10000000) begin
cnt <= 0;
led_blink <= ~led_blink;
end;
end
wire reset_nes = init_reset || buttons[1] || arm_reset || download_reset || loader_fail || bk_loading;
wire run_nes = (nes_ce == 3); // keep running even when reset, so that the reset can actually do its job!
wire [14:0] bram_addr;
wire [7:0] bram_din;
wire [7:0] bram_dout;
wire bram_write;
wire bram_override;
// NES is clocked at every 4th cycle.
always @(posedge clk) nes_ce <= nes_ce + 1'd1;
NES nes
(
clk, reset_nes, run_nes,
mapper_flags,
sample, color,
joypad_strobe, joypad_clock, {powerpad_d4[0],powerpad_d3[0],joypad_bits2[0],joypad_bits[0]},
fds_swap,
5'b11111, // enable all channels
memory_addr,
memory_read_cpu, memory_din_cpu,
memory_read_ppu, memory_din_ppu,
memory_write, memory_dout,
bram_addr, bram_din, bram_dout,
bram_write, bram_override,
cycle, scanline,
int_audio, ext_audio
);
assign SDRAM_CKE = 1'b1;
wire [7:0] xor_data;
wire [7:0] bios_data;
reg last_loader_write;
wire bios_write = (loader_write && !last_loader_write && filetype == 8'h00);
dpram #("fdspatch.mif", 13) biospatch
(
.clock_a(clk),
.address_a(ioctl_addr[12:0]),
.wren_a(bios_write),
.data_a(bios_data ^ loader_write_data),
.q_a(xor_data),
.clock_b(clk),
.address_b(loader_addr[12:0]),
.q_b(bios_data)
);
// loader_write -> clock when data available
reg loader_write_mem;
reg [7:0] loader_write_data_mem;
reg [21:0] loader_addr_mem;
reg loader_write_triggered;
always @(posedge clk) begin
if(loader_write) begin
loader_write_triggered <= 1'b1;
loader_addr_mem <= loader_addr;
loader_write_data_mem <= (downloading && filetype == 8'h00) ? loader_write_data ^ xor_data : loader_write_data;
end
if(nes_ce == 3) begin
loader_write_mem <= loader_write_triggered;
if(loader_write_triggered)
loader_write_triggered <= 1'b0;
end
end
sdram sdram
(
// interface to the MT48LC16M16 chip
.sd_data ( SDRAM_DQ ),
.sd_addr ( SDRAM_A ),
.sd_dqm ( {SDRAM_DQMH, SDRAM_DQML} ),
.sd_cs ( SDRAM_nCS ),
.sd_ba ( SDRAM_BA ),
.sd_we ( SDRAM_nWE ),
.sd_ras ( SDRAM_nRAS ),
.sd_cas ( SDRAM_nCAS ),
// system interface
.clk ( clk85 ),
.clkref ( nes_ce[1] ),
.init ( !clock_locked ),
// cpu/chipset interface
.addr ( downloading || loader_busy ? {3'b000, loader_addr_mem} : {3'b000, memory_addr} ),
.we ( memory_write || loader_write_mem ),
.din ( downloading || loader_busy ? loader_write_data_mem : memory_dout ),
.oeA ( memory_read_cpu ),
.doutA ( memory_din_cpu ),
.oeB ( memory_read_ppu ),
.doutB ( memory_din_ppu ),
.bk_clk ( clk ),
.bk_addr ( {sd_lba[5:0],sd_buff_addr} ),
.bk_dout ( sd_buff_din ),
.bk_din ( sd_buff_dout ),
.bk_we ( sd_buff_wr & sd_ack ),
.bko_addr ( bram_addr ),
.bko_dout ( bram_din ),
.bko_din ( bram_dout ),
.bko_we ( bram_write ),
.bk_override ( bram_override )
);
wire downloading;
wire [2:0] scale = status[3:1];
wire [2:0] sl = scale ? scale - 1'd1 : 3'd0;
assign VGA_SL = sl[1:0];
video video
(
.*,
.clk(clk85),
.count_v(scanline),
.count_h(cycle),
.forced_scandoubler(forced_scandoubler),
.scale(scale),
.hide_overscan(hide_overscan),
.palette(palette2_osd),
.ce_pix(CE_PIXEL)
);
///////////////////////// STATE SAVE/LOAD /////////////////////////////
reg bk_ena = 0;
always @(posedge clk) begin
reg old_downloading = 0;
old_downloading <= downloading;
if(~old_downloading & downloading) bk_ena <= 0;
//Save file always mounted in the end of downloading state.
if(downloading && img_mounted && !img_readonly) bk_ena <= 1;
end
wire bk_load = status[6];
wire bk_save = status[7];
reg bk_loading = 0;
reg bk_state = 0;
reg bk_request = 0;
always @(posedge clk) begin
reg old_load = 0, old_save = 0, old_ack;
reg old_downloading = 0;
old_downloading <= downloading;
old_load <= bk_load & bk_ena;
old_save <= bk_save & bk_ena;
old_ack <= sd_ack;
if(~old_ack & sd_ack) {sd_rd, sd_wr} <= 0;
if(!bk_state) begin
if((~old_load & bk_load) | (~old_save & bk_save)) begin
bk_loading <= bk_load;
bk_request <= 1;
end
if(old_downloading & ~downloading & |img_size & bk_ena) begin
bk_loading <= 1;
bk_request <= 1;
end
if (bk_request && !loader_busy) begin
bk_request <= 0;
bk_state <= 1;
sd_lba <= 0;
sd_rd <= bk_load;
sd_wr <= ~bk_load;
end
end else begin
if(old_ack & ~sd_ack) begin
if(&sd_lba[5:0]) begin
bk_loading <= 0;
bk_state <= 0;
end else begin
sd_lba <= sd_lba + 1'd1;
sd_rd <= bk_loading;
sd_wr <= ~bk_loading;
end
end
end
end
endmodule
/////////////////////////////////////////////////////////////////////////
// Module reads bytes and writes to proper address in ram.
// Done is asserted when the whole game is loaded.
// This parses iNES headers too.
module GameLoader
(
input clk,
input reset,
input downloading,
input [7:0] filetype,
input [7:0] indata,
input indata_clk,
input invert_mirroring,
output reg [21:0] mem_addr,
output [7:0] mem_data,
output mem_write,
output [31:0] mapper_flags,
output reg busy,
output reg done,
output reg error
);
reg [7:0] prgsize;
reg [3:0] ctr;
reg [7:0] ines[0:15]; // 16 bytes of iNES header
reg [21:0] bytes_left;
wire [7:0] prgrom = ines[4]; // Number of 16384 byte program ROM pages
wire [7:0] chrrom = ines[5]; // Number of 8192 byte character ROM pages (0 indicates CHR RAM)
wire has_chr_ram = (chrrom == 0);
assign mem_data = (state == STATE_CLEARRAM) ? 8'h00 : indata;
assign mem_write = (((bytes_left != 0) && (state == STATE_LOADPRG || state == STATE_LOADCHR)
|| (downloading && (state == STATE_LOADHEADER || state == STATE_LOADFDS))) && indata_clk)
|| ((bytes_left != 0) && ((state == STATE_CLEARRAM) || (state == STATE_COPYBIOS)) && clearclk == 4'h2);
wire [2:0] prg_size = prgrom <= 1 ? 3'd0 : // 16KB
prgrom <= 2 ? 3'd1 : // 32KB
prgrom <= 4 ? 3'd2 : // 64KB
prgrom <= 8 ? 3'd3 : // 128KB
prgrom <= 16 ? 3'd4 : // 256KB
prgrom <= 32 ? 3'd5 : // 512KB
prgrom <= 64 ? 3'd6 : 3'd7;// 1MB/2MB
wire [2:0] chr_size = chrrom <= 1 ? 3'd0 : // 8KB
chrrom <= 2 ? 3'd1 : // 16KB
chrrom <= 4 ? 3'd2 : // 32KB
chrrom <= 8 ? 3'd3 : // 64KB
chrrom <= 16 ? 3'd4 : // 128KB
chrrom <= 32 ? 3'd5 : // 256KB
chrrom <= 64 ? 3'd6 : 3'd7;// 512KB/1MB
// detect iNES2.0 compliant header
wire is_nes20 = (ines[7][3:2] == 2'b10);
// differentiate dirty iNES1.0 headers from proper iNES2.0 ones
wire is_dirty = !is_nes20 && ((ines[9][7:1] != 0)
|| (ines[10] != 0)
|| (ines[11] != 0)
|| (ines[12] != 0)
|| (ines[13] != 0)
|| (ines[14] != 0)
|| (ines[15] != 0));
// Read the mapper number
wire [7:0] mapper = {is_dirty ? 4'b0000 : ines[7][7:4], ines[6][7:4]};
wire [7:0] ines2mapper = {is_nes20 ? ines[8] : 8'h00};
// ines[6][0] is mirroring
// ines[6][3] is 4 screen mode
// ines[8][7:4] is NES 2.0 submapper
assign mapper_flags = {7'b0, ines2mapper, ines[6][3], has_chr_ram, ines[6][0] ^ invert_mirroring, chr_size, prg_size, mapper};
reg [3:0] clearclk; //Wait for SDRAM
typedef enum bit [2:0] { STATE_LOADHEADER, STATE_LOADPRG, STATE_LOADCHR, STATE_LOADFDS, STATE_ERROR, STATE_CLEARRAM, STATE_COPYBIOS, STATE_DONE } mystate;
mystate state;
always @(posedge clk) begin
if (reset) begin
state <= STATE_LOADHEADER;
busy <= 0;
done <= 0;
ctr <= 0;
mem_addr <= (filetype[1:0] | filetype[7:6]) == 6'h02 ? 22'b00_0100_0000_0000_0001_0000 : 22'b00_0000_0000_0000_0000_0000; // Address for FDS : BIOS/PRG
end else begin
case(state)
// Read 16 bytes of ines header
STATE_LOADHEADER:
if (indata_clk) begin
error <= 0;
ctr <= ctr + 1'd1;
mem_addr <= mem_addr + 1'd1;
ines[ctr] <= indata;
bytes_left <= {prgrom, 14'b0};
if (ctr == 4'b1111) begin
// Check the 'NES' header. Also, we don't support trainers.
busy <= 1;
if ((ines[0] == 8'h4E) && (ines[1] == 8'h45) && (ines[2] == 8'h53) && (ines[3] == 8'h1A) && !ines[6][2]) begin
mem_addr <= 0; // Address for PRG
state <= STATE_LOADPRG;
//FDS
end else if ((ines[0] == 8'h46) && (ines[1] == 8'h44) && (ines[2] == 8'h53) && (ines[3] == 8'h1A)) begin
mem_addr <= 22'b00_0100_0000_0000_0001_0000; // Address for FDS skip Header
state <= STATE_LOADFDS;
bytes_left <= 21'b1;
end else if (filetype[7:0]==8'h00) begin // Bios
state <= STATE_LOADFDS;
mem_addr <= 22'b00_0000_0000_0000_0001_0000; // Address for BIOS skip Header
bytes_left <= 21'b1;
end else if ((filetype[1:0] | filetype[7:6])==6'h02) begin // FDS
state <= STATE_LOADFDS;
mem_addr <= 22'b00_0100_0000_0000_0010_0000; // Address for FDS no Header
bytes_left <= 21'b1;
end else begin
state <= STATE_ERROR;
end
end
end
STATE_LOADPRG, STATE_LOADCHR: begin // Read the next |bytes_left| bytes into |mem_addr|
if (bytes_left != 0) begin
if (indata_clk) begin
bytes_left <= bytes_left - 1'd1;
mem_addr <= mem_addr + 1'd1;
end
end else if (state == STATE_LOADPRG) begin
state <= STATE_LOADCHR;
mem_addr <= 22'b10_0000_0000_0000_0000_0000; // Address for CHR
bytes_left <= {1'b0, chrrom, 13'b0};
end else if (state == STATE_LOADCHR) begin
done <= 1;
busy <= 0;
end
end
STATE_ERROR: begin
done <= 1;
error <= 1;
busy <= 0;
end
STATE_LOADFDS: begin // Read the next |bytes_left| bytes into |mem_addr|
if (downloading) begin
if (indata_clk) begin
mem_addr <= mem_addr + 1'd1;
end
end else begin
// mem_addr <= 22'b11_1000_0000_0000_0000_0000;
// bytes_left <= 21'h800;
mem_addr <= 22'b11_1000_0000_0001_0000_0010; // FDS - Clear these two RAM addresses to restart BIOS
bytes_left <= 21'h2;
ines[4] <= 8'hFF;//no masking
ines[5] <= 8'h00;//0x2000
ines[6] <= 8'h40;
ines[7] <= 8'h10;
ines[8] <= 8'h00;
ines[9] <= 8'h00;
ines[10] <= 8'h00;
ines[11] <= 8'h00;
ines[12] <= 8'h00;
ines[13] <= 8'h00;
ines[14] <= 8'h00;
ines[15] <= 8'h00;
state <= STATE_CLEARRAM;
clearclk <= 4'h0;
end
end
STATE_CLEARRAM: begin // Read the next |bytes_left| bytes into |mem_addr|
clearclk <= clearclk + 4'h1;
if (bytes_left != 21'h0) begin
if (clearclk == 4'hF) begin
bytes_left <= bytes_left - 1'd1;
mem_addr <= mem_addr + 1'd1;
end
end else begin
mem_addr <= 22'b00_0000_0000_0000_0000_0000;
bytes_left <= 21'h2000;
state <= STATE_COPYBIOS;
clearclk <= 4'h0;
end
end
STATE_COPYBIOS: begin // Read the next |bytes_left| bytes into |mem_addr|
clearclk <= clearclk + 4'h1;
if (bytes_left != 21'h0) begin
if (clearclk == 4'hF) begin
bytes_left <= bytes_left - 1'd1;
mem_addr <= mem_addr + 1'd1;
end
end else begin
state <= STATE_DONE;
end
end
STATE_DONE: begin // Read the next |bytes_left| bytes into |mem_addr|
done <= 1;
busy <= 0;
end
endcase
end
end
endmodule