Skip to content

sokoide/tangnano_lcd_cpu_bsram

Repository files navigation

Tang Nano LCD + 8bit 6502 CPU + BSRAM example

About

  • Tang Nano 9K or 20K + 043026-N6(ML) 4.3 inch 480x272 LCD module example
  • The default is for 9K. To make it for 20K, change the following 3 files
    • lcd_cpu_bsram.gprj

        <!-- Tang Nano 9K -->
          <!-- <Device name="GW1NR-9C" pn="GW1NR-LV9QN88PC6/I5">gw1nr9c-004</Device> -->
          <!-- Tang Nano 20K -->
          <Device name="GW2AR-18C" pn="GW2AR-LV18QN88C8/I7">gw2ar18c-000</Device>
      
              <!-- Tang Nano 9K -->
              <!-- <File path="src/lcd_cpu_bsram_9K.cst" type="file.cst" enable="1"/>
              <File path="src/gowin_rpll_9K/gowin_rpll40.v" type="file.verilog" enable="1"/>
              <File path="src/gowin_rpll_9K/gowin_rpll9.v" type="file.verilog" enable="1"/> -->
              <!-- Tang Nano 20K -->
              <File path="src/lcd_cpu_bsram_20K.cst" type="file.cst" enable="1"/>
              <File path="src/gowin_rpll_20K/gowin_rpll40.v" type="file.verilog" enable="1"/>
              <File path="src/gowin_rpll_20K/gowin_rpll9.v" type="file.verilog" enable="1"/>
    • Makefile

      # Tang Nano 20K
      DEVICE=GW2AR-18C
      # Tang Nano 9K
      # DEVICE=GW1NR-9C
    • src/top.sv

        // Tang Nano 9K:
        //  wire rst_n = ResetButton;
        // Tang Nano 20K:
        wire rst_n = !ResetButton;

Getting Started

Run an Example

cd examples
# if not installed
brew install srecord cc65
# edit Makefile -> SRCS and change `simple.s` to any of the examples you want to use
make clean
make
# include/boot_program.sv and examples/example.lst are generated
# examples/example.lst is printed as below
$ make
ca65 -l example.lst -o simple.o simple.s
ld65 -C baremetal.cfg -o example.bin simple.o
srec_cat example.bin -binary -offset 0x0200 -o example.hex -Intel
../utils/hex_fpga/hex_fpga -hexfile example.hex -svfile ../include/boot_program.sv
INFO[0000] started
INFO[0000] o: {hexFilePath:example.hex svFilePath:../include/boot_program.sv}
INFO[0000] :020000040000FA
INFO[0000] hexLine: &{length:2 addr:[0 0] recordType:4 data:[0 0] checksum:0}
INFO[0000] :06020000A9418D00E0EFB2
INFO[0000] hexLine: &{length:6 addr:[2 0] recordType:0 data:[169 65 141 0 224 239] checksum:0}
INFO[0000] :00000001FF
INFO[0000] hexLine: &{length:0 addr:[0 0] recordType:1 data:[] checksum:0}
../include/boot_program.sv file written
cat example.lst
ca65 V2.18 - N/A
Main file   : simple.s
Current file: simple.s

000000r 1               ; Simple Example) draw 'A' on top-left
000000r 1               ;
000000r 1               ; Used Instructions:
000000r 1               ; LDA immediate (1byte)
000000r 1               ; STA abosolute (2 bytes)
000000r 1               ; $EF: HLT (custom instruction)
000000r 1               ;
000000r 1               ; Program loaded and starts at 0x0200
000000r 1                   .org $0200
000200  1
000200  1               start:
000200  1               ; load $41 ('A') into A register
000200  1  A9 41            LDA #$41
000202  1               ; store a value of A register at $E000 (top-left corner of VRAM)
000202  1  8D 00 E0         STA $E000
000205  1               ; HLT: stop CPU
000205  1  EF               .byte $EF
000205  1

# make a bitstream and download it onto Tang Nano
cd ../
make download
# the exmple will be compined with the 6502 CPU / LCD controller and copied into Tang Nano

Implemented Instructions

  • +: implemented
    • All 6502 instructions except for the followings
  • -: not going to be implemented
    • break, interrupt related oned
  • !: custom instruction which is not available in 6502
    • 0xCF CVR: Clear VRAM
      • CF: (no operand) clear VRAM
    • 0xDF IFO: Info ... show registers and memory
      • DF 0000: show registers and 0x0000-0x007F
      • DF 8000: show registers and 0x0080-0x00FF
      • DF 8010: show registers and 0x1080-0x10FF
    • 0xEF HLT: Halt ... stop the CPU
      • EF: (no operand) stop the CPU. LCD controller continues running
    • 0xFF WVS: Wait For VSync ... wait until the next vsync timing of the LCD
      • FF 00: wait for vsync once (~1/58 sec)
      • FF 05: wait for vsync 6 times (~6/58 sec)
      • FF 3A: wait for vsync 58 times (~1 sec)
0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB 0xC 0xD 0xE 0xF
0x0 BRK ORA ORA ASL PHP ORA ASL ORA ASL
impl idx zp zp impl imm acc abs abs
- + + + + + + + +
0x1 BPL ORA ORA ASL CLC ORA ORA ASL
rel idy zpx zpx impl aby abx abx
+ + + + + + + +
0x2 JSR AND BIT AND ROL PLP AND ROL BIT AND ROL
abs idx zp zp zp impl imm acc abs abs abs
+ + + + + + + + + + +
0x3 BMI AND AND ROL SEC AND AND ROL
rel idy zpx zpx impl aby abx abx
+ + + + + + + +
0x4 RTI EOR EOR LSR PHA EOR LSR JMP EOR LSR
impl idx zp zp impl imm acc abs abs abs
- + + + + + + + + +
0x5 BVC EOR EOR LSR CLI EOR EOR LSR
rel idy zpx zpx impl aby abx abx
+ + + + - + + +
0x6 RTS ADC ADC ROR PLA ADC ROR JMP ADC ROR
impl idx zp zp impl imm acc ind abs abs
+ + + + + + + + + +
0x7 BVS ADC ADC ROR SEI ADC ADC ROR
rel idy zpx zpx impl aby abx abx
+ + + + - + + +
0x8 STA STY STA STX DEY TXA STY STA STX
idx zp zp zp impl impl abs abs abs
+ + + + + + + + +
0x9 BCC STA STY STA STX TYA STA TXS STA
rel idy zpx zpx zpy impl aby impl abx
+ + + + + + + + +
0xA LDY LDA LDX LDY LDA LDX TAY LDA TAX LDY LDA LDX
imm idx imm zp zp zp impl imm impl abs abs abs
+ + + + + + + + + + + +
0xB BCS LDA LDY LDA LDX CLV LDA TSX LDY LDA LDX
rel idy zpx zpx zpy impl aby impl abx abx aby
+ + + + + + + + + + +
0xC CPY CMP CPY CMP DEC INY CMP DEX CPY CMP DEC CVR
imm idx zp zp zp impl imm impl abs abs abs impl
+ + + + + + + + + + + !
0xD BNE CMP CMP DEC CLD CMP CMP DEC IFO
rel idy zpx zpx impl aby abx abx abs
+ + + + - + + + !
0xE CPX SBC CPX SBC INC INX SBC NOP CPX SBC INC HLT
imm idx zp zp zp impl imm impl abs abs abs impl
+ + + + + + + + + + + !
0xF BEQ SBC SBC INC SED SBC SBC INC WVS
rel idy zpx zpx impl aby abx abx imm
+ + + + - + + + !

6502 Addressing Modes - Legend

Abbrev Full Name Description
impl Implied No operand needed. Used for instructions like CLC, RTS, SEI, etc.
acc Accumulator Operates directly on the accumulator (A register), e.g., ASL A
imm Immediate The operand is a constant value, e.g., LDA #$01
zp Zero Page Uses a one-byte address ($00–$FF), e.g., LDA $10
zpx Zero Page,X Zero page address plus the X register, e.g., LDA $10,X
zpy Zero Page,Y Zero page address plus the Y register, e.g., LDX $10,Y
abs Absolute Full 16-bit address, e.g., LDA $1234
abx Absolute,X Absolute address plus X, e.g., LDA $1234,X
aby Absolute,Y Absolute address plus Y, e.g., LDA $1234,Y
ind Indirect Used only with JMP, jumps to the address stored at the given address, e.g., JMP ($1234)
idx (Indirect,X) Indirect address from zero page plus X, e.g., LDA ($10,X)
idy (Indirect),Y Indirect address from zero page, then add Y, e.g., LDA ($10),Y
rel Relative Offset relative to the program counter (used for branches), e.g., BEQ $10

Memory Map

32KB RAM:
0x0000-0x00FF: Zero Page (256B)
0x0100-0x01FF: Stack (256B)
0x0200-0x7BFF: RAM (30.5KB)
0x7C00-0x7FFF: Shadow VRAM (1KB)

1KB VRAM (SDPB):
Write-only for CPU. Use the Shadow VRAM address which has the same data as VRAM for read.
0xE000-0xE3FF: Text VRAM (1KB)

4KB Font ROM (pROM):
0xF000-0xFFFF: Font ROM (4KB)

Font ROM

  • Used Sweet16Font licensed under boost software license, meaning you don't have to give credit/embed license
Total 4KB Font ROM (pROM):
Not mapped, can't access from CPU. Only 128 chars are embeded so far. Code 128-255 may be used for games, etc.
pROM address: 0x0000-0x0FFF: Font ROM (4KB)
  16x8 ‎ = 128bits = 16bytes / char
  16 bytes x 256 chars ‎ =  4KB

Test

Test Bench Example for Hello World

  • Here is a waveform by DSim Desktop when the following Hello World example ran.
  • The 1st byte (0xA9) is loaded at 0x0200.
  • You can find the Y register ry incremented at PC=0x020C (boot_program[12]) which is INY (0xC8).

testbench

    // Hello World
    boot_program[0]  = 8'hA0;  // LDY #0
    boot_program[1]  = 8'h00;
    boot_program[2]  = 8'hA2;  // LDX #0
    boot_program[3]  = 8'h00;
    boot_program[4]  = 8'hB9;  // loop: LDA message, Y
    boot_program[5]  = 8'h13;
    boot_program[6]  = 8'h02;
    boot_program[7]  = 8'hF0;  // BEQ done
    boot_program[8]  = 8'h07;
    boot_program[9]  = 8'h9D;  // STA $E000, X; $E000 is a top-left corder of text VRAM
    boot_program[10] = 8'h00;
    boot_program[11] = 8'hE0;
    boot_program[12] = 8'hC8;  // INY
    boot_program[13] = 8'hE8;  // INX
    boot_program[14] = 8'hD0;  // BNE loop
    boot_program[15] = 8'hF4;
    boot_program[16] = 8'h4C;  // done: JMP done (infinite loop)
    boot_program[17] = 8'h10;
    boot_program[18] = 8'h12;
    boot_program[19] = 8'h48;  // message: Hello World!, 0
    boot_program[20] = 8'h65;  // 'H'
    boot_program[21] = 8'h6C;  // 'e'
    boot_program[22] = 8'h6C;  // 'l'
    boot_program[23] = 8'h6F;  // 'l'
    boot_program[24] = 8'h20;  // ...
    boot_program[25] = 8'h57;
    boot_program[26] = 8'h6F;
    boot_program[27] = 8'h72;
    boot_program[28] = 8'h6C;
    boot_program[29] = 8'h64;
    boot_program[30] = 8'h21;
    boot_program[31] = 8'h00;  // 0 terminator

How to Run the test

  • Run VSCode (remote server) on x64 Linux or Windows
    • Unfortunately, it doesn't support macOS
    • x64 Ubuntu on Apple Silicon macOS is fine to run it
  • Install DSIM Studio plug-in on the remote Linux/local Windows, register yourself and activate it
  • Change paths in ldc_cpu_bsram.dpf
  • Open the updated dpf project in DSIM
  • Configure and run "library configuration" then tb_cpu in "Simulation Configuration"

DSIM

043026-N6(ML) LCD spec

Interface PIN connections

Pin No. Symbol Function
1 LEDK Back light power supply negative
2 LEDA Back light power supply positive
3 GND Ground
4 VCC Power supply
5-12 R0-R7 Red Data
13-20 G0-G7 Green Data
21-28 B0-B7 Blue Data
29 GND Ground
30 CLK Clock signal
31 DISP Display on/off
32 HSYNC Horizontal sync input in RGB mode (short to GND if not used)
33 VSYNC Vertical sync input in RGB mode (short to GND if not used)
34 DE Data enable
35 NC No Connection
36 GND Ground
37 XR Touch panel X-right
38 YD Touch panel Y-bottom
39 XL Touch panel X-left
40 YU Touch panel Y-up

Parallel RGP Input Timing

Item Symbol Values (Min.) Values (Typ.) Values (Max.) Unit Remark
DCLK Frequency Fclk 8 9 12 MHz
Hsync
Period time Th 485 531 589 DCLK
Display Period Thdisp - 480- - DCLK
Back Porch Thbp 3 43 43 DCLK
Front Porch Thfp 2 4 75 DCLK
Vsync
Period time Tv 276 292 321 H
Display Period Tvdisp - 272 - H
Back Porch Tvbp 2 12 12 H
Front Porch Tvfp 2 4 37 H

Sync Mode

sync

Sync DE Mode

sync DE

Example

lcd

About

TangNano 9K/20K + 4.3 inch LCD + 8bit CPU + BSRAM example

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published