/* floppy_track_encoder.v encode a full floppy track from raw sector data on the fly */ /* verilator lint_off UNUSED */ /* verilator lint_off UNDRIVEN */ /* verilator lint_off CASEINCOMPLETE */ module floppy_track_encoder ( // system signals input clk, // clock at which data bytes are delivered via odata input ready, input rst, input side, input sides, input [6:0] track, // current track output reg [21:0] addr, // address to fetch from input [7:0] idata, output [7:0] odata ); always @(posedge clk) begin addr <= { 3'b00, soff, 9'd0 } + // sector offset * 512 for two sides (sides?{ 3'b00, soff, 9'd0 }:22'd0) + // another sector offset * 512 for two sides (side?{ 9'd0, spt, 9'd0 }:22'd0) + // side * sectors * 512 { 9'd0, sector, src_offset }; // offset within track end // number of sectors on current track wire [3:0] spt = (track[6:4] == 3'd0)?4'd12: // track 0 - 15 (track[6:4] == 3'd1)?4'd11: // track 16 - 31 (track[6:4] == 3'd2)?4'd10: // track 32 - 47 (track[6:4] == 3'd3)?4'd9: // track 48 - 63 4'd8; // track 64 - ... // all possible tack*sector factors wire [9:0] track_times_12 = // x*12 = x*8 + x*4 { track, 3'b000 } + // x<<3 + { 1'b0, track, 2'b00 }; // x<<2 wire [9:0] track_times_11 = // x*11 = x*8 + x*2 + x*1 { track, 3'b000 } + // x<<3 + { 2'b00, track, 1'b0 } + // x<<1 + { 3'b000, track }; // x<<0 wire [9:0] track_times_10 = // x*10 = x*8 + x*2 { track, 3'b000 } + // x<<3 + { 2'b00, track, 1'b0 }; // x<<1 wire [9:0] track_times_9 = // x*9 = x*8 + x*1 { track, 3'b000 } + // x<<3 + { 3'b000, track }; // x<<0 wire [9:0] track_times_8 = // x*8 { track, 3'b000 }; // x<<3 // sector offset of current track is the sum of all sectors on all tracks before wire [6:0] trackm1 = track - 7'd1; wire [9:0] soff = (track == 0)?10'd0: // track 0 (trackm1[6:4] == 3'd0)?track_times_12: // track 1 - 16 (trackm1[6:4] == 3'd1)?(track_times_11 + 10'd16): // track 17 - 32 (trackm1[6:4] == 3'd2)?(track_times_10 + 10'd32 + 10'd16): // track 33 - 48 (trackm1[6:4] == 3'd3)?(track_times_9 + 10'd48 + 10'd32 + 10'd16): // track 49 - 64 (track_times_8 + 10'd64 + 10'd48 + 10'd32 + 10'd16); // track 65 - // parts of an address block wire [5:0] sec_in_tr = {2'b00, sector}; wire [5:0] track_low = track[5:0]; wire [5:0] track_hi = { side, 4'b0000, track[6] }; wire [5:0] format = { sides, 5'h2 }; // double sided = 22, single sided = 2 wire [5:0] checksum = track_low ^ sec_in_tr ^ track_hi ^ format; // data input to the sony encoder during address block wire [5:0] sony_addr_in = (count == 3)?track_low: (count == 4)?sec_in_tr: (count == 5)?track_hi: (count == 6)?format: checksum; // data input to the sony encoder during data header wire [5:0] sony_dhdr_in = sec_in_tr; wire [5:0] sony_dsum_in = (count == 0)?{ c3[7:6], c2[7:6], c1[7:6] }: (count == 1)?c3[5:0]: (count == 2)?c2[5:0]: c1[5:0]; // feed data into sony encoder wire [5:0] si = (state == STATE_ADDR)?sony_addr_in: (state == STATE_DHDR)?sony_dhdr_in: (state == STATE_DZRO)?nib_out: (state == STATE_DPRE)?nib_out: (state == STATE_DATA)?nib_out: (state == STATE_DSUM)?sony_dsum_in: 6'h3f; // encoder table taken from MESS emulator wire [7:0] sony_to_disk_byte = (si==6'h00)?8'h96:(si==6'h01)?8'h97:(si==6'h02)?8'h9a:(si==6'h03)?8'h9b: // 0x00 (si==6'h04)?8'h9d:(si==6'h05)?8'h9e:(si==6'h06)?8'h9f:(si==6'h07)?8'ha6: (si==6'h08)?8'ha7:(si==6'h09)?8'hab:(si==6'h0a)?8'hac:(si==6'h0b)?8'had: (si==6'h0c)?8'hae:(si==6'h0d)?8'haf:(si==6'h0e)?8'hb2:(si==6'h0f)?8'hb3: (si==6'h10)?8'hb4:(si==6'h11)?8'hb5:(si==6'h12)?8'hb6:(si==6'h13)?8'hb7: // 0x10 (si==6'h14)?8'hb9:(si==6'h15)?8'hba:(si==6'h16)?8'hbb:(si==6'h17)?8'hbc: (si==6'h18)?8'hbd:(si==6'h19)?8'hbe:(si==6'h1a)?8'hbf:(si==6'h1b)?8'hcb: (si==6'h1c)?8'hcd:(si==6'h1d)?8'hce:(si==6'h1e)?8'hcf:(si==6'h1f)?8'hd3: (si==6'h20)?8'hd6:(si==6'h21)?8'hd7:(si==6'h22)?8'hd9:(si==6'h23)?8'hda: // 0x20 (si==6'h24)?8'hdb:(si==6'h25)?8'hdc:(si==6'h26)?8'hdd:(si==6'h27)?8'hde: (si==6'h28)?8'hdf:(si==6'h29)?8'he5:(si==6'h2a)?8'he6:(si==6'h2b)?8'he7: (si==6'h2c)?8'he9:(si==6'h2d)?8'hea:(si==6'h2e)?8'heb:(si==6'h2f)?8'hec: (si==6'h30)?8'hed:(si==6'h31)?8'hee:(si==6'h32)?8'hef:(si==6'h33)?8'hf2: // 0x30 (si==6'h34)?8'hf3:(si==6'h35)?8'hf4:(si==6'h36)?8'hf5:(si==6'h37)?8'hf6: (si==6'h38)?8'hf7:(si==6'h39)?8'hf9:(si==6'h3a)?8'hfa:(si==6'h3b)?8'hfb: (si==6'h3c)?8'hfc:(si==6'h3d)?8'hfd:(si==6'h3e)?8'hfe: 8'hff; // states of encoder state machine localparam STATE_SYN0 = 4'd0; // 56 bytes sync pattern (0xff) localparam STATE_ADDR = 4'd1; // 10 bytes address block localparam STATE_SYN1 = 4'd2; // 5 bytes sync pattern (0xff) localparam STATE_DHDR = 4'd3; // 4 bytes data block header localparam STATE_DZRO = 4'd4; // 8 encoded zero bytes in data block localparam STATE_DPRE = 4'd5; // 4 bytes data prefetch localparam STATE_DATA = 4'd6; // the payload itself localparam STATE_DSUM = 4'd7; // 4 bytes data checksum localparam STATE_DTRL = 4'd8; // 3 bytes data block trailer localparam STATE_WAIT = 4'd15; // wait until start of next sector // output data during address block wire [7:0] odata_addr = (count == 0)?8'hd5: (count == 1)?8'haa: (count == 2)?8'h96: (count == 8)?8'hde: (count == 9)?8'haa: sony_to_disk_byte; wire [7:0] odata_dhdr = (count == 0)?8'hd5: (count == 1)?8'haa: (count == 2)?8'had: sony_to_disk_byte; wire [7:0] odata_dtrl = (count == 0)?8'hde: (count == 1)?8'haa: 8'hff; // demultiplex output data assign odata = (state == STATE_ADDR)?odata_addr: (state == STATE_DHDR)?odata_dhdr: (state == STATE_DZRO)?sony_to_disk_byte: (state == STATE_DPRE)?sony_to_disk_byte: (state == STATE_DATA)?sony_to_disk_byte: (state == STATE_DSUM)?sony_to_disk_byte: (state == STATE_DTRL)?odata_dtrl: 8'hff; // ------------------------ nibbler ---------------------------- reg [7:0] c1; reg [7:0] c2; reg c2x; reg [7:0] c3; reg c3x; wire nibbler_reset = (state == STATE_DHDR); reg [1:0] cnt; reg [7:0] nib_xor_0; reg [7:0] nib_xor_1; reg [7:0] nib_xor_2; // request an input byte. this happens 4 byte ahead of output. // only three bytes are read while four bytes are written due // to 6:2 encoding wire strobe = ((state == STATE_DPRE) || ((state == STATE_DATA) && (count < 683-4-1))) && (cnt != 3); reg [7:0] data_latch; always @(posedge clk) if(ready && strobe) data_latch <= idata; always @(posedge clk or posedge nibbler_reset) begin if(nibbler_reset) begin c1 <= 8'h00; c2 <= 8'h00; c2x <= 1'b0; c3 <= 8'h00; c3x <= 1'b0; cnt <= 2'd0; nib_xor_0 <= 8'h00; nib_xor_1 <= 8'h00; nib_xor_2 <= 8'h00; end else if(ready && ((state == STATE_DPRE) || (state == STATE_DATA))) begin cnt <= cnt + 2'd1; // memory read during cnt 0-3 if(count < 683-4) begin // encode first byte if(cnt == 1) begin c1 <= { c1[6:0], c1[7] }; { c3x, c3 } <= { 1'b0, c3 } + { 1'b0, nib_in } + { 8'd0, c1[7] }; nib_xor_0 <= nib_in ^ { c1[6:0], c1[7] }; end // encode second byte if(cnt == 2) begin { c2x, c2 } <= { 1'b0, c2 } + { 1'b0, nib_in } + { 8'd0, c3x }; c3x <= 1'b0; nib_xor_1 <= nib_in ^ c3; end // encode third byte if(cnt == 3) begin c1 <= c1 + nib_in + { 7'd0, c2x }; c2x <= 1'b0; nib_xor_2 <= nib_in ^ c2; end end else begin // since there are 512/3 = 170 2/3 three byte blocks in a sector the // last run has to be filled up with zeros if(cnt == 3) nib_xor_2 <= 8'h00; end end end // bytes going into the nibbler wire [7:0] nib_in = (state == STATE_DZRO)?8'h00: data_latch; // four six bit units come out of the nibbler wire [5:0] nib_out = (cnt == 1)?nib_xor_0[5:0]: (cnt == 2)?nib_xor_1[5:0]: (cnt == 3)?nib_xor_2[5:0]: { nib_xor_0[7:6], nib_xor_1[7:6], nib_xor_2[7:6] }; // count bytes per sector reg [3:0] state; reg [9:0] count; reg [3:0] sector; reg [8:0] src_offset; always @(posedge clk or posedge rst) begin if(rst) begin count <= 10'd0; state <= STATE_SYN0; sector <= 4'd0; src_offset <= 9'd0; end else if(ready) begin count <= count + 10'd1; if(strobe) src_offset <= src_offset + 9'd1; case(state) // send 14*4=56 sync bytes STATE_SYN0: begin if(count == 55) begin state <= STATE_ADDR; count <= 10'd0; end end // send 10 bytes address block STATE_ADDR: begin if(count == 9) begin state <= STATE_SYN1; count <= 10'd0; end end // send 5 sync bytes STATE_SYN1: begin if(count == 4) begin state <= STATE_DHDR; count <= 10'd0; end end // send 4 bytes data block hdr STATE_DHDR: begin if(count == 3) begin state <= STATE_DZRO; count <= 10'd0; end end // send 8 zero bytes before data block STATE_DZRO: begin if(count == 11) begin state <= STATE_DPRE; count <= 10'd0; end end // start prefetching 4 bytes data STATE_DPRE: begin if(count == 3) begin state <= STATE_DATA; count <= 10'd0; end end // send 512 bytes data block 6:2 encoded in 683 bytes STATE_DATA: begin if(count == 682) begin state <= STATE_DSUM; count <= 10'd0; end end // send 4 bytes data checksum STATE_DSUM: begin if(count == 3) begin state <= STATE_DTRL; count <= 10'd0; end end // send 3 bytes data block trailer STATE_DTRL: begin if(count == 2) begin state <= STATE_WAIT; count <= 10'd0; end end // fill sector up to 1024 bytes STATE_WAIT: begin // if(count == 1023-56-10-5-4-12-4-683-4-3) begin count <= 10'd0; state <= STATE_SYN0; src_offset <= 9'd0; // interleave of 1 // if(sector != spt-4'd1) sector <= sector + 4'd1; // else sector <= 4'd0; // interleave of 2 if((sector == spt-4'd2) || (sector == spt-4'd1)) sector <= { 3'd0, !sector[0] }; else sector <= sector + 4'd2; end end endcase end end endmodule