blob: 67067d1c9cd61e07c10122f1e6b0bfaf7a30b032 [file] [log] [blame]
`default_nettype none
`timescale 1ns/10ps
module hack_soc (
input clk,
input display_clk,
input reset,
input hack_external_reset,
// ** RAM: qspi serial sram **/
output ram_cs_n,
output ram_sck,
output ram_sio_oe, // output enable the SIO lines
// SIO as inputs from SRAM
input ram_sio0_i, // sram_si_sio0
input ram_sio1_i, // sram_so_sio1
input ram_sio2_i, // sram_sio2
input ram_sio3_i, // sram_hold_n_sio3
// SIO as outputs to SRAM
output ram_sio0_o, // sram_si_sio0
output ram_sio1_o, // sram_so_sio1
output ram_sio2_o, // sram_sio2
output ram_sio3_o, // sram_hold_n_sio3
// ** ROM: qspi serial sram **/
output rom_cs_n,
output rom_sck,
output rom_sio_oe, // output enable the SIO lines
// SIO as inputs from SRAM
input rom_sio0_i, // sram_si_sio0
input rom_sio1_i, // sram_so_sio1
input rom_sio2_i, // sram_sio2
input rom_sio3_i, // sram_hold_n_sio3
// SIO as outputs to SRAM
output rom_sio0_o, // sram_si_sio0
output rom_sio1_o, // sram_so_sio1
output rom_sio2_o, // sram_sio2
output rom_sio3_o, // sram_hold_n_sio3
// ** VRAM: qspi serial sram **/
output vram_cs_n,
output vram_sck,
output vram_sio_oe, // output enable the SIO lines
// SIO as inputs from SRAM
input vram_sio0_i, // sram_si_sio0
input vram_sio1_i, // sram_so_sio1
input vram_sio2_i, // sram_sio2
input vram_sio3_i, // sram_hold_n_sio3
// SIO as outputs to SRAM
output vram_sio0_o, // sram_si_sio0
output vram_sio1_o, // sram_so_sio1
output vram_sio2_o, // sram_sio2
output vram_sio3_o, // sram_hold_n_sio3
// ** DISPLAY ** //
output display_hsync,
output display_vsync,
output display_rgb,
// ** KEYBOARD ** //
input [7:0] keycode,
// ** GPIO ** //
input [HACK_GPIO_I_WIDTH-1:0] gpio_i,
output reg [HACK_GPIO_O_WIDTH-1:0] gpio_o,
// ROM LOADING LINES
input rom_loader_load,
input rom_loader_sck,
input [INSTRUCTION_WIDTH-1:0] rom_loader_data,
output rom_loader_ack
// DEBUG nets
// output [ROM_ADDRESS_WIDTH-1:0] debug_pc,
// output [RAM_ADDRESS_WIDTH-1:0] debug_addressM,
// output [INSTRUCTION_WIDTH-1:0] debug_instruction,
// output reg [WORD_WIDTH-1:0] debug_gpio
);
//*******************************************************************************************
// Main project parameters
//*******************************************************************************************
parameter WORD_WIDTH = 16;
parameter RAM_WORDS = 32768; // 2^A_WIDTH
parameter RAM_ADDRESS_WIDTH = $clog2(RAM_WORDS);
parameter ROM_WORDS = 32768; // 2^A_WIDTH
parameter ROM_ADDRESS_WIDTH = $clog2(ROM_WORDS);
parameter INSTRUCTION_WIDTH = WORD_WIDTH;
parameter VRAM_WORDS = 8192;
parameter VRAM_ADDRESS_WIDTH = $clog2(VRAM_WORDS);
// Address Mapping
parameter [RAM_ADDRESS_WIDTH-1:0] HACK_ADDRESS_VRAM_START = 16384;
parameter [RAM_ADDRESS_WIDTH-1:0 ]HACK_ADDRESS_VRAM_END = 24575;
parameter [RAM_ADDRESS_WIDTH-1:0] HACK_ADDRESS_KEYBOARD = 'h6000;
parameter [RAM_ADDRESS_WIDTH-1:0] HACK_ADDRESS_GPIO_I = 'h6001;
parameter [RAM_ADDRESS_WIDTH-1:0] HACK_ADDRESS_GPIO_O = 'h6002;
parameter SRAM_ADDRESS_WIDTH = 24;
parameter HACK_GPIO_WIDTH = 8;
parameter HACK_GPIO_I_WIDTH = 4;
parameter HACK_GPIO_O_WIDTH = 4;
parameter HACK_SCREEN_WIDTH = 512;
parameter HACK_SCREEN_HEIGHT = 256;
parameter HACK_SCREEN_H_OFFSET = 64;//64;
parameter HACK_SCREEN_V_OFFSET = 112;
reg [1:0] hack_wait_clocks;
reg rom_loading_process;
wire hack_clk_strobe;
wire hack_clk_going_to_rise;
hack_clock hack_clock_0(
.clk(clk),
.reset(reset),
.hack_clk(hack_clk),
.strobe(hack_clk_strobe),
.going_to_rise(hack_clk_going_to_rise)
);
wire hack_clk;
wire hack_reset;
wire [RAM_ADDRESS_WIDTH-1:0] hack_addressM;
wire hack_writeM;
wire [WORD_WIDTH-1:0] hack_inM;
wire [WORD_WIDTH-1:0] hack_outM;
wire [INSTRUCTION_WIDTH-1:0] hack_instruction;
wire [ROM_ADDRESS_WIDTH-1:0] hack_pc;
reg hack_rom_request;
hack_cpu #(
.WORD_WIDTH(WORD_WIDTH),
.INSTRUCTION_WIDTH(INSTRUCTION_WIDTH),
.RAM_ADDRESS_WIDTH(RAM_ADDRESS_WIDTH),
.ROM_ADDRESS_WIDTH(ROM_ADDRESS_WIDTH)
) cpu (
.clk(hack_clk),
.inM(hack_inM),
.instruction(hack_instruction),
.reset(hack_reset),
.outM(hack_outM),
.writeM(hack_writeM),
.addressM(hack_addressM),
.pc(hack_pc)
);
wire rom_loader_request;
wire [INSTRUCTION_WIDTH-1:0] rom_loader_output_data;
wire [ROM_ADDRESS_WIDTH-1:0] rom_loader_output_address;
rom_stream_loader #(.DATA_WIDTH(INSTRUCTION_WIDTH), .ADDRESS_WIDTH(ROM_ADDRESS_WIDTH))
rom_loader(
.clk(clk),
.reset(reset),
// Loader nets
.load(rom_loading_process), //rom_loader_load),
.input_data(rom_loader_data),
.sck(rom_loader_sck),
.ack(rom_loader_ack),
// ROM nets
.rom_busy(rom_busy),
.rom_initialized(rom_initialized),
.rom_request(rom_loader_request),
.output_data(rom_loader_output_data),
.output_address(rom_loader_output_address)
);
// inputs to spi_sram_encoder
wire ram_request;
reg ram_step1_write_request;
reg ram_step2_read_request;
// outputs from spi_sram_encoder
wire ram_busy;
wire ram_initialized;
wire ram_write_enable;
wire [WORD_WIDTH-1:0] ram_data_out;
reg [RAM_ADDRESS_WIDTH-1:0] synch_hack_addressM;
reg synch_hack_writeM;
reg [WORD_WIDTH-1:0] synch_hack_outM;
// always @(posedge hack_clk ) begin
// synch_hack_writeM <= hack_writeM;
// synch_hack_outM <= hack_outM;
// end
always @(posedge clk ) begin
ram_step1_write_request <= 0;
ram_step2_read_request <= 0;
if(hack_clk_going_to_rise) begin
synch_hack_outM <= 0;
if(hack_writeM) begin
synch_hack_writeM <= hack_writeM;
synch_hack_outM <= hack_outM;
synch_hack_addressM <= hack_addressM;
ram_step1_write_request <= 1;
end
end else if(hack_clk_strobe && ~hack_clk) begin
ram_step1_write_request <= 0;
ram_step2_read_request <= 1;
synch_hack_writeM <= 0;
synch_hack_addressM <= hack_addressM;
synch_hack_outM <= 0;
end
end
spi_sram_encoder #( .WORD_WIDTH(WORD_WIDTH), .ADDRESS_WIDTH(RAM_ADDRESS_WIDTH) )
ram_encoder_0
(
.clk(clk),
.reset(reset),
.request(ram_request),
.busy(ram_busy),
.initialized(ram_initialized),
.address(synch_hack_addressM),
.write_enable(ram_write_enable),
.data_in(ram_data_out),
.data_out(synch_hack_outM),
.sram_cs_n(ram_cs_n),
.sram_sck(ram_sck),
.sram_sio_oe(ram_sio_oe),
.sram_sio0_i(ram_sio0_i),
.sram_sio1_i(ram_sio1_i),
.sram_sio2_i(ram_sio2_i),
.sram_sio3_i(ram_sio3_i),
.sram_sio0_o(ram_sio0_o),
.sram_sio1_o(ram_sio1_o),
.sram_sio2_o(ram_sio2_o),
.sram_sio3_o(ram_sio3_o)
);
// inputs to spi_sram_encoder
wire rom_request;
wire [ROM_ADDRESS_WIDTH-1:0] rom_address;
// outputs from spi_sram_encoder
wire rom_busy;
wire rom_initialized;
wire rom_write_enable;
// wire [INSTRUCTION_WIDTH-1:0] rom_data_out = {INSTRUCTION_WIDTH{1'b0}};
spi_sram_encoder #( .WORD_WIDTH(INSTRUCTION_WIDTH), .ADDRESS_WIDTH(ROM_ADDRESS_WIDTH) )
rom_encoder_0
(
.clk(clk),
.reset(reset),
.request(rom_request),
.busy(rom_busy),
.initialized(rom_initialized),
.address(rom_address),
.write_enable(rom_write_enable),
.data_in(hack_instruction),
.data_out(rom_loader_output_data),
.sram_cs_n(rom_cs_n),
.sram_sck(rom_sck),
.sram_sio_oe(rom_sio_oe),
.sram_sio0_i(rom_sio0_i),
.sram_sio1_i(rom_sio1_i),
.sram_sio2_i(rom_sio2_i),
.sram_sio3_i(rom_sio3_i),
.sram_sio0_o(rom_sio0_o),
.sram_sio1_o(rom_sio1_o),
.sram_sio2_o(rom_sio2_o),
.sram_sio3_o(rom_sio3_o)
);
wire pixel_value;
wire vram_initialized;
wire vram_write_enable;
wire [VRAM_ADDRESS_WIDTH-1:0] vram_write_address;
spi_video_ram_2 #(
.WORD_WIDTH(WORD_WIDTH),
.VRAM_ADDRESS_WIDTH(VRAM_ADDRESS_WIDTH),
.SRAM_ADDRESS_WIDTH(SRAM_ADDRESS_WIDTH),
.HACK_SCREEN_WIDTH(HACK_SCREEN_WIDTH),
.HACK_SCREEN_HEIGHT(HACK_SCREEN_HEIGHT),
.HACK_SCREEN_H_OFFSET(HACK_SCREEN_H_OFFSET),
.HACK_SCREEN_V_OFFSET(HACK_SCREEN_V_OFFSET)
) spi_video_ram_1 (
.clk(clk),
.reset(reset),
.initialized(vram_initialized),
// VIDEO VRAM READ
.clks_before_active(display_clks_before_active),
.display_active(display_active),
.display_hpos(display_hpos),
.display_vpos(display_vpos),
.pixel_out(pixel_value),
// HACK VRAM WRITE
.hack_clk_rise_edge(hack_clk_strobe & hack_clk),
.hack_outM(hack_outM),
.hack_addressM(vram_write_address),
.hack_writeM(vram_write_enable),
// Serial SRAM nets
.sram_cs_n(vram_cs_n),
.sram_sck(vram_sck),
.sram_sio_oe(vram_sio_oe), // output enable the SIO lines
// SIO as inputs from SRAM
.sram_sio0_i(vram_sio0_i), // sram_si_sio0
.sram_sio1_i(vram_sio1_i), // sram_so_sio1
.sram_sio2_i(vram_sio2_i), // sram_sio2
.sram_sio3_i(vram_sio3_i), // sram_hold_n_sio3
// SIO as outputs to SRAM
.sram_sio0_o(vram_sio0_o), // sram_si_sio0
.sram_sio1_o(vram_sio1_o), // sram_so_sio1
.sram_sio2_o(vram_sio2_o), // sram_sio2
.sram_sio3_o(vram_sio3_o) // sram_hold_n_sio3
);
// VIDEO GENERATOR
wire [9:0] display_hpos;
wire [9:0] display_vpos;
wire display_active;
wire [9:0] display_clks_before_active;
wire reset_display = reset; //hack_reset; //reset;
// assign display_rgb = display_hpos[2] || display_vpos[2];
video_signal_generator_640x480 video_generator_1 (
//i_clk, // base clock
.i_pix_stb(display_clk), // pixel clock strobe
.i_rst(reset_display), // reset: restarts frame
.o_hs(display_hsync), // horizontal sync
.o_vs(display_vsync), // vertical sync
// .o_blanking(), // high during blanking interval
.o_active(display_active), // high during active pixel drawing
// .o_screenend(), // high for one tick at the end of screen
// .o_animate(), // high for one tick at end of active drawing
.o_x(display_hpos), // current pixel x position
.o_y(display_vpos), // current pixel y position
.o_clks_before_active(display_clks_before_active)
);
// ** Memory Address Mapping ** //
wire mapping_is_ram_address = hack_addressM < HACK_ADDRESS_VRAM_START;
wire mapping_is_vram_address = (hack_addressM >= HACK_ADDRESS_VRAM_START) && (hack_addressM <= HACK_ADDRESS_VRAM_END);
wire mapping_is_ram_or_vram_address = hack_addressM <= HACK_ADDRESS_VRAM_END;
wire mapping_is_keyboard_address = (hack_addressM==HACK_ADDRESS_KEYBOARD);
wire mapping_is_gpio_i_address = (hack_addressM==HACK_ADDRESS_GPIO_I);
wire mapping_is_gpio_o_address = (hack_addressM==HACK_ADDRESS_GPIO_O);
// assign ram_request = !hack_reset && ram_initialized && !ram_busy && hack_clk_strobe && hack_clk;
// assign ram_request = !hack_reset && ram_initialized && !ram_busy && hack_clk_strobe;
assign ram_request = !hack_reset && ram_initialized && !ram_busy && (ram_step1_write_request || ram_step2_read_request) ;
// assign hack_rom_request = rom_initialized && !rom_busy && hack_clk_strobe && hack_clk;
always @(posedge clk ) begin
hack_rom_request <= 0;
if(hack_clk_strobe && ~hack_clk) begin
hack_rom_request <= rom_initialized && !rom_busy ;//&& hack_clk_strobe && hack_clk;
end
end
assign rom_request = rom_loading_process ? rom_loader_request : hack_rom_request;
assign rom_write_enable = (rom_loading_process);// && rom_loader_request);
assign ram_write_enable = !hack_reset && synch_hack_writeM && mapping_is_ram_or_vram_address;
assign vram_write_enable = !hack_reset && hack_clk_strobe && hack_writeM && mapping_is_vram_address;
assign rom_address = rom_loading_process ? rom_loader_output_address : hack_pc;
assign vram_write_address = hack_addressM[VRAM_ADDRESS_WIDTH-1:0];
assign hack_inM = (mapping_is_ram_or_vram_address) ? ram_data_out : /* ram & vram */
(hack_addressM == HACK_ADDRESS_KEYBOARD) ? { {(WORD_WIDTH-8){1'b0}}, keycode} : /*keyboard*/
mapping_is_gpio_i_address ? { {(WORD_WIDTH-HACK_GPIO_O_WIDTH){1'b0}},gpio_i_stored} : /* GPIO_I */
mapping_is_gpio_o_address ? { {(WORD_WIDTH-HACK_GPIO_O_WIDTH){1'b0}}, gpio_o} : /* GPIO_O */
0;
assign hack_reset = rom_loading_process || hack_external_reset || (hack_wait_clocks!=0) || reset || !ram_initialized || !rom_initialized || !vram_initialized;
assign display_rgb = display_active ? (hack_reset ? logo_pixel : pixel_value) : 0 ;
wire logo_pixel;
reg [4:0] boot_loading_offset;
//assign boot_loading_offset = rom_loader_data[3:0];// rom_loading_process ? rom_loader_data[9:0] : 0;
always @(posedge clk ) begin
if(reset) begin
boot_loading_offset <= 0;
end else begin
if(rom_loading_process && rom_loader_sck)
boot_loading_offset <= boot_loading_offset + 1;
end
end
boot_logo boot_logo_1 (
.hpos(display_hpos),
.vpos(display_vpos),
.pixel(logo_pixel)
, .loading_offset(boot_loading_offset)
);
always @(posedge clk ) begin
if(rom_loader_load) begin
if(hack_reset || (hack_clk_strobe && hack_clk)) begin
rom_loading_process <= 1'b1;
end
end else begin
rom_loading_process <= 1'b0;
end
end
always @(posedge clk ) begin
if(reset) begin
hack_wait_clocks <= 2;
end else begin
if(hack_external_reset || rom_loading_process) begin
hack_wait_clocks <= 2;
end else if(hack_wait_clocks!=0 && hack_clk_strobe && hack_clk) begin
hack_wait_clocks <= hack_wait_clocks - 2'b1;
end
end
end
// GPIO_O
always @(posedge hack_clk) begin
if(hack_reset) begin
gpio_o <= 0;
end else begin
if(mapping_is_gpio_o_address && hack_writeM) begin
gpio_o <= hack_outM[HACK_GPIO_O_WIDTH-1:0];
end
end
end
// GPIO_I
reg [HACK_GPIO_I_WIDTH-1:0] gpio_i_stored;
always @(posedge hack_clk) begin
if(hack_reset) begin
gpio_i_stored <= 0;
end else begin
if(mapping_is_gpio_i_address && ~hack_writeM) begin
gpio_i_stored <= gpio_i;
end
end
end
`ifdef FORMAL
// register for knowing if we have just started
reg f_past_valid = 0;
reg initial_reset_passed = 0;
// start in reset
initial assume(reset);
initial assume(rom_loader_load==0);
initial assume(hack_wait_clocks==2);
// The clock toggles.
reg last_clk = 1'b0;
always @($global_clock) begin
assume (clk == !last_clk);
last_clk <= clk;
f_past_valid <= 1;
// Disable loading ROMs formal verification for now
assume(rom_loader_load==0);
assume(hack_external_reset==0);
if(f_past_valid) begin
if(initial_reset_passed) begin
assume(reset==0);
end
end
end
always @(negedge clk) begin
end
always @(posedge clk) begin
if(initial_reset_passed) begin
//assume(reset==0);
COVER_RAM_INIT: cover(ram_initialized);
COVER_ROM_INIT: cover(rom_initialized);
COVER_VRAM_INIT: cover(vram_initialized);
ASSERT_WAIT_CLOCK_BOUNDARIES: assert(hack_wait_clocks<=2);
if(!ram_initialized) begin
ASSERT_RAM_REQUESTS_ON_INIT: assert(ram_request==0);
end
if(!rom_initialized) begin
ASSERT_ROM_REQUESTS_ON_INIT: assert(rom_request==0);
end
if($past(ram_request) && !hack_reset && $rose(hack_clk)) begin
ASSERT_RAM_CLK_SYNCHRO: assert($rose(ram_sck));
end
end
if(f_past_valid) begin
COVER_HACK_CLOCK_START: cover($rose(hack_clk));
if($fell(reset)) begin
initial_reset_passed <= 1;
end
end
end
`endif
endmodule