Idea: Propeddle with the P1V and a 6502 Softcore
Hi,
I stumbled upon the Propeddle Project from jacgoudsmit and maybe it would be cool to port it to pure
FPGA? Buffers, 128K RAM, P1V, 6502 (T65 Core) and Octal D Flipflop can all be done in the FPGA (e.g.
on the BeMicroCVs Cyclone V).
@jacgoudsmith: What do you think?
I stumbled upon the Propeddle Project from jacgoudsmit and maybe it would be cool to port it to pure
FPGA? Buffers, 128K RAM, P1V, 6502 (T65 Core) and Octal D Flipflop can all be done in the FPGA (e.g.
on the BeMicroCVs Cyclone V).
@jacgoudsmith: What do you think?

Comments
I cannot find a Propeddle schematic in readable format (pdf...) - so I don't know in details how are they connected i it.
Here you go: https://github.com/jacgoudsmit/Propeddle/blob/master/Hardware/Kicad/Plot/Schematic.pdf?raw=true
A unquie concept that opens up a world of possibilities! It begs the question,
what other processes can be masked on the FPGA?
on the FPGA? Just a thought..........:)
Of course I've thought about this but let's think about this for a minute.
First of all, with the P1V code, the Cyclone 5 that's on the BeMicro CV is almost full. Adding a soft-core 6502 to the P1V certainly wouldn't fit in the FPGA. You would need a bigger FPGA such as the on on the DE2-115.
On the Propeddle, the Propeller is intended as an easy-to-program emulator for the peripherals that would normally be in a 6502 computer. Because of the 8 cogs and the large amount of available software in OBEX, it's relatively easy to emulate an Apple 1 and it should be pretty easy to emulate simple 6502 systems such as KIM-1, SYM, PET-2001, OSI etc, or to create your own 6502 system using Spin or PASM or C or C++. For many hobbyists, this makes it possible to put the kit together and make it do something useful. But the Propeller can "only" do 8 things at once, at a speed that's relatively slow because everything has to happen sequentially with PASM instructions. The Apple 1 emulator uses 4 cogs and it has almost not hardware that's (emulated to be) directly connected to the 6502.
An FPGA can do a much better job of emulating hardware, including complicated things such as video. The big advantage of an FPGA is that it basically does everything at the same time, just like normal digital electronics.
So, if you want to emulate a 6502 system with all its peripherals, it makes much more sense to just put the 6502 softcore in the FPGA and emulate the peripherals with Verilog directly. It will take a lot less resources than emulating a Propeller and a 6502 but of course not everyone knows Verilog.
And of course this has been done before: on the 6502.org forums and website, there are several people who used an FPGA to emulate old systems and implement new systems.
===Jac
I agree with that, but I was thinking about a 6 core P1V as it seems to give enough space for the 6502 and the "glue logic".
By the way - I ported this to the BeMicro and currently working on some 6502/6510 code + MOS6581, so we have a stand-alone
sid player: https://git.no-route.org/syso/bemicro-cv-multicomp
Having a soft 6502 core will enable a POKEY/SID players which can play not only SID dumps but real sid files.
Then, of course, SD and Basic.
I was Atari 8-bit user so all my work is inspired by this machine.The pallette I made for my "mode 2" is Atari 8-bit like. The difference is - this is 448x280 @ 256 colors instead 320x200 @ 2 colors. Or... 1792x1120 @ 4 colors. With switching pallette banks and sprites added it can make a new level of retrocomputing.
And.. adding a 6502 core to the system may enable Atari 8-bit software to run...
Do you already have your code at Git? If not, would be cool if you could maintain it at GitHub (or if you want something
different, I can set it up at my GitLab server)
/** * Buffered SD-Driver * Data is transferred from-to a 512 bytes buffer for easy/simple access * * (c) Alejandro Paz Schmidt, distributed under the terms of the MIT license */ module sd_driver( input wire clk_in, // sd interface output wire sd_clk, output wire sd_cs_n, output wire sd_data_o, input wire sd_data_in, // cpu interface input wire cpu_clk_in, // memory read/write clock `ifdef ALTERA_CV input wire [8:0] cpu_addr_in, `else input wire [10:0] cpu_addr_in, `endif input wire cpu_oe_in, input wire cpu_we_in, `ifdef ALTERA_CV input wire [31:0] cpu_data_in, output wire [31:0] cpu_data_o, `else input wire [7:0] cpu_data_in, output wire [7:0] cpu_data_o, `endif output wire wled_o, // activity led write output wire rled_o // activity led read ); parameter ST_RESET = 0; parameter ST_WAIT_FOR_CMD = 1; parameter ST_ACK_CMD_RECEIVE = 2; parameter ST_ACK_CMD_TRANSMIT = 3; parameter ST_TRANSFER = 4; parameter ST_TRANSFER_START = 5; parameter ST_SEND_BITS = 6; parameter ST_SEND_BITS_END = 7; `ifdef ALTERA_CV parameter BUFFER_BIT = 7; // bit of the address that determines which buffer is being written/read parameter DATA_BIT = 8; // 0 means control register, 1 means data buffers parameter DATA_BUS_WIDTH = 32; `else parameter BUFFER_BIT = 9; // bit of the address that determines which buffer is being written/read parameter DATA_BIT = 10; // 0 means control register, 1 means data buffers parameter DATA_BUS_WIDTH = 8; `endif // ctrl reg 0 parameter CMD_RECV_BIT = 7; parameter CMD_SEND_BIT = 6; parameter CMD_CS_BEG_BIT = 5; parameter CMD_CS_END_BIT = 4; parameter CMD_USE_CRC = 3; // ctrl reg 2 parameter CMD_BUFF_BIT = 7; parameter CMD_FULL_PAGE = 6; reg [7:0] sd_cmd_reg_0, sd_cmd_reg_1, sd_cmd_reg_2; reg [2:0] sd_state; reg [8:0] sd_tfr_size; reg [3:0] sd_bit; reg [8:0] sd_buff_addr; reg sd_buffer; // asserted when data buffer reg sd_inhibit_sdo; // when asserted sends '0' to the SD card, used for sending commands reg sd_inhibit_write; // when asserted inhibits writes to the buffer from the card side reg [7:0] sd_shift_reg_in, sd_shift_reg_o; reg sd_mem_write; reg [2:0] sd_bit_cnt; reg sd_cs; reg [7:0] crc7; reg [7:0] latched_data; reg sd_cmd_acknowledged; // asserted when a command is in progress, inhibits writes to the command register reg sd_cmd_reg_dirty; // command register dirty, needs processing wire [7:0] sd_mem_in, sd_mem_o; wire [7:0] new_crc_7, xor_data_crc, new_crc_0, new_crc_1, new_crc_2, new_crc_3, new_crc_4; wire [7:0] new_crc_5, new_crc_6; wire [DATA_BUS_WIDTH-1:0] cpu_data_from_buffer; // command register 0 // 7 receive bytes from card // 6 send to card from buffer // 5 CS status at the begin of the transmission // 4 CS status at the end of the transaction // 3 use crc instead of last byte of command // 2..0 not used // command register 1 // 7..0 not yet used // // // // // // command register 2, transfer size // 7 buffer 0 or 1 // 6 full page transfer // 5..0 size in bytes + 1 // command register 3 clear crc register assign sd_data_o = sd_inhibit_sdo ? 1'b0:sd_shift_reg_o[7]; assign sd_clk = (sd_inhibit_sdo ? /* normal clock */ clk_in:!clk_in) & (sd_state == ST_SEND_BITS); assign sd_cs_n = sd_cs; `ifdef ALTERA_CV assign cpu_data_o = (cpu_oe_in & (!cpu_addr_in[DATA_BIT])) ? { cpu_addr_in, 15'h0, sd_cmd_acknowledged }:cpu_data_from_buffer; `else assign cpu_data_o = (cpu_oe_in & (!cpu_addr_in[DATA_BIT])) ? { 7'h0, sd_cmd_acknowledged }:cpu_data_from_buffer; `endif assign rled_o = !sd_cs_n & sd_inhibit_sdo; assign wled_o = !sd_cs_n & !sd_inhibit_sdo; assign new_crc_7 = ( cpu_data_in[7] ^ crc7[6]) ? { crc7[6:0], 1'b0 }^8'h09:{ crc7[6:0], 1'b0 }; assign new_crc_6 = ( cpu_data_in[6] ^ new_crc_7[5]) ? { new_crc_7[6:0], 1'b0 }^8'h09:{ new_crc_7[6:0], 1'b0 }; assign new_crc_5 = ( cpu_data_in[5] ^ new_crc_6[4]) ? { new_crc_6[6:0], 1'b0 }^8'h09:{ new_crc_6[6:0], 1'b0 }; assign new_crc_4 = ( cpu_data_in[4] ^ new_crc_5[3]) ? { new_crc_5[6:0], 1'b0 }^8'h09:{ new_crc_5[6:0], 1'b0 }; assign new_crc_3 = ( cpu_data_in[3] ^ new_crc_4[2]) ? { new_crc_4[6:0], 1'b0 }^8'h09:{ new_crc_4[6:0], 1'b0 }; assign new_crc_2 = ( cpu_data_in[2] ^ new_crc_3[1]) ? { new_crc_3[6:0], 1'b0 }^8'h09:{ new_crc_3[6:0], 1'b0 }; assign new_crc_1 = ( cpu_data_in[1] ^ new_crc_2[0]) ? { new_crc_2[6:0], 1'b0 }^8'h09:{ new_crc_2[6:0], 1'b0 }; assign new_crc_0 = ( cpu_data_in[0] ) ? { new_crc_1[6:0], 1'b0 }^8'h09:{ new_crc_1[6:0], 1'b0 }; `ifdef SIMULATOR ram_dp_1k ram_1k( .clka(clk_in), .addra( { sd_buffer, sd_buff_addr[8:0] }), .writea(sd_mem_write), .reada(1'b1), .dataa(sd_shift_reg_in), .qa(sd_mem_o), .clkb(cpu_clk_in), .addrb(cpu_addr_in[9:0]), .writeb(cpu_we_in & cpu_addr_in[DATA_BIT]), .readb(cpu_oe_in & cpu_addr_in[DATA_BIT]), .datab(cpu_data_in), .qb(cpu_data_from_buffer) ); `else `ifdef ALTERA_CV wire [31:0] sd_mem_data; spi_buffer ram_1k( .address_a( { sd_buffer, sd_buff_addr[8:2] }), .data_a( { sd_shift_reg_in, sd_shift_reg_in, sd_shift_reg_in, sd_shift_reg_in } ), .wren_a(sd_mem_write), .byteena_a(sd_buff_addr[1:0] == 2'h0 ? 4'b0001: sd_buff_addr[1:0] == 2'h1 ? 4'b0010: sd_buff_addr[1:0] == 2'h2 ? 4'b0100:4'b1000), .clock_a(clk_in), .q_a(sd_mem_data), .clock_b(cpu_clk_in), .address_b(cpu_addr_in[7:0]), .data_b(cpu_data_in), .wren_b(cpu_we_in & cpu_addr_in[DATA_BIT]), .byteena_b(4'hf), .q_b(cpu_data_from_buffer)); assign sd_mem_o = sd_buff_addr[1:0] == 2'h0 ? sd_mem_data[7:0]: sd_buff_addr[1:0] == 2'h1 ? sd_mem_data[15:8]: sd_buff_addr[1:0] == 2'h2 ? sd_mem_data[23:16]:sd_mem_data[31:24]; `else // Lattice True dual ported memory 1 Kbytes 8 bits spi_buffer ram_1k( .DataInA(sd_shift_reg_in), .AddressA( { sd_buffer, sd_buff_addr[8:0] }), .ClockA(clk_in), .ClockEnA(1'b1), .WrA(sd_mem_write), .ResetA(1'b0), .QA(sd_mem_o), .DataInB(cpu_data_in), .AddressB(cpu_addr_in[9:0]), .ClockB(cpu_clk_in), .ClockEnB(1'b1), .WrB(cpu_we_in & cpu_addr_in[DATA_BIT]), .ResetB(1'b0), .QB(cpu_data_from_buffer) ); `endif // ALTERA_CV `endif always @(posedge clk_in) begin if (cpu_we_in) begin if (cpu_addr_in[DATA_BIT]) // write to control register begin crc7 <= new_crc_0; // save last crc latched_data <= cpu_addr_in; // recalculates crc end else case (cpu_addr_in[1:0]) 2'h0: if ((!sd_cmd_acknowledged) && (!sd_cmd_reg_dirty)) begin sd_cmd_reg_0 <= cpu_data_in; sd_cmd_reg_dirty <= 1'b1; end 2'h1: begin sd_cmd_reg_1 <= cpu_data_in; end 2'h2: // transfer size begin sd_cmd_reg_2 <= cpu_data_in; end 2'h3: crc7 <= 8'h0; // clear crc register endcase end if (sd_cmd_acknowledged && sd_cmd_reg_dirty) begin sd_cmd_reg_dirty <= 1'b0; end end /* SD state machine */ always @(posedge clk_in) begin case (sd_state) ST_RESET: begin sd_cs <= 1'b1; sd_state <= ST_WAIT_FOR_CMD; end ST_WAIT_FOR_CMD: begin if (sd_cmd_reg_dirty && (!sd_cmd_acknowledged)) begin if (sd_cmd_reg_0[CMD_RECV_BIT]) begin sd_state <= ST_ACK_CMD_RECEIVE; sd_cmd_acknowledged <= 1'b1; end else if (sd_cmd_reg_0[CMD_SEND_BIT]) begin sd_state <= ST_ACK_CMD_TRANSMIT; sd_cmd_acknowledged <= 1'b1; end end end ST_ACK_CMD_RECEIVE: // receive begin sd_buff_addr <= 9'h0; sd_inhibit_sdo <= 1'b1; sd_inhibit_write <= 1'b0; sd_buffer <= sd_cmd_reg_2[CMD_BUFF_BIT]; // buffer selection if (sd_cmd_reg_2[CMD_FULL_PAGE]) // full page ? sd_tfr_size <= 9'h1ff; else sd_tfr_size <= { 3'h0, sd_cmd_reg_2[5:0] }; sd_state <= ST_TRANSFER; sd_cs <= sd_cmd_reg_0[CMD_CS_BEG_BIT]; end ST_ACK_CMD_TRANSMIT: begin sd_buff_addr <= 9'h0; sd_inhibit_write <= 1'b1; sd_inhibit_sdo <= 1'b0; sd_buffer <= sd_cmd_reg_2[CMD_BUFF_BIT]; // buffer selection if (sd_cmd_reg_2[CMD_FULL_PAGE]) // full page ? sd_tfr_size <= 9'h1ff; else sd_tfr_size <= { 3'h0, sd_cmd_reg_2[5:0] }; sd_state <= ST_TRANSFER; sd_cs <= sd_cmd_reg_0[CMD_CS_BEG_BIT]; end ST_TRANSFER: // memory read start begin sd_state <= ST_TRANSFER_START; end ST_TRANSFER_START: begin if (sd_cmd_reg_0[CMD_USE_CRC] && (sd_tfr_size == 'h0)) sd_shift_reg_o <= crc7[6:0] | 1'b1; // uses CRC7 as last command byte else sd_shift_reg_o <= sd_mem_o; sd_bit_cnt <= 3'd7; sd_state <= ST_SEND_BITS; sd_mem_write <= 1'b0; end ST_SEND_BITS: begin sd_shift_reg_o <= sd_shift_reg_o << 1; sd_shift_reg_in <= (sd_shift_reg_in << 1) | sd_data_in; // data capture happens one clock after sd_clk if (sd_bit_cnt) begin sd_bit_cnt <= sd_bit_cnt - 8'd1; end else begin sd_state <= ST_SEND_BITS_END; if (sd_inhibit_write) // only for transmit sd_buff_addr <= sd_buff_addr + 9'd1; end end ST_SEND_BITS_END: begin if (sd_tfr_size) begin sd_tfr_size <= sd_tfr_size - 9'd1; sd_state <= ST_TRANSFER_START; end else begin sd_state <= ST_WAIT_FOR_CMD; sd_cmd_acknowledged <= 1'b0; sd_cs <= sd_cmd_reg_0[CMD_CS_END_BIT]; // to chain commands end if (!sd_inhibit_write) begin sd_mem_write <= 1'b1; sd_buff_addr <= sd_buff_addr + 9'd1; end end endcase end initial begin sd_state = 0; sd_cmd_acknowledged = 0; sd_cmd_reg_dirty = 0; crc7 = 0; end endmodule `ifdef SIMULATOR // double port memory module ram_dp_1k( input wire clka, input wire [9:0] addra, input wire writea, input wire reada, input wire [7:0] dataa, output reg [7:0] qa, input wire clkb, input wire [9:0] addrb, input wire writeb, input wire readb, input wire [7:0] datab, output reg [7:0] qb ); reg [7:0] mem[1023:0]; always @(posedge clka) begin if (writea) mem[addra] <= dataa; qa <= mem[addra]; end always @(posedge clkb) begin if (writeb) mem[addrb] <= datab; qb <= mem[addrb]; end endmodule `endifA testbench is here:
module tb_sd_card(); reg sd_clk, cpu_clk; reg [10:0] cpu_addr; reg [7:0] cpu_data_o; reg cpu_we; reg cpu_oe; reg sd_data_to_driver; wire wled, rled; sd_driver drv( .clk_in(sd_clk), // sd interface .sd_clk(), .sd_cs_n(), .sd_data_o(), .sd_data_in(sd_data_to_driver), // cpu interface .cpu_clk_in(cpu_clk), // memory read/write clock .cpu_addr_in(cpu_addr), .cpu_oe_in(cpu_oe), .cpu_we_in(cpu_we), .cpu_data_in(cpu_data_o), .cpu_data_o(), .wled_o(wled), // activity led write .rled_o(rled) // activity led read ); always #25 sd_clk = ~ sd_clk; // 20 MHz clock always #16.67 cpu_clk = ~cpu_clk; // almost 33 MHz clock initial begin $dumpvars; sd_clk = 0; cpu_clk = 1; cpu_addr = 0; cpu_oe = 0; cpu_we = 0; sd_data_to_driver = 0; // ask status #100 cpu_addr = 0; cpu_oe = 1; #49 cpu_oe = 0; // memory write test #100 cpu_addr = 'h400; cpu_data_o = 8'h40; cpu_we = 1; #49 cpu_we = 0; #100 cpu_addr = 'h401; cpu_data_o = 8'h00; cpu_we = 1; #49 cpu_we = 0; #100 cpu_addr = 'h402; cpu_data_o = 8'h00; cpu_we = 1; #49 cpu_we = 0; #100 cpu_addr = 'h403; cpu_data_o = 8'h00; cpu_we = 1; #49 cpu_we = 0; #100 cpu_addr = 'h404; cpu_data_o = 8'h00; cpu_we = 1; #49 cpu_we = 0; #100 // transfer size... cpu_data_o = 8'b0_0_000101; // 5 bytes from lower buffer to sd card cpu_addr = 'h002; cpu_we = 1; #49 cpu_we = 0; #50 // transfer CS should remain low after end of command cpu_data_o = 8'b0_1_0_0_1_000; // CS low all the time, use CRC as last byte cpu_addr = 'h000; cpu_we = 1; #49 cpu_we = 0; // ask status #100 cpu_addr = 0; cpu_oe = 1; #49 cpu_oe = 0; #2000 // ask status #100 cpu_addr = 0; cpu_oe = 1; #49 cpu_oe = 0; #100 #2000 $finish; end endmodulerun it from a script like:
The path thing is needed in case some dll breaks iverilog, who knows which one ... I love dll hell
module sd1(clk,rst,sclk,miso,mosi,cs,st,addr,secnum,datain,dataout,stb,wr,rd,ready,err,debug); //Piotr Kardasz pik33@o2.pl //free code - gpl 2.0 or higher input wire clk; input wire rst; output reg sclk; output reg mosi; output reg cs; input wire miso; input wire [6:0] addr; input wire [31:0] secnum; input wire stb; // write strobe input wire wr; // start sector write input wire rd; // start sector read input wire [31:0] datain; output reg [31:0] dataout; output reg ready; output reg err; output reg [7:0] st; output reg[7:0] debug; reg [7:0] wordcnt; reg [31:0] writebuf[128]; reg [31:0] readbuf[128]; reg[15:0] cnt; reg[4:0] state; reg slowspiclk; reg fastspiclk; reg oldrst; reg oldstb; reg oldwr; reg oldrd; reg[56:0] cmd; reg[48:0] res; reg[48:0] res2; reg[26:0] cnt2; reg clk2; reg [23:0] watchdog; reg[31:0]qqqq; initial begin cnt<=0; state<=0; mosi<=1; sclk<=1; cs<=1; res<=0; ready<=0; err<=0; watchdog<=0; // $readmemh("wb.hex",writebuf); end always begin st<={err,ready,1'b0,state}; if (state==0) sclk<=1; else if ((state>=1) && (state<14)) sclk<=slowspiclk; else sclk<=fastspiclk; end always@(posedge clk) qqqq<=writebuf[wordcnt]; always@(posedge clk) begin slowspiclk<=cnt[7]; //195 kHz fastspiclk<=cnt[0]; //25 MHz dataout<=readbuf[addr]; oldrst<=rst; oldstb<=stb; if ((stb==1) && (oldstb==0)) writebuf[addr]<=datain; if ((rst==1) && (oldrst==0)) //posedge reset begin cnt<=0; err<=0; state<=1; mosi=1; cs=1; end else // if not reset begin //generate err and ready if (state==14) begin err<=0; ready<=1; watchdog<=0; end else begin ready<=0; if (watchdog>10_000_000) begin err<=1; watchdog<=10_000_001; end else watchdog<=watchdog+1; end // init state machine if (state==0) //idle after powerup begin cnt<=0; mosi<=1; cs<=1; end else if (state==1) //send 88 clocks begin if (cnt[15:8]==88) begin cmd<=56'b11111111_01_000000_00000000_00000000_00000000_00000000_10010101; //cmd0 cnt<=1; state<=2; cs=0; end else cnt<=cnt+1; end else if (state==2) // send cmd0 begin if (cnt[7:0]==4) mosi<=cmd[55]; if (cnt[7:0]==8) begin cmd<=(cmd<<1) | 56'b1; end if (cnt[15:8]==56) begin state<=3; cnt<=1; mosi<=1; end else cnt<=cnt+1; end else if (state==3) // wait for 0 on miso begin if ((cnt[7:0]==127) && (miso==0)) begin state<=4; cnt<=128; res<=(res<<1) | miso; end else cnt<=cnt+1; end else if (state==4) begin if (cnt[7:0]==127) res<=(res<<1) | miso; cnt<=cnt+1; if (cnt[15:8]==8) // TODO! check if res=1 begin state<=5; cnt<=0; cmd<=56'b11111111_01_001000_00000000_00000000_00000001_10101010_10000111; //cmd8 end end else if (state==5) // send cmd8 begin if (cnt[7:0]==4) mosi<=cmd[55]; if (cnt[7:0]==8) begin cmd<=(cmd<<1) | 56'b1; end if (cnt[15:8]==56) begin state<=6; cnt<=1; end else cnt<=cnt+1; end else if (state==6) // wait for 0 on miso begin if ((cnt[7:0]==127) &&(miso==0)) begin state<=7; cnt<=128; end else cnt<=cnt+1; end else if (state==7) begin if (cnt[7:0]==127) res<=(res<<1) | miso; cnt<=cnt+1; if (cnt[15:8]==40) begin state<=8; cnt<=0; cmd<=56'hFF_77_00_00_00_00_FF; end end else if (state==8) // send cmd55 begin if (cnt[7:0]==4) mosi<=cmd[55]; if (cnt[7:0]==8) begin cmd<=(cmd<<1) | 56'b1; end if (cnt[15:8]==56) begin state<=9; cnt<=0; end else cnt<=cnt+1; end else if (state==9) // wait for 0 on miso begin if ((cnt[7:0]==127) &&(miso==0)) begin state<=10; cnt<=128; end else cnt<=cnt+1; end else if (state==10) begin if (cnt[7:0]==127) res<=(res<<1) | miso; cnt<=cnt+1; if (cnt[15:8]==8) // TODO! check if res=1 begin state<=11; cnt<=1; cmd<=56'hFF_69_40_00_00_00_FF; //cmd41 end end else if (state==11) // send cmd41 begin if (cnt[7:0]==4) mosi<=cmd[55]; if (cnt[7:0]==8) begin cmd<=(cmd<<1) | 56'b1; end if (cnt[15:8]==56) begin state<=12; cnt<=1; end else cnt<=cnt+1; end else if (state==12) // wait for 0 on miso begin if ((cnt[7:0]==127) &&(miso==0)) begin state<=13; cnt<=128; end else cnt<=cnt+1; end else if (state==13) begin if (cnt[7:0]==127) res<=(res<<1) | miso; cnt<=cnt+1; if (cnt[15:8]==8) begin if (res[7:0]==0) begin state<=14; cnt<=0; cs<=1; end else begin cmd<=56'hFF_77_00_00_00_00_FF; //cmd55 state<=8; cnt<=1; end end end else if (state==14) // ready for read/write begin if ((rd==1) && (oldrd==0)) // posedge read begin cmd<= {16'hFF_51,secnum,8'hFF};// (56'hFF_51_00_00_00_00_FF | (secnum<<8)); state<=15; cnt<=0; cs<=0; end else if ((wr==1) && (oldwr==0)) // posedge write begin cmd<={16'hFF_58,secnum,8'hFF};//(56'hFF_58_00_00_00_00_FF | (secnum<<8)); state<=16; cnt<=1; cs<=0; end else begin state<=14; cnt<=0; cs<=1; end end else if (state==15) // send cmd17 begin if (cnt[0]==0) begin mosi<=cmd[55]; cmd<=(cmd<<1) | 56'b1; end if (cnt[7:1]==56) begin state<=17; cnt<=1; end else begin state<=15; cnt<=cnt+1; end end else if (state==17) // wait for 0 on miso begin if (cnt[0]==1) begin mosi<=cmd[55]; res<=(cmd<<1) | miso; end if ((cnt[0]==1) && (miso==0)) begin state<=18; cnt<=0; end else begin cnt<=cnt+1; state<=17; end end else if (state==18) //get response begin if (cnt[0]==1) res<=(res<<1) | miso; if (cnt[7:1]==8) // TODO! check if res=1 begin debug<=res; state<=19; cnt<=1; end else begin cnt<=cnt+1; state<=18; end; end else if (state==19) // wait for 0 on miso => FE sent begin if (cnt[0]==1) res<=(res<<1) |miso; if ((cnt[0]==1) && (miso==0)) begin debug<=res; state<=20; cnt<=0; wordcnt<=0; end else begin cnt<=cnt+1; state<=19; end end else if (state==20) begin if (cnt[0]==1) res<=(res<<1) | miso; if (cnt[7:1]==32) begin cnt<=1; wordcnt<=wordcnt+1; if (wordcnt==129) begin state<=14; cnt<=0; cs<=1; end else if (wordcnt<128) begin readbuf[wordcnt]<=res; end end else begin cnt<=cnt+1; state<=20; end end /// ------ write ----- else if (state==16) // send cmd24 begin if (cnt[0]==0) begin mosi<=cmd[55]; cmd<=(cmd<<1) | 56'b1; end if (cnt[7:1]==56) begin state<=21; cnt<=0; end else cnt<=cnt+1; end else if (state==21) // wait for 0 on miso begin if (miso==0) begin state<=22; cnt<=0; end else cnt<=cnt+1; end else if (state==22) //get response begin if (cnt[0]==1) res<=(res<<1) | miso; cnt<=cnt+1; if (cnt[7:1]==8) // TODO! check if res=1 begin state<=23; cnt<=0; cmd<=(48'hFF_FE_00_00_00_00 | (secnum<<8)); end end else if (state==23 ) //send ---- FFFE----!!!---- begin res<=32'hFF_FF_FF_FE; state<=24; wordcnt=0; end else if (state==24) // send writebuf begin if (cnt[0]==0) begin mosi<=res[31]; res<=(res<<1) | 32'b1; end if (cnt[7:1]==32) begin cnt<=0; wordcnt<=wordcnt+1; if (wordcnt<128) res<=qqqq; if (wordcnt==128) begin state<=25; res<=32'hffffffff; end end else cnt<=cnt+1; end else if (state==25)// send ffff begin if (cnt[0]==1) res<=(res<<1) | 32'b1; if (cnt[7:1]==16) begin cnt<=0; state<=26; end else cnt<=cnt+1; end else if (state==26) // wait for 0 on miso begin if ((cnt[0]==1) && (miso==0)) begin state<=27; cnt<=0; end else cnt<=cnt+1; end else if (state==27) //get response begin if (cnt[0]==1) res<=(res<<1) | miso; cnt<=cnt+1; if (cnt[7:1]==8) begin debug<=res; if (res[7:4]==4'b0101) begin state<=28; cnt<=0; end end end else if (state==28) //wait until ff begin if (cnt[0]==1) res<=(res<<1) | miso; cnt<=cnt+1; if (cnt[7:1]==8) begin // debug<=res; if (res[7:0]==8'hFF) begin cs<=1; state<=14; cnt<=0; end end end else // error!!! begin cnt<=0; mosi<=1; cs<=1; state<=31; end end end endmodule===Jac
We want a new retrocomputer
About resources, I'll check it tomorrow. Maybe my code can help to make your driver run.
@pki: It actually works,
If it would be possible to attach this to the 6502 address/data bus (without propeller) and just read and write
to it using the OSI BASICs PEEK and POKE - i think that would be ideal to start with. I have to see how I implement
something like SYS on the OSI BASIC. Work in progess https://git.no-route.org/syso/bemicro-cv-multicomp-6502/tree/master/ROMS/6502
(you might also want to look into subdirectories, pik33)
This is a driver which can do 3 things: initialize the card, read a sector, write a sector.
To read a sector you have to set the sector number, strobe the read and wait for ready, then get 128 longs from the buffer.
To write a sector you have to fill the write buffer, then strobe the write and wait for ready.
I used this driver with Nios II/e, accessing it with some parallel ports. Then I found open source fat32 driver written in c. It needed only attaching 3 functions: sector read, sector write and initialize. So, I wrote these 3 functions and it worked with fat32 formatted sdhc. I hope the driver can be compiled with prop gcc in xmm mode and then executed from de2-115 sram. Or maybe sdram, if I managed to attach it to my system.
My retrocomputer vga thing is now near the 1.0 state. Today I managed to add the sprite machine to it. So I have all the retrocomputer should have: a lot of different graphisc modes, from 1792x1120x4 colors to 448x280x256 colors, horizontal scroll register, display list, 4 pallette banks and some (now 4, but adding more is simply ctrl-c,ctrl-v thing) 32x32 sprites with scalable x and y zoom. This is all the Atari 8-bit and C64 have, except the resolutions are more recent.
I think it may be possible to add a 6502 with 64 k ram made from fpga ram blocks. Then this ram can be accessed by p1v, so if the 6502 makes some work, for example, drive a SID/POKEY/AY chip, the Propeller can fetch this and in this example, make a sound using SIDCog/AYcog/POKEY emulator.
I apologize if my remark was interpreted that way; I didn't intend to be rude.
Using the on-board SD card reader on the BeMicro CV and other boards would be extremely useful and would be something I'm interested in, too (especially because there's no useful EEPROM). But accessing the SD card and booting from it is a feature that's not going to be specific to my Propeddle project. It would have been better to start a new thread about it, rather than add it as follow-up here, so that others (who may not be interested in the Propeddle project) might see it. So I was basically wondering why it was posted here.
Incidentally, I am considering adding an SD card reader for mass storage to the Propeddle project, but it will be connected to some Propeller pins so it can use a driver from OBEX to access it (no Verilog or FPGA Propeller needed); however, unless there's such a thing as an I2C-based SD card reader, it'll have to share pins with the 6502 so it will require a chip to enable or disable it while the system is running normally. You heard it here first :-)
I'm seeing some great ideas, and I wish I had more time to look into it. Never mind me folks, carry on! :-)
===Jac
This of course works, I published an audio player here, but it is not as fast as a hardware driver can be. Modern SD can use 50 MHz SPI clock whiile the Propeller can read @ 5 Mbps.
And something else: the coprocessor. There are some operation which are LE expensive, for example division. The div/mod thing needs 2500 LEs. So let there be some addresses where the propeller can put the data and then get the result. I will add this to my sram/vga driver.