MacPlus_MiSTer/rtl/floppy_track_encoder.v

370 lines
11 KiB
Verilog

/*
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