`timescale 1ns / 100ps `define ROM_MAX 'h20000 `define BB_WRITE 8'h80 `define BB_AUTOINC 8'h40 `define BB_REG_CTRL_BASE 6'h00 `define BB_REG_CPU_BASE 6'h10 `define BB_REG_MEM_BASE 6'h20 `define BB_REG_IWM_BASE 6'h28 `define BB_REG_SCSI_BASE 6'h30 `define BB_REG_SCOPE_BASE 6'h38 /* SCSI Backbus interface */ `define BB_REG_LINES 0 `define BB_LINES_BSY 7 `define BB_LINES_SEL 6 `define BB_LINES_ACK 5 `define BB_LINES_ATN 4 `define BB_LINES_RST 3 `define BB_REG_ASSERT 1 `define BB_ASSERT_BSY 7 `define BB_ASSERT_SEL 6 `define BB_ASSERT_CD 5 `define BB_ASSERT_IO 4 `define BB_ASSERT_MSG 3 `define BB_ASSERT_REQ 2 `define BB_ASSERT_RST 1 `define BB_ASSERT_AUTO 0 /* Automatic mode */ `define BB_REG_ODATA 2 `define BB_REG_IDATA 3 `define BB_REG_ACNT_HI 4 `define BB_REG_ACNT_LO 5 module sim_pic ( input sdi, output reg sdo, output reg sck, output reg _spi_cs, input scsi_hshake, output reg nmi); integer rom_file; integer rom_size; reg [7:0] rom[0:`ROM_MAX]; reg [7:0] scsi_asserts; reg [7:0] scsi_cdb[0:11]; reg [7:0] scsi_buf[0:2047]; integer dbg_foo; /* SPI half clock period */ parameter SPI_HCLOCK = 40; /* Setup time of data vs rising clock edge */ parameter SPI_HEAD = 4; task do_spi; input [7:0] out_byte; /* Out to FPGA */ output reg [7:0] in_byte; /* In from FPGA */ reg [7:0] in_sr; reg [7:0] out_sr; begin in_sr = 8'hff; out_sr = out_byte; repeat(8) begin sck = 0; #(SPI_HCLOCK-SPI_HEAD); sdo = out_sr[7]; out_sr = { out_sr[6:0], 1'b0 }; in_sr = { in_sr[6:0], sdi }; #SPI_HEAD sck = 1; #SPI_HCLOCK; end sck = 0; in_byte = in_sr; end endtask // do_spi task run_to; input [23:0] addr; reg [7:0] stat; begin /* Set breakpoint */ _spi_cs = 0; do_spi(`BB_WRITE | `BB_AUTOINC | `BB_REG_CPU_BASE | 8, val); do_spi(addr[23:16], val); do_spi(addr[15:8], val); do_spi(addr[7:0], val); _spi_cs = 1; #(SPI_HCLOCK*4); /* Run CPU interface */ _spi_cs = 0; do_spi(`BB_WRITE | `BB_REG_CPU_BASE | 6, val); do_spi(8'h42, val); /* RUN + BKEN */ _spi_cs = 1; #(SPI_HCLOCK*4); stat = 0; while(!stat[3]) begin /* Get CPU status */ _spi_cs = 0; do_spi(`BB_REG_CPU_BASE | 7, val); do_spi(8'hff, val); do_spi(8'hff, stat); _spi_cs = 1; // $display("stat: %h", stat); // #(SPI_HCLOCK*40); end end endtask // run_to task scsi_set_lines; input [7:0] lines; begin _spi_cs = 0; do_spi(`BB_WRITE | `BB_REG_SCSI_BASE | `BB_REG_ASSERT, val); do_spi(lines, val); _spi_cs = 1; #(SPI_HCLOCK*4); end endtask task scsi_set; input integer line; begin scsi_asserts[line] = 1'b1; scsi_set_lines(scsi_asserts); end endtask task scsi_clear; input integer line; begin scsi_asserts[line] = 1'b0; scsi_set_lines(scsi_asserts); end endtask task scsi_set_autocnt; input integer cnt; begin _spi_cs = 0; do_spi(`BB_WRITE | `BB_AUTOINC | `BB_REG_SCSI_BASE | `BB_REG_ACNT_HI, val); do_spi(cnt[15:8], val); do_spi(cnt[7:0], val); _spi_cs = 1; #(SPI_HCLOCK*4); end endtask task scsi_set_data; input [7:0] data; begin _spi_cs = 0; do_spi(`BB_WRITE | `BB_REG_SCSI_BASE | `BB_REG_IDATA, val); do_spi(data, val); _spi_cs = 1; #(SPI_HCLOCK*4); end endtask task scsi_get_data; output [7:0] val; reg [7:0] dummy; begin _spi_cs = 0; do_spi(`BB_REG_SCSI_BASE | `BB_REG_ODATA, dummy); do_spi(8'hff, dummy); do_spi(8'hff, val); _spi_cs = 1; #(SPI_HCLOCK*4); end endtask task scsi_get_lines; output [7:0] val; reg [7:0] dummy; begin _spi_cs = 0; do_spi(`BB_REG_SCSI_BASE | `BB_REG_LINES, dummy); do_spi(8'hff, dummy); do_spi(8'hff, val); _spi_cs = 1; #(SPI_HCLOCK*4); end endtask task scsi_do_cmd; output integer len; output [7:0] stat; output direction; integer i; begin stat = 0; len = 0; direction = 0; case(scsi_cdb[0]) 'h12: begin /* INQUIRY */ direction = 1; for (i=0; i < 256; i = i + 1) scsi_buf[i] = 0; scsi_buf[4] = 32; scsi_buf[8] = 'h46; scsi_buf[9] = 'h4f; scsi_buf[10] = 'h4f; scsi_buf[16] = 'h42; scsi_buf[17] = 'h41; scsi_buf[18] = 'h52; len = scsi_cdb[4]; $display("CMD: INQUIRY 0x%h bytes", len); end 'h08: begin /* READ6 */ direction = 1; len = 512 * scsi_cdb[4]; if (len == 0) len = 512 * 256; $display("CMD: READ6 0x%h bytes", len); end 'h0a: begin /* WRITE6 */ direction = 0; len = 512 * scsi_cdb[4]; if (len == 0) len = 512 * 256; $display("CMD: WRITE6 0x%h bytes", len); end 'h28: begin /* READ10 */ direction = 1; len = 512 * (scsi_cdb[7] * 256 + scsi_cdb[8]); $display("CMD: READ10 0x%h bytes", len); end 'h2a: begin /* WRITE10 */ direction = 0; len = 512 * (scsi_cdb[7] * 256 + scsi_cdb[8]); $display("CMD: WRITE10 0x%h bytes", len); end default: begin stat = 1; /* CHECK CONDITION */ end endcase end endtask // scsi_init_cmd task do_scsi; reg [7:0] lines; reg [7:0] data; integer len, llen; reg [7:0] stat; reg direction; begin scsi_get_lines(lines); $display("Waiting selection... Lines: %h", lines); while (!lines[`BB_LINES_SEL] || lines[`BB_LINES_BSY]) scsi_get_lines(lines); scsi_get_data(data); $display("Select ID: %h lines %h", data, lines); stat = 0; if (!data[6]) $display("Wrong ID !"); else begin $display("Setting BSY"); scsi_set(`BB_ASSERT_BSY); $display("Waiting !SEL..."); while(lines[`BB_LINES_SEL]) scsi_get_lines(lines); $display("Setting CMD, starting cmd transfer"); scsi_set(`BB_ASSERT_CD); len = 1; i = 0; stat = 0; while(len) begin scsi_set(`BB_ASSERT_REQ); while(!lines[`BB_LINES_ACK]) scsi_get_lines(lines); scsi_get_data(data); $display("CMD %h = %h", i, data); scsi_cdb[i] = data; len = len - 1; i = i + 1; if (i == 1) begin /* get command size */ case (data) 'h12: len = 6 - 1; 'h08: len = 6 - 1; 'h0a: len = 6 - 1; 'h28: len = 10 - 1; 'h2a: len = 10 - 1; default: begin len = 0; stat = 1; end endcase $display("CMD size adjust %h", len); end scsi_clear(`BB_ASSERT_REQ); while(lines[`BB_LINES_ACK]) scsi_get_lines(lines); end scsi_do_cmd(len, stat, direction); scsi_clear(`BB_ASSERT_CD); if (direction) scsi_set(`BB_ASSERT_IO); i = 0; while (len) begin scsi_set(`BB_ASSERT_AUTO); /* Break up transfer */ if (len > 256) llen = 256; else llen = len; len = len - llen; $display("Chunk of %h, remaining %h...", llen, len); scsi_set_autocnt(llen); _spi_cs = 0; if (direction) begin do_spi(`BB_WRITE | `BB_REG_SCSI_BASE | `BB_REG_IDATA, val); while(llen != 0) begin $display("Writing byte %h", i); do_spi(scsi_buf[i], val); wait (!scsi_hshake); wait (scsi_hshake); llen = llen - 1; i = i + 1; end end else begin do_spi(`BB_REG_SCSI_BASE | `BB_REG_ODATA, val); #160; wait (scsi_hshake); do_spi(8'hff, val); wait (!scsi_hshake); $display("dummy1: %h", val); wait (scsi_hshake); do_spi(8'hff, val); wait (!scsi_hshake); $display("dummy2: %h", val); wait (scsi_hshake); do_spi(8'hff, val); wait (!scsi_hshake); $display("dummy3: %h", val); while(llen != 0) begin wait (scsi_hshake) ; do_spi(8'hff, data); if (llen > 3) wait (!scsi_hshake); scsi_buf[i] = data; $display("DATA %h: %h", i, data); llen = llen - 1; i = i + 1; end end _spi_cs = 1; #(SPI_HCLOCK*4); scsi_clear(`BB_ASSERT_AUTO); end $display("sending status %h", stat); scsi_set(`BB_ASSERT_CD); scsi_set(`BB_ASSERT_IO); scsi_set_data(stat); scsi_set(`BB_ASSERT_REQ); while(!lines[`BB_LINES_ACK]) scsi_get_lines(lines); scsi_clear(`BB_ASSERT_REQ); while(lines[`BB_LINES_ACK]) scsi_get_lines(lines); scsi_set(`BB_ASSERT_MSG); $display("Sending message"); scsi_set_data(0); scsi_set(`BB_ASSERT_REQ); while(!lines[`BB_LINES_ACK]) scsi_get_lines(lines); scsi_clear(`BB_ASSERT_REQ); while(lines[`BB_LINES_ACK]) scsi_get_lines(lines); $display("Clearing phase & BSY"); scsi_clear(`BB_ASSERT_CD); scsi_clear(`BB_ASSERT_IO); scsi_clear(`BB_ASSERT_MSG); scsi_clear(`BB_ASSERT_BSY); end // else: !if(!data[6]) end endtask // do_scsi task run_scsi; begin while(1) begin wait (scsi_hshake) do_scsi(); end end endtask // run_scsi task dump_latches; reg [7:0] sval[0:7]; begin /* Read latches */ _spi_cs = 0; do_spi(`BB_AUTOINC | `BB_REG_CPU_BASE, val); do_spi(8'hff, val); do_spi(8'hff, sval[0]); do_spi(8'hff, sval[1]); do_spi(8'hff, sval[2]); do_spi(8'hff, sval[3]); do_spi(8'hff, sval[4]); do_spi(8'hff, sval[5]); _spi_cs = 1; #(SPI_HCLOCK*4); $display("RW:%b U:%b L:%b ADDR: %h DATA: %h", sval[5][0], sval[5][1], sval[5][2], { sval[0], sval[1], sval[2] }, { sval[3], sval[4] }); end endtask // dump_latches task step; input integer count; begin repeat(count) begin /* Step CPU interface */ _spi_cs = 0; do_spi(`BB_WRITE | `BB_REG_CPU_BASE | 6, val); do_spi(8'h82, val); /* RUN + STEP */ _spi_cs = 1; #(SPI_HCLOCK*4); /* Should wait for completion... not useful * in practice as SPI is too slow */ end // repeat (count) end endtask // step reg [7:0] val; // reg [7:0] scopedump[0:(2048 * 8)-1]; integer i; initial begin nmi = 0; _spi_cs = 1; sdo = 1'bz; sck = 0; scsi_asserts = 0; #100 _spi_cs = 0; do_spi(`BB_AUTOINC | `BB_REG_CTRL_BASE, val); do_spi(8'hff, val); do_spi(8'hff, val); $display("FPGA ID = 0x%h", val); do_spi(8'hff, val); $display("FPGA Version = 0x%h", val); do_spi(8'hff, val); $display("FPGA Control = 0x%h", val); _spi_cs = 1; #(SPI_HCLOCK*4); /* Un-reset CPU */ _spi_cs = 0; do_spi(`BB_WRITE | `BB_REG_CTRL_BASE | 2, val); do_spi(8'h01, val); _spi_cs = 1; #(SPI_HCLOCK*4); `ifdef foo $display("Running to puts..."); run_to('h40326c); dump_latches(); repeat(1000) begin step(1); dump_latches(); end `endif $display("Run...."); /* Run CPU interface */ _spi_cs = 0; do_spi(`BB_WRITE | `BB_REG_CPU_BASE | 6, val); do_spi(8'h02, val); /* RUN */ _spi_cs = 1; #(SPI_HCLOCK*4); run_scsi(); `ifdef foo $display("Running to iwm_test1..."); run_to('h4010f0); dump_latches(); repeat(100) begin step(1); dump_latches(); end `endif `ifdef foo $display("Running to P_mBootBeep..."); run_to('h40028a); dump_latches(); step(1); dump_latches(); $display("Running to IWM init..."); run_to('h4000fc); dump_latches(); step(1); dump_latches(); $display("Running to P_ChecksumRomAndTestMemory..."); run_to('h400d76); dump_latches(); step(1); dump_latches(); $display("Running to P_BootPart2 (fake hit)..."); run_to('h400352); dump_latches(); step(1); dump_latches(); $display("Running to P_BootPart2..."); run_to('h400352); dump_latches(); step(1); dump_latches(); repeat(1000) begin step(1); dump_latches(); end `endif `ifdef __disabled__ /* Write memory from 0x201000 using mem SPI (ROM) */ $display("Loading ROM..."); rom_file = $fopenr("rom.bin"); rom_size = $fread(rom, rom_file, 0); $fclose(rom_file); _spi_cs = 0; do_spi(`BB_WRITE | `BB_AUTOINC | `BB_REG_MEM_BSAE, val); do_spi(8'h20, val); /* ROM base */ do_spi(8'h00, val); do_spi(8'h00, val); _spi_cs = 1; #(SPI_HCLOCK*4); _spi_cs = 0; do_spi(`BB_WRITE | `BB_REG_MEM_BASE | 3, val);/ i = 0; repeat(rom_size) begin do_spi(rom[i], val); i = i+1; if ((i % 1024) == 0) $display("%h", i); end _spi_cs = 1; #(SPI_HCLOCK*4); $display("RAM dump..."); $display("%h %h %h %h %h %h %h %h", sval[0], sval[1], sval[2], sval[3], sval[4], sval[5], sval[6], sval[7]); /* Start the scope */ _spi_cs = 0; do_spi(`BB_WRITE | `BB_REG_SCOPE_BASE, val); do_spi(8'h02, val); _spi_cs = 1; #(SPI_HCLOCK*4); /* Un-reset CPU */ _spi_cs = 0; do_spi(`BB_WRITE | `BB_REG_CTRL_BASE | 2, val); do_spi(8'h01, val); _spi_cs = 1; #(SPI_HCLOCK*4); /* Set breakpoint */ _spi_cs = 0; do_spi(`BB_WRITE | `BB_AUTOINC | `BB_REG_CPU_BASE | 8, val); do_spi(8'h00, val); do_spi(8'h10, val); do_spi(8'h22, val); _spi_cs = 1; #(SPI_HCLOCK*4); /* Run CPU interface */ _spi_cs = 0; do_spi(`BB_WRITE | `BB_REG_CPU_BASE | 6, val); do_spi(8'h42, val); /* RUN + BKEN */ _spi_cs = 1; #(SPI_HCLOCK*4); repeat(10) begin /* Get CPU status */ _spi_cs = 0; do_spi(`BB_WRITE | `BB_REG_CPU_BASE | 7, val); do_spi(8'hff, val); do_spi(8'hff, val); _spi_cs = 1; #(SPI_HCLOCK*4); $display("CPU Stat: %h", val); end `endif `ifdef foo $display("Steps:"); repeat(100) begin /* Step CPU interface */ _spi_cs = 0; do_spi(`BB_WRITE | `BB_REG_CPU_BASE | 6, val); do_spi(8'h82, val); /* RUN + STEP */ _spi_cs = 1; #(SPI_HCLOCK*4); /* We shall wait for cycle to complete but we know * how slow our SPI is ... */ /* Read latches */ _spi_cs = 0; do_spi(`BB_AUTOINC | `BB_REG_CPU_BASE, val); do_spi(8'hff, val); do_spi(8'hff, sval[0]); do_spi(8'hff, sval[1]); do_spi(8'hff, sval[2]); do_spi(8'hff, sval[3]); do_spi(8'hff, sval[4]); do_spi(8'hff, sval[5]); _spi_cs = 1; #(SPI_HCLOCK*4); $display("RW:%b U:%b L:%b ADDR: %h DATA: %h", sval[5][0], sval[5][1], sval[5][2], { sval[0], sval[1], sval[2] }, { sval[3], sval[4] }); end `endif `ifdef foo $display("Reading 0x1020 via SPI initiaed read cycle:"); /* Read value at 0x1020 */ _spi_cs = 0; do_spi(8'hc8, val); /* b001_000 */ do_spi(8'h00, val); do_spi(8'h10, val); do_spi(8'h20, val); do_spi(8'haa, val); do_spi(8'h55, val); do_spi(8'h01, val); /* _uds = 0, _lds = 0, r_w = 1 */ do_spi(8'h04, val); /* ctrl: cycle */ _spi_cs = 1; #(SPI_HCLOCK*4); /* Here too, shall wait but heh ! */ /* Read latches */ _spi_cs = 0; do_spi(8'h48, val); /* b001_000 */ do_spi(8'hff, val); do_spi(8'hff, sval[0]); do_spi(8'hff, sval[1]); do_spi(8'hff, sval[2]); do_spi(8'hff, sval[3]); do_spi(8'hff, sval[4]); do_spi(8'hff, sval[5]); _spi_cs = 1; #(SPI_HCLOCK*4); $display("RW:%b U:%b L:%b ADDR: %h DATA: %h", sval[5][0], sval[5][1], sval[5][2], { sval[0], sval[1], sval[2] }, { sval[3], sval[4] }); /* Read memory from 0x1000 using mem SPI */ _spi_cs = 0; do_spi(8'he0, val); /* b100_000 */ do_spi(8'h00, val); do_spi(8'h10, val); do_spi(8'h00, val); _spi_cs = 1; #(SPI_HCLOCK*4); _spi_cs = 0; do_spi(8'h23, val); /* b100_000 */ do_spi(8'hff, val); do_spi(8'hff, val); /* add. dummy cycle for reads */ do_spi(8'hff, sval[0]); do_spi(8'hff, sval[1]); do_spi(8'hff, sval[2]); do_spi(8'hff, sval[3]); do_spi(8'hff, sval[4]); do_spi(8'hff, sval[5]); do_spi(8'hff, sval[6]); do_spi(8'hff, sval[7]); _spi_cs = 1; #(SPI_HCLOCK*4); $display("RAM dump..."); $display("%h %h %h %h %h %h %h %h", sval[0], sval[1], sval[2], sval[3], sval[4], sval[5], sval[6], sval[7]); `endif `ifdef foo $display("Run...."); /* Run CPU interface */ _spi_cs = 0; do_spi(8'h8e, val); /* b001_110 */ do_spi(8'h02, val); /* RUN */ _spi_cs = 1; #(SPI_HCLOCK*4); `endif /* Wait a bit and stop the scope */ #4000000; `ifdef foo _spi_cs = 0; do_spi(`BB_WRITE | `BB_REG_SCOPE_BASE, val); do_spi(8'h00, val); _spi_cs = 1; #(SPI_HCLOCK*4); `endif `ifdef foo /* Dump scope output */ _spi_cs = 0; do_spi(8'h3c, val); do_spi(8'hff, val); i = 0; repeat(2048) begin do_spi(8'hff, sval[0]); do_spi(8'hff, sval[1]); do_spi(8'hff, sval[2]); do_spi(8'hff, sval[3]); do_spi(8'hff, sval[4]); do_spi(8'hff, sval[5]); do_spi(8'hff, sval[6]); do_spi(8'hff, sval[7]); $display("%h %h %h %h %h %h %h %h", sval[0], sval[1], sval[2], sval[3], sval[4], sval[5], sval[6], sval[7]); end _spi_cs = 1; #(SPI_HCLOCK*4); `endif end endmodule