Skip to content

Commit b61b298

Browse files
authored
[mega65] Add MEGA65 headers for hardware registers (#154)
* Add header mega65 header files from kickc This adds headers for vic2-4, cia/sid, math, hypervisor. Also adds a test of using the mega65.h header and vic4 registers. * Apply formatting * Add plasma example for MEGA65 This illustrates how to reduced the CPU speed; set the character set using the VIC-IV header; and the use of prama unroll. * Update plasma * Update plasma * Header work * Cleanup mega65 headers to match iomap.txt * Add ethernet and hypervisor * 45E100 Fast Ethernet controller header * Integer defines to annonymous enums Warnings for extensions are suppressed and compatability with CC65 is checked. * Update math registers [skip actions] * Fix mult duplicate * Add default color palette; prune headers * Prune header comments * Fix missing comma * Fix assertion
1 parent becc1c3 commit b61b298

File tree

9 files changed

+1082
-0
lines changed

9 files changed

+1082
-0
lines changed

examples/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ endif()
5252
if(PLATFORM MATCHES ^atari2600-)
5353
add_subdirectory(atari2600)
5454
endif()
55+
if(PLATFORM STREQUAL ^mega65)
56+
add_subdirectory(mega65)
57+
endif()
5558
if(PLATFORM STREQUAL neo6502)
5659
add_subdirectory(neo6502)
5760
endif()

examples/mega65/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
add_executable(viciv_test.prg viciv_test.c)
2+
install_example(viciv_test.prg)
3+
4+
add_executable(plasma.prg plasma.cc)
5+
install_example(plasma.prg)
6+

examples/mega65/plasma.cc

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
// Copyright 2023 LLVM-MOS Project
2+
// Licensed under the Apache License, Version 2.0 with LLVM Exceptions.
3+
// See https://github.com/llvm-mos/llvm-mos-sdk/blob/main/LICENSE for license
4+
// information.
5+
6+
/*
7+
* Simplistic character-mode plasma effect
8+
*
9+
* Inspired by cc65/samples/cbm
10+
* - 2001 by groepaz
11+
* - Cleanup and porting by Ullrich von Bassewitz
12+
* - 2023 Mega65/LLVM-MOS C++ adaptation by Mikael Lund aka Wombat
13+
*/
14+
15+
#include <array>
16+
#include <cstdint>
17+
#include <mega65.h>
18+
19+
/*
20+
* Simple pseudo-random number generator
21+
* https://en.wikipedia.org/wiki/Xorshift
22+
*/
23+
class RandomXORS {
24+
private:
25+
uint32_t state = 7;
26+
27+
public:
28+
inline uint8_t rand8() { return static_cast<uint8_t>(rand32() & 0xff); }
29+
inline uint32_t rand32() {
30+
state ^= state << 13;
31+
state ^= state >> 17;
32+
state ^= state << 5;
33+
return state;
34+
}
35+
};
36+
37+
/*
38+
* Sets MEGA65 speed to 3.5 Mhz
39+
*/
40+
void speed_mode3() {
41+
VICIV.ctrlb |= VIC3_FAST_MASK;
42+
VICIV.ctrlc &= ~VIC4_VFAST_MASK;
43+
}
44+
45+
/*
46+
* Cyclic sine lookup table
47+
*/
48+
constexpr uint8_t sine_table[UINT8_MAX + 1] = {
49+
0x80, 0x7d, 0x7a, 0x77, 0x74, 0x70, 0x6d, 0x6a, 0x67, 0x64, 0x61, 0x5e,
50+
0x5b, 0x58, 0x55, 0x52, 0x4f, 0x4d, 0x4a, 0x47, 0x44, 0x41, 0x3f, 0x3c,
51+
0x39, 0x37, 0x34, 0x32, 0x2f, 0x2d, 0x2b, 0x28, 0x26, 0x24, 0x22, 0x20,
52+
0x1e, 0x1c, 0x1a, 0x18, 0x16, 0x15, 0x13, 0x11, 0x10, 0x0f, 0x0d, 0x0c,
53+
0x0b, 0x0a, 0x08, 0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x03, 0x02, 0x02,
54+
0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03,
55+
0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0c, 0x0d, 0x0f,
56+
0x10, 0x11, 0x13, 0x15, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24,
57+
0x26, 0x28, 0x2b, 0x2d, 0x2f, 0x32, 0x34, 0x37, 0x39, 0x3c, 0x3f, 0x41,
58+
0x44, 0x47, 0x4a, 0x4d, 0x4f, 0x52, 0x55, 0x58, 0x5b, 0x5e, 0x61, 0x64,
59+
0x67, 0x6a, 0x6d, 0x70, 0x74, 0x77, 0x7a, 0x7d, 0x80, 0x83, 0x86, 0x89,
60+
0x8c, 0x90, 0x93, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, 0xa8, 0xab, 0xae,
61+
0xb1, 0xb3, 0xb6, 0xb9, 0xbc, 0xbf, 0xc1, 0xc4, 0xc7, 0xc9, 0xcc, 0xce,
62+
0xd1, 0xd3, 0xd5, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8,
63+
0xea, 0xeb, 0xed, 0xef, 0xf0, 0xf1, 0xf3, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9,
64+
0xfa, 0xfa, 0xfb, 0xfc, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff,
65+
0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfc, 0xfb, 0xfa,
66+
0xfa, 0xf9, 0xf8, 0xf6, 0xf5, 0xf4, 0xf3, 0xf1, 0xf0, 0xef, 0xed, 0xeb,
67+
0xea, 0xe8, 0xe6, 0xe4, 0xe2, 0xe0, 0xde, 0xdc, 0xda, 0xd8, 0xd5, 0xd3,
68+
0xd1, 0xce, 0xcc, 0xc9, 0xc7, 0xc4, 0xc1, 0xbf, 0xbc, 0xb9, 0xb6, 0xb3,
69+
0xb1, 0xae, 0xab, 0xa8, 0xa5, 0xa2, 0x9f, 0x9c, 0x99, 0x96, 0x93, 0x90,
70+
0x8c, 0x89, 0x86, 0x83};
71+
72+
/*
73+
* Generate charset with 8 * 256 characters at given address
74+
*/
75+
void make_charset(uint16_t charset_address, RandomXORS &rng) {
76+
/*
77+
* Lambda function to generate a single 8x8 pixels pattern
78+
*/
79+
auto make_char = [&](const uint8_t sine) {
80+
uint8_t pattern = 0;
81+
constexpr uint8_t bits[8] = {1, 2, 4, 8, 16, 32, 64, 128};
82+
for (const auto bit : bits) {
83+
if (rng.rand8() > sine) {
84+
pattern |= bit;
85+
}
86+
}
87+
return pattern;
88+
};
89+
90+
auto charset = reinterpret_cast<volatile uint8_t *>(charset_address);
91+
for (const auto sine : sine_table) {
92+
for (int _i = 0; _i < 8; ++_i) {
93+
*(charset++) = make_char(sine);
94+
}
95+
}
96+
}
97+
98+
/*
99+
* Plasma class
100+
*/
101+
template <size_t COLS, size_t ROWS> class Plasma {
102+
private:
103+
std::array<uint8_t, ROWS> ydata;
104+
std::array<uint8_t, COLS> xdata;
105+
uint8_t x_cnt1 = 0;
106+
uint8_t x_cnt2 = 0;
107+
uint8_t y_cnt1 = 0;
108+
uint8_t y_cnt2 = 0;
109+
110+
public:
111+
/*
112+
* Generate and activate charset at given address
113+
*/
114+
Plasma(const uint16_t charset_address, RandomXORS &rng) {
115+
make_charset(charset_address, rng);
116+
VICIV.charptr = charset_address;
117+
}
118+
119+
/*
120+
* Draw frame
121+
*/
122+
inline void update() {
123+
auto i = y_cnt1;
124+
auto j = y_cnt2;
125+
for (auto &y : ydata) {
126+
y = sine_table[i] + sine_table[j];
127+
i += 4;
128+
j += 9;
129+
}
130+
i = x_cnt1;
131+
j = x_cnt2;
132+
for (auto &x : xdata) {
133+
x = sine_table[i] + sine_table[j];
134+
i += 3;
135+
j += 7;
136+
}
137+
x_cnt1 += 2;
138+
x_cnt2 -= 3;
139+
y_cnt1 += 3;
140+
y_cnt2 -= 5;
141+
142+
write_to_screen();
143+
}
144+
145+
/*
146+
* Write summed buffers to screen memory
147+
*/
148+
inline void write_to_screen() const {
149+
auto screen_ptr = reinterpret_cast<volatile uint8_t *>(&DEFAULT_SCREEN);
150+
for (const auto y : ydata) {
151+
#pragma unroll
152+
for (const auto x : xdata) {
153+
*(screen_ptr++) = y + x;
154+
}
155+
}
156+
}
157+
};
158+
159+
int main() {
160+
constexpr size_t COLS = 80;
161+
constexpr size_t ROWS = 25;
162+
constexpr uint16_t CHARSET_ADDRESS = 0x3000;
163+
RandomXORS rng;
164+
Plasma<COLS, ROWS> plasma(CHARSET_ADDRESS, rng);
165+
speed_mode3();
166+
while (true) {
167+
plasma.update();
168+
}
169+
}

examples/mega65/viciv_test.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <mega65.h>
2+
3+
int main(void) {
4+
VICIV.screencol = COLOR_BUBBLEGUM;
5+
while (1) {
6+
VICIV.bordercol++;
7+
}
8+
return 0;
9+
}

mos-platform/mega65/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ platform(mega65 COMPLETE HOSTED PARENT commodore)
33
if(NOT CMAKE_CROSSCOMPILING)
44
return()
55
endif()
6+
install(FILES
7+
_45E100.h
8+
_vic3.h
9+
_vic4.h
10+
mega65.h
11+
TYPE INCLUDE)
612

713
install(FILES link.ld TYPE LIB)
814

mos-platform/mega65/_45E100.h

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright 2023 LLVM-MOS Project
2+
// Licensed under the Apache License, Version 2.0 with LLVM Exceptions.
3+
// See https://github.com/llvm-mos/llvm-mos-sdk/blob/main/LICENSE for license
4+
// information.
5+
6+
#ifndef _45E100_H
7+
#define _45E100_H
8+
9+
#include <stdint.h>
10+
11+
#ifdef __cplusplus
12+
extern "C" {
13+
#endif
14+
15+
/// 45E100 Fast Ethernet controller
16+
///
17+
/// Enabled by writing 0x53 and then 0x47 to VIC-IV register 0xD02F
18+
struct __45E100 {
19+
uint8_t ctrl1; //!< Control register 1 (offset 0x00)
20+
uint8_t ctrl2; //!< Control register 2 (offset 0x01)
21+
union {
22+
uint16_t txsz; //!< X Packet size (offset 0x02)
23+
struct {
24+
uint8_t txsz_lsb; //!< X Packet size (low byte) (offset 0x02)
25+
uint8_t txsz_msb; //!< X Packet size (high byte) (offset 0x03)
26+
};
27+
};
28+
uint8_t command; //!< Write-only command register (offset 0x04)
29+
uint8_t ctrl3; //!< Control register 3 (offset 0x05)
30+
/// MIIM PHY number (use 0 for Nexys4, 1 for MEGA65 r1 PCBs)
31+
/// and MIIM register number (offset 0x06)
32+
uint8_t miim_phy_reg;
33+
uint16_t miimv; //!< MIIM register value (offset 0x07)
34+
uint8_t macaddr[6]; //!< MAC address (offset 0x09)
35+
};
36+
#ifdef __cplusplus
37+
static_assert(sizeof(struct __45E100) == 16);
38+
#endif
39+
40+
/// 45E100 Fast Ethernet controller commands
41+
enum
42+
#ifdef __clang__
43+
: uint8_t
44+
#endif
45+
{
46+
ETHERNET_STOPTX = 0,
47+
ETHERNET_STARTTX = 1,
48+
ETHERNET_RXNORMAL = 208,
49+
ETHERNET_DEBUGVIC = 212,
50+
ETHERNET_DEBUGCPU = 220,
51+
ETHERNET_RXONLYONE = 222,
52+
ETHERNET_FRAME1K = 241,
53+
ETHERNET_FRAME2K = 242
54+
};
55+
56+
/*
57+
* The following masks are auto-generated from iomap.txt.
58+
* See https://github.com/dansanderson/mega65-symbols
59+
* Date: 2023-08-25
60+
*/
61+
62+
enum
63+
#ifdef __clang__
64+
: uint8_t
65+
#endif
66+
{
67+
/** Write 0 to hold ethernet controller under reset */
68+
ETH_RST_MASK = 0b00000001,
69+
/** Write 0 to hold ethernet controller transmit sub-system under reset
70+
*/
71+
ETH_TXRST_MASK = 0b00000010,
72+
/** Read ethernet RX bits currently on the wire */
73+
ETH_DRXD_MASK = 0b00000100,
74+
/** Read ethernet RX data valid (debug) */
75+
ETH_DRXDV_MASK = 0b00001000,
76+
/** Allow remote keyboard input via magic ethernet frames */
77+
ETH_KEYEN_MASK = 0b00010000,
78+
/** Indicate if ethernet RX is blocked until RX buffers freed */
79+
ETH_RXBLKD_MASK = 0b01000000,
80+
/** Ethernet transmit side is idle, i.e., a packet can be sent. */
81+
ETH_TXIDLE_MASK = 0b10000000,
82+
/** Number of free receive buffers */
83+
ETH_RXBF_MASK = 0b00000110,
84+
/** Enable streaming of CPU instruction stream or VIC-IV display on
85+
* ethernet
86+
*/
87+
ETH_STRM_MASK = 0b00001000,
88+
/** Ethernet TX IRQ status */
89+
ETH_TXQ_MASK = 0b00010000,
90+
/** Ethernet RX IRQ status */
91+
ETH_RXQ_MASK = 0b00100000,
92+
/** Enable ethernet TX IRQ */
93+
ETH_TXQEN_MASK = 0b01000000,
94+
/** Enable ethernet RX IRQ */
95+
ETH_RXQEN_MASK = 0b10000000,
96+
/** Ethernet disable promiscuous mode */
97+
ETH_NOPROM_MASK = 0b00000001,
98+
/** Disable CRC check for received packets */
99+
ETH_NOCRC_MASK = 0b00000010,
100+
/** Ethernet TX clock phase adjust */
101+
ETH_TXPH_MASK = 0b00001100,
102+
/** Accept broadcast frames */
103+
ETH_BCST_MASK = 0b00010000,
104+
/** Accept multicast frames */
105+
ETH_MCST_MASK = 0b00100000,
106+
/** Ethernet RX clock phase adjust */
107+
ETH_RXPH_MASK = 0b11000000,
108+
/** Ethernet MIIM register number */
109+
ETH_MIIMREG_MASK = 0b00011111,
110+
/** Ethernet MIIM PHY number (use 0 for Nexys4, 1 for MEGA65 r1 PCBs) */
111+
ETH_MIIMPHY_MASK = 0b11100000
112+
};
113+
114+
#ifdef __cplusplus
115+
} // extern block
116+
#endif
117+
#endif // header

0 commit comments

Comments
 (0)