From 30380f136e6af160619142255e9afdadce3bd4de Mon Sep 17 00:00:00 2001 From: brad Date: Sat, 10 Apr 2010 20:15:39 +0000 Subject: [PATCH] Added rf sector buffer --- rtl/ide.v | 99 ++++++++++++ rtl/ide_disk.v | 414 +++++++++++++++++++++++++++++++++++++++++++++++ rtl/pdp8_rf.v | 10 +- rtl/ram_256x12.v | 29 ++++ 4 files changed, 551 insertions(+), 1 deletion(-) create mode 100644 rtl/ide.v create mode 100644 rtl/ide_disk.v create mode 100644 rtl/ram_256x12.v diff --git a/rtl/ide.v b/rtl/ide.v new file mode 100644 index 0000000..43fc577 --- /dev/null +++ b/rtl/ide.v @@ -0,0 +1,99 @@ +// +// ide.v +// simple state machine to do proper read & write cycles to ATA IDE device +// + +module ide(clk, reset, ata_rd, ata_wr, ata_addr, ata_in, ata_out, ata_done, + ide_data_bus, ide_dior, ide_diow, ide_cs, ide_da); + + input clk; + input reset; + + input ata_rd; + input ata_wr; + input [4:0] ata_addr; + input [15:0] ata_in; + output [15:0] ata_out; + reg [15:0] ata_out; + output ata_done; + + inout [15:0] ide_data_bus; + output ide_dior; + output ide_diow; + output [1:0] ide_cs; + output [2:0] ide_da; + + + reg [2:0] ata_state; + + parameter [2:0] + idle = 3'd0, + s0 = 3'd1, + s1 = 3'd2, + s2 = 3'd3, + s3 = 3'd4, + s4 = 3'd5; + + wire assert_cs; + wire assert_rw; + + reg [2:0] ata_state_next; + + + // if write, drive ide_bus + assign ide_data_bus = (ata_wr && (ata_state == s0 || + ata_state == s1 || + ata_state == s2 || + ata_state == s3)) ? ata_in : 16'bz; + + // assert cs & da during r/w cycle + assign assert_cs = (ata_rd || ata_wr) && ata_state != s4; + + assign ide_cs = assert_cs ? ata_addr[4:3] : 2'b11; + assign ide_da = assert_cs ? ata_addr[2:0] : 3'b111; + + // assert r/w one cycle sort + assign assert_rw = ata_state == s0 || + ata_state == s1 || + ata_state == s2; + + assign ide_dior = (assert_rw && ata_rd) ? 1'b0 : 1'b1; + assign ide_diow = (assert_rw && ata_wr) ? 1'b0 : 1'b1; + + // send back done pulse at end + assign ata_done = ata_state == s3; + + always @(posedge clk) + if (reset) + ata_state <= idle; + else + ata_state <= ata_state_next; + + always @(clk or ata_state or ata_rd or ata_wr or ata_addr or ide_data_bus) + begin + case (ata_state) + idle: + begin + if (ata_rd || ata_wr) + ata_state_next = s0; + else + ata_state_next = idle; + end + + s0: ata_state_next = s1; + s1: ata_state_next = s2; + s2: ata_state_next = s3; + s3: ata_state_next = s4; + s4: ata_state_next = idle; + default: ata_state_next = idle; + endcase + end + + always @(posedge clk) + if (reset) + ata_out <= 0; + else + if (ata_state == s2 && ata_rd) + ata_out <= ide_data_bus; + +endmodule // ide diff --git a/rtl/ide_disk.v b/rtl/ide_disk.v new file mode 100644 index 0000000..0285de8 --- /dev/null +++ b/rtl/ide_disk.v @@ -0,0 +1,414 @@ +// +// ide_disk.v +// single block (512 byte/256 work) IDE disk read/write +// + +module ide_disk(clk, reset, + ide_lba, ide_read_req, ide_write_req, + ide_error, ide_done, + buffer_addr, buffer_rd, buffer_wr, + buffer_in, buffer_out); + + input clk; + input reset; + input [24:0] ide_lba; + input ide_read_req; + input ide_write_req; + + output ide_error; + output ide_done; + + output [7:0] buffer_addr; + output buffer_rd; + output buffer_wr; + output [11:0] buffer_in; + output [11:0] buffer_out; + + parameter [4:0] + ready = 5'd0, + init0 = 5'd1, + init1 = 5'd2, + init2 = 5'd3, + init3 = 5'd4, + init4 = 5'd5, + init5 = 5'd6, + init6 = 5'd7, + init7 = 5'd8, + init8 = 5'd9, + init9 = 5'd10, + init10 = 5'd11, + init11 = 5'd12, + read0 = 5'd13, + read1 = 5'd14, + write0 = 5'd15, + write1 = 5'd16, + last0 = 5'd17, + last1 = 5'd18, + last2 = 5'd19, + last3 = 5'd20, + wait0 = 5'd21, + wait1 = 5'd22; + + parameter ATA_ALTER = 5'b01110; + parameter ATA_DEVCTRL = 5'b01110; /* bit [2] is a nIEN */ + parameter ATA_DATA = 5'b10000; + parameter ATA_ERROR = 5'b10001; + parameter ATA_FEATURE = 5'b10001; + parameter ATA_SECCNT = 5'b10010; + parameter ATA_SECNUM = 5'b10011; /* LBA[7:0] */ + parameter ATA_CYLLOW = 5'b10100; /* LBA[15:8] */ + parameter ATA_CYLHIGH = 5'b10101; /* LBA[23:16] */ + parameter ATA_DRVHEAD = 5'b10110; /* LBA + DRV + LBA[27:24] */ + parameter ATA_STATUS = 5'b10111; + parameter ATA_COMMAND = 5'b10111; + + parameter IDE_STATUS_BSY = 7; + parameter IDE_STATUS_DRDY = 6; + parameter IDE_STATUS_DWF = 5; + parameter IDE_STATUS_DSC = 4; + parameter IDE_STATUS_DRQ = 3; + parameter IDE_STATUS_CORR = 2; + parameter IDE_STATUS_IDX = 1; + parameter IDE_STATUS_ERR = 0; + + parameter ATA_CMD_READ = 16'h0020; + parameter ATA_CMD_WRITE = 16'h0030; + + reg ata_rd; + reg ata_wr; + reg [4:0] ata_addr; + reg [15:0] ata_in; + wire [15:0] ata_out; + wire ata_done; + + inout [15:0] ide_data_bus; + output ide_dior; + output ide_diow; + output [1:0] ide_cs; + output [2:0] ide_da; + + reg [7:0] offset; + reg [7:0] wc; + + // + ide ide1(.clk(clk), .reset(reset), + .ata_rd(ata_rd), .ata_wr(ata_wr), .ata_addr(ata_addr), + .ata_in(ata_in), .ata_out(ata_out), .ata_done(ata_done), + .ide_data_bus(ide_data_bus), + .ide_dior(ide_dior), .ide_diow(ide_diow), + .ide_cs(ide_cs), .ide_da(ide_da)); + + // + wire [23:0] lba = ide_lba; + wire start = ide_read_req | ide_write_req; + + + // + alway @(posedge clk) + if (reset) + begin + err <= 1'b0; + done <= 1'b1; + offset <= 0; + wc <= 0; + end + else + begin + if (set_err) + err <= 1'b1; + else + if (clear_err) + err <= 1'b0; + + if (set_done) + done <= 1'b1; + else + if (clear_done) + done <= 1'b0; + + if (inc_offset) + begin + offset <= offset + 1; + wc <= wc + 1; + end + end + + // + // ide state machine + // + always @(posedge clk) + if (reset) + ide_state <= ready; + else + begin + ide_state <= ide_state_next; + end + + always @(ide_state or lba or start or + ata_done or ata_out or + dma_data_in or dma_ack) + begin + ide_state_next = ide_state; + + assert_int = 0; + + set_err = 0; + clear_err = 0; + + set_done = 0; + clear_done = 0; + + inc_offset = 0; + + ata_rd = 0; + ata_wr = 0; + ata_addr = 0; + ata_in = 0; + + buffer_rd = 0; + buffer_wr = 0; + buffer_addr = 0; + buffer_out = 0; + + case (ide_state) + ready: + begin + if (start) + begin + ide_state_next = init0; + $display("ide_disk: XXX go!"); + end + end + + init0: + begin + clear_done = 1; + ata_addr = ATA_STATUS; + ata_rd = 1; + if (ata_done && + ~ata_out[IDE_STATUS_BSY] && + ata_out[IDE_STATUS_DRDY]) + ide_state_next = init1; + end + + init1: + begin + ata_wr = 1; + ata_addr = ATA_DRVHEAD; + ata_in = 16'h0040; + if (ata_done) + ide_state_next = wait0; + end + + wait0: + begin + // cnt = 1; + // if (cnt_rdy) + ide_state_next = init2; + //$display("ide_disk: XXX wait0"); + end + + init2: + begin + ata_addr = ATA_STATUS; + ata_rd = 1; + if (ata_done && + ~ata_out[IDE_STATUS_BSY] && + ata_out[IDE_STATUS_DRDY]) + ide_state_next = init3; + end + + init3: + begin + ata_wr = 1; + ata_addr = ATA_DEVCTRL; + ata_in = 16'h0002; // nIEN + if (ata_done) + ide_state_next = init4; + end + + init4: + begin + ata_wr = 1; + ata_addr = ATA_SECCNT; + ata_in = { 8'b0, 8'd1 }; + if (ata_done) + ide_state_next = init5; + end + + init5: + begin + ata_wr = 1; + ata_addr = ATA_SECNUM; + ata_in = {8'b0, lba[7:0]}; // LBA[7:0] + if (ata_done) + ide_state_next = init6; + end + + init6: + begin + ata_wr = 1; + ata_addr = ATA_CYLLOW; + ata_in = {8'b0, lba[15:8]}; // LBA[15:8] + if (ata_done) + ide_state_next = init7; + end + + + init7: + begin + ata_wr = 1; + ata_addr = ATA_CYLHIGH; + ata_in = lba[23:16]; // LBA[23:16] + if (ata_done) + ide_state_next = init8; + end + + init8: + begin + ata_wr = 1; + ata_addr = ATA_DRVHEAD; + ata_in = 16'h0040; // LBA[27:24] + LBA + if (ata_done) + ide_state_next = init9; + end + + init9: + begin + ata_wr = 1; + ata_addr = ATA_COMMAND; + ata_in = ide_write_req ? ATA_CMD_WRITE : + ide_read_req ? ATA_CMD_READ : 16'b0; + if (ata_done) + ide_state_next = wait1; + end + + wait1: + begin +// cnt = 1; +// if (cnt_rdy) + ide_state_next = init10; + end + + init10: + begin + ata_rd = 1; + ata_addr = ATA_ALTER; + if (ata_done) + ide_state_next = init11; + end + + init11: + begin + ata_rd = 1; + ata_addr = ATA_STATUS; + + //if (ata_done) $display("ide_disk: XXX init11 ata_out %x", ata_out); + if (ata_done && + ~ata_out[IDE_STATUS_BSY] && + ata_out[IDE_STATUS_DRQ]) + begin + if (ide_write_req) + ide_state_next = write0; + else + if (ide_read_req) + ide_state_next = read0; + end + + if (ata_out[IDE_STATUS_ERR]) + set_err = 1; + end + + read0: + begin + ata_rd = 1; + ata_addr = ATA_DATA; + + if (ata_done) + begin + inc_offset = 1; + ide_state_next = read1; + end + end + + read1: + begin + //buffer write + buffer_addr = offset; + buffer_out = ata_out; + + if (0) $display("read1: XXX ata_out %o, buffer_addr %o", + ata_out, buffer_addr); + + buffer_wr = 1; + inc_offset = 1; + + if (wc == 16'h0000) + ide_state_next = last0; + else +// if (wc == 16'hff00) +// ide_state_next = init10; +// else + ide_state_next = read0; + end + + write0: + begin + //buffer read + buffer_addr = offset; + buffer_rd = 1; + + ata_in = dma_data_in; + inc_offset = 1; + ide_state_next = write1; + end + + write1: + begin + if (wc == 0) + ide_state_next = last0; + else +// if (wc == 16'hff00) +// ide_state_next = init10; +// else + ide_state_next = write0; + end + + last0: + begin + ata_rd = 1; + ata_addr = ATA_ALTER; + if (ata_done) + ide_state_next = last1; + end + + last1: + begin + ata_rd = 1; + ata_addr = ATA_STATUS; + if (ata_done) + ide_state_next = last2; + end + + last2: + begin + clear_err = 1; + set_done = 1; + ide_state_next = last3; + end + + last3: + begin + ide_state_next = ready; + $display("ide_disk: XXX last3, done"); + end + + default: + begin + end + + endcase + end + +endmodule + diff --git a/rtl/pdp8_rf.v b/rtl/pdp8_rf.v index b5de7ee..386dac0 100644 --- a/rtl/pdp8_rf.v +++ b/rtl/pdp8_rf.v @@ -290,7 +290,7 @@ will process the information. // read from ram DB_begin_xfer_write: ma_out = dma_addr - mb_out = buffer_out + buffer_hold <= ram_in ram_read_req = 1 if ram_done db_next_state = DB_check_xfer_write; @@ -454,6 +454,7 @@ module pdp8_rf(clk, reset, iot, state, mb, reg buffer_dirty; reg [11:0] buffer_hold; + wire [11:0] buffer_out; wire buffer_matches_DMA; wire buffer_rd; @@ -474,6 +475,13 @@ module pdp8_rf(clk, reset, iot, state, mb, assign buffer_addr = disk_addr[7:0]; assign ide_done = 1; + + // ide sector buffer + ram_256x12 buffer(.A(buffer_addr), + .DI(buffer_hold), + .DO(buffer_out), + .CE_N(1'b0), + .WE_N(~buffer_wr)); // combinatorial always @(state or diff --git a/rtl/ram_256x12.v b/rtl/ram_256x12.v new file mode 100644 index 0000000..e6786ae --- /dev/null +++ b/rtl/ram_256x12.v @@ -0,0 +1,29 @@ +/* 256x12 static ram */ +module ram_256x12(A, DI, DO, CE_N, WE_N); + + input[14:0] A; + input [11:0] DI; + input CE_N, WE_N; + output [11:0] DO; + + reg [11:0] ram [0:255]; + integer i; + + initial + begin + for (i = 0; i < 256; i=i+1) + ram[i] = 12'b0; + end + + always @(WE_N or CE_N or A or DI) + begin + if (WE_N == 0 && CE_N == 0) + begin + ram[ A ] = DI; + end + end + + assign DO = ram[ A ]; + +endmodule +